Gianni Giaccaglini

Tricks & mini applics on WPF
posts - 46, comments - 0, trackbacks - 0

sabato 28 febbraio 2015

Crittografia di un documento Word

 

Criptare/decriptare un documento Word con tecniche più o meno originali

Antefatto. Dopo l’esperienza di cui al post precedente (Criptare/decriptare un testo con Excel + VBA) ho pensato di utilizzarla direttamente su un documento Word. La scommessa era quella di ottenere una crittografia in grado di:

a) mantenere i vari formati possibili (grassetti, corsivi, colori, evidenziazioni ecc.);

b) sfruttare, oltre agli scorrimenti (Shift, d’ora in poi) casuali, l’inversione di brani di testo.

Subito ho constatato che si tratta di impegni conflittuali. Sulla carta un oggetto Document di Word offre una proprietà alletante, ovvero Content, che racchiude, come dice il suo nome, l’intero contenuto. Attenzione però perché si tratta dei soli caratteri, escludendo segni speciali e formattazioni. Lo stesso accade per la funzione di stringa stringReverse (non sfruttata nel post precedente, mi era sfuggita) che traduce “Roma” in “amoR”. Non è finita: a complicare le cose si mette di traverso un tabella Word. Questa, come non tutti sanno (me compreso, fino a ieri l’altro) è caratterizzata da particolari segni che, per così dire, ne fissano l’intelaiatura, che viene sconvolta ricorrendo a StringReverse.

Forse una soluzione del genere moglie ebbra e botte piena esiste, ma alla fine ho deciso di non ammattire, decidendo di procedere carattere per carattere.

L’archivio sperimentale .docm

Il testo possibile è quello riportato qui di seguito, racchiuso tra linee :

______________________________________________________________________________________________

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.

Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.

SHIFT CASUALI AL TERMINE DEL DOC macro GestioneTabella di ThisDocument. Ciao

TABELLINA

Ciao

Pio

pao

chi

sei

Tu?

________________________________________________________________________________________________ 


Ricordo che la parte in pseudo-latinorum si ottiene digitando =Lorem() + Invio.

In fondo al documento ho infine inglobato una casella di testo – comando Inserisci > Casella di testo, quindi In tale oggetto (Shape, detto en passant) ho poi inserito una tabella (pochi ci penserebbero, ma si può), caratterizzata da una sola riga e venti colonne. L’obiettivo è di poter coprire, insieme a un numero di altre righe, un numero adeguato di scorrimenti, alias shift.

NOTA. Per evitare la vista di tali shift a intrusi sarebbe stato bello poter occultare la fatidica casella, che ahimè non gode della proprietà Visible. Un rimedio parziale consiste nel minimizzare le dimensione dei caratteri e assegnare loro il colore bianco nonché ridurre le dimensioni della casella fin quasi a farla scomparire.

La macro crittografica

Dopo tante chiacchiere riporto la macro dal nome di non sfrenata fantasia (Cripta) qui sotto, pezzo per pezzo.  Cominciamo con la parte iniziale.

Dim VettShift() As Integer ' A livello Dichiarazioni

Sub Cripta()
  Selection.HomeKey unit:=wdStory
  Dim Tutticar As Characters
  Set Tutticar = ThisDocument.Characters
  Dim TotCar As Long
  Dim NumCol As Integer, NumRighe As Integer
  NumCol = 20
  TotCar = Tutticar.Count
  If TotCar > 20 Then
    NumRighe = Int(TotCar / (8 * NumCol)) ' Copre 1/8 ca. del doc.
 
Else
    NumRighe = 1
  End If

L’istruzione Selection.HomeKey unit:=wdStory assicura che il cursore si porti al primo carattere del testo. Segue l’impostazione in una variabile Tutticar di tipo Characters dell’intero sistema dei caratteri del nostro documento. Le rimanenti istruzioni, fino a ThisDocument.Shapes(1).Select definiscono il numero di colonne (fissato a 20) e quello delle righe in modo da coprire un ottavo circa del documento. Volendo si può aumentare tale copertura, ma a scapito dei tempi di creazione degli scorrimenti (pseudo) casuali.

Segue la parte che svolge due mestieri: aggiungere alla prima riga, inizialmente unica, della tabella interna della textbox, altre righe fino al NumRighe calcolato sopra e poi caricare numeri casuali da 1 a 10 nell’insieme delle celle create in precedenza. Il procedimento non dovrebbe presentare ostacoli al comprendonio.

  Dim i As Integer, j As Integer
  ThisDocument.Shapes(1).Select
  Dim MiaTab As Table
  Set MiaTab = Selection.Tables(1)
  ' MiaTab.Rows.Delete ' Utilizzabile carica
  For i = 1 To NumRighe – 1
    MiaTab.Rows.Add
  Next
  Dim TestoCella As String
  For i = 1 To NumRighe
    For j = 1 To NumCol
      TestoCella = "" & Int(Rnd * 10) ' Numeri casuali fino a 10
      MiaTab.Cell(i, j).Range.Text = TestoCella
    Next
  Next

NOTA. Va solo detto che non sembra proprio possibile agire “a distanza” sugli elementi della tabella interna, è giocoforza esordire con  ThisDocument.Shapes(1).Select e solo allora si può impostare in MiaTab come membro della selezione.

Un punto problematico

Qualcuno si stupirà del codice seguente, in quanto carica gli shift non tanto su un’entità in memoria, bensì su un vettore unidimensionale anziché su una matrice di tante righe e colonne quante ne ha la tabella interna alla casella di testo. Ne riparlerò in fondo all’articolo, per ora mi limito a far notare che l’uso di un vettore è più funzionale alla gestione carattere per carattere già anticipata.

  ' Carica Shift da MiaTab a VettShift
  ReDim VettShift(1 To NumRighe * NumCol)
  Dim k As Integer
  ThisDocument.Shapes(1).Select
    For i = 1 To NumRighe
      For j = 1 To NumCol
        TestoCella = _
        Selection.Tables(1).Cell(i, j).Range.Text
        ' Elimina il pallino:
        TestoCella = _
        Left(TestoCella, Len(TestoCella) - 1)

      k = k + 1
      VettShift(k) = 0 + TestoCella
    Next j
  Next i
  Selection.HomeKey unit:=wdStory ' Cursore sul documento

L’unica osservazione degna di rilievo è relativa al codice in neretto, che serve a eliminare lo strano “pallino” nero che affianca i contenuti di ogni cella di una tabella, permettendo così di caricare i soli numeri nel VettShift.

Il codice crittografico, finalmente

  ' Criptazione
  Dim Car As String
  Dim Shift As Integer, NumShift As Integer
  NumShift = UBound(VettShift)
  k = 1
  For i = 1 To Tutticar.Count
    Car = Mid(Tutticar(i), 1)
    Shift = VettShift(k)
  ' Evita i pallini e altri segni speciali delle tabelle
    If Asc(Car) > 31 Then  _
      Tutticar(i).Text = Chr(Asc(Car) + Shift)
    end if
    k = IIf(k = NumShift, 1, k + 1)
  Next
  Set Tutticar = Nothing
End Sub

La struttura e la missione di tale codice dovrebbe, qui giunti, essere chiara a tutti, per cui mi limito a due osservazioni:

a) l’istruzione k = IIf(k = NumShift, 1, k + 1) fa sì che quando si l’ultimo scorrimento di VettShift si riparta con indice k = 1;

b) le istruzioni in grassetto eliminano pallini e altri speciali simboli che, per così dire, “sostengono” la struttura tabellare. Questi hanno tutti valore Ascii <= 31 (*) per cui saltandoli come pestiferi vengono considerati solo i caratteri “veri e propri”, evitando strane anomalie in presenza di tabelle (tra cui un  fenomeno, per me inspiegabile, che fa sì che caratteri del documento fuori tabella vengano incorporati in essa!).

NOTA (*) L’esplorazione normale dei caratteri della tabella indica sistematicamente dei Carriage Return, di Ascii = 13. Forse altri speciali, esistenti, sono occultati.

Infine, stavo quasi per dimenticarmene, la macro Decripta di ripristino dell’originale è pressoché identica alla Cripta, a parte i valori negativi degli shift, in valore assoluto uguali a quelli usati nel crittografare. L’importante è operare come già detto nel precedente post. Ossia, repetita iuvant:

1. le routine Cripta e Decripta vanno collocate in moduli distinti, Modulo1 e Modulo2 (o altri nomi graditi a ciascuno);

2. al destinatario del documento ne va spedita una copia .xlsx e comunque priva di macro VBA, inviando a parte e possibilmente in tempi diversi il Modulo2. Così solo un hacker superlativo potrà intercettare tutto quel che occorre per ricostruire l’originale.

NOTA. Questo metodo ha qualche analogia con quello a doppia chiave? Giudichi ognuno...

Conclusioni

Le contraddizioni da me stesso ammesse francamente meritano una spiegazione. In primis va puntualizzato che lo scopo di questo articolo non era di offrire una soluzione né tantomeno un applicativo. Il codice fornito è figlio di quello del post precedente, per cui inizialmente pensai che si potesse applicare a brani di testo. Per i motivi esposti all’inizio tale ipotesi presentava complicanze e difficoltà, almeno per chi scrive e... la sua pigrizia, decidendo così di agire carattere per carattere.

Da ultimo mi vengono in mente due possibili correzioni:

1) inserire nella TextBox una sola riga con una sola colonna, inserendo poi altre colonne (e celle) in relazione al numero di caratteri del documento;

2) rinunciare alla TextBox e inserire di brutto in cima a entrambe le Sub Cripta e Decripta un’istruzione VettShift = Array(3,5,2,... ), questa scelta oltretutto velocizza l’esecuzione ma richiede che il numero e i valori degli scorrimenti vengano elaborati a parte (suggerimento: tramite Excel).

posted @ lunedì 1 gennaio 0001 00:00 | Feedback (0) |

Powered by:
Powered By Subtext Powered By ASP.NET