Gianni Giaccaglini

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

venerdì 27 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) |

Crittografia di un testo con Excel + VBA

 Criptare/decriptare un testo usando Excel + VBA

Premessa teorica. Dal dibattito sui procedimenti di cifratura/decifratura o, come qui mi esprimerò, di criptazione/decriptazione di un testo alla fine è scaturito questo caposaldo: soltanto una chiave di lunghezza uguale a quella del testo garantisce totale segretezza

Convinto che questa meta sia molto ardua da conseguire (specie se a livello di un amatore per quanto creativo) ritengo tuttavia che si possa raggiungere un ragionevole compromesso, adottando per giunta criteri particolari non del tutto standard (anche se non s’inventa nulla a questo m ondo…).

 

Veniamo al dunque mostrando subito la parte sinistra del modello Excel, posta a partire dalla cella A1.

NOTA. Le evidenziazioni come sfondi e sottolineatura sono servite a mostrare che il codice macro agisce esclusivamente sui valori, lasciando immutate e formattazioni.

Brani originali

Shift1

Shift2

Shift3

Shift4

Brani criptati

Nel deserto dell'Africa

4

3

3

2

dfmtiD+nohh"rwvgvhh"ohR

un leone, che j'era entrato n’ago

2

4

1

4

pxcvurg$bvg+k$gld$.iosgp!rw

chiamò un tenente.

5

4

1

3

2jwoishu$sx!ördjlh

"Grazie! - je disse doppo - .

5

4

2

5

3%/$tursi%gwxnf$jo"1%&gmftK'

de avemme libberato.

5

1

5

2

0tuftjcgkq!jorf{c%fi

Vedrai sarò ariconoscente.

3

4

1

3

2hwoifvprrfjvd#óvdv!mdueiY

Che voi? Esse promosso?

3

2

4

4

Cqvwsorvt"hwwG#Cmqy$ijF

Embè...te darò na mano."

2

2

5

5

'3qpfr"cs%ôtfi"gy300ígoG

E quella sera stessa

3

5

5

2

cxxhvx%dtjx#cqqhwv%H

mantenne la promessa.

4

5

2

3

2duxipqwt#cq$hpsiwpfq

Andò dar tenente: "Amico,

1

5

4

1

-pgnnB&%;fxsfoiy!sei!óhsB

 la promozione è certa;

3

1

1

4

$<bwvfd#ì!fqsj{rqpss$bm#

ho magnato er capitano."

2

1

2

2

$0ppcvjrce!tg"pvcphco"pj

CIFRE E SEGNI SPECIALI:

2

5

5

3

?NNDNHGSX%KQLJU#J%GUKNE

    12*3^3 >= 4àéè§[]%& y=(1+0,25x)

2

1

1

4

*y76-1-5)>{$'&__¨éëä5!?B!4`7+33

 

Sulla prima colonna si ha una serie di brani originari, affiancata dalla colonna dei vari scorrimenti  (Shift) da applicare ad essi, in modo ciclico. Facciamo un esempio, partendo dal primo brano (Nel deserto…). Ai vari caratteri si applicano gli shift posti fra parentesi, che si susseguono con 4, 3, 3, 2 poi di nuovo 4, 3, ecc.

N (4) => R; e(3) =>h;  l(3) => o spazio(2) => "; d(4) =>h; e(3) =>h ... e via di seguito, ottenendo Rho”hh...

N.B. Il fatto di aver spezzato un testo in brani di lunghezza limitata dovrebbe far sì che quattro scorrimenti bastino a fornire una ragionevole sicurezza contro curiosi e spie, umani o softwaristici. A ciò ho aggiunto due particolarità:

1) Gli shift vengono di volta in volta creati mediante numeri  casuali.

2) Nella criptazione, come nell’opposta operazione decriptante, è stata usata la funzione VBA StrReverse (Testo) che rovescia un Testo, tramutando ad esempio Roma in amoR.

NOTA. Si riveda il caso del primo brano (Nel deserto…). Sopra avevamo visto che la criptazione lo traduce in Rho”hh... Qualcuno si sarà stupito di non aver trovato questa sequenza nella terza colonna. Ma rileggendola all’incontrario il mistero si chiarisce, alla luce dell’osservazione 2.

Sulla colonna subito a destra (non riportata sopra per motivi editoriali) si ha la situazione identica all’originale, com’era da attendersi.

Brani decriptati

Nel deserto dell'Africa

un leone, che j'era entrato

chiamò un tenente.

"Grazie! - je disse doppo - .

de avemme libberato.

Vedrai sarò ariconoscente.

Che voi? Esse promosso?

Embè...te darò na mano."

E quella sera stessa

mantenne la promessa.

Andò dar tenente: "Amico,

 la promozione è certa;

ho magnato er capitano."

CIFRE E SEGNI SPECIALI:

12*3^3 >= 4àéè§[]%& y=(1+0,25x)

 

N.B. I risultati della prima e della quarta colonna derivano da due funzioni personali dal nome promettente TestoCript e TestoDecript entrambe dotate di argomenti Testo, Sh1, Sh2, Sh3 ed Sh4. Altro non sono che i succitati scorrimenti, alias Shift.

Prima di esaminarle indichiamone l’impiego, ponendo sulla sinistra l’intervallo cui ciascuna è applicata:

F2:F16=TestoCript(A2;B2;C2;D2;E2) 
G2:G16=TestoDecript(F2;B2;C2;D2;E2)

Ai buoni intenditori che hanno seguito questi discorsi non servono altre ciance.

Il codice criptante

Si trova nel Modulo1, insieme alla macro che prepara gli scorrimenti (pseudo) casuali:

Dim ZonaShift As Range ' Variabile a livello Modulo

Sub CaricaShift()
  Dim NumRighe As Integer
  With Range("A2")
    NumRighe = Range(.Cells(1), .End(xlDown)).Rows.Count
  End With
  Set ZonaShift = Range(Range("B2"), Cells(NumRighe + 1, 5))
  Dim Cella As Range
  For Each Cella In ZonaShift
    Cella = Int(Rnd * 5 + 1)
  Next
End Sub

Function TestoCript(ByVal Testo As String, Sh1 As Integer, Sh2 As Integer, Sh3 As Integer, Sh4 As Integer) As String
  Dim VettShift(1 To 4) As Integer
  Dim i As Integer, j As Integer
  ' Carica scorrimenti nella matrice VettShift
  VettShift(1) = Sh1
  VettShift(2) = Sh2
  VettShift(3) = Sh3
  VettShift(4) = Sh4
  Dim NuovoTesto As String, Car As String
  j = 1
  For i = 1 To Len(Testo)
    Car = _
    Chr(Asc(Mid(Testo, i, 1)) + VettShift(j))
    j = IIf(j = 4, 1, j + 1)
    NuovoTesto = NuovoTesto & Car
  Next
  TestoCript = StrReverse(NuovoTesto)
End Function

Sub ProvaTestoCript()
  MsgBox TestoCript("Amba123;?", 1, 2, 3, 4)
End Sub

È importante sottolineare che l’istruzione
TestoCript = StrReverse(NuovoTesto)

è presente all’uscita della Function, il cui risultato deriva dalla successione cripta poi rovescia. Come conviene anticipare ed è logico attendersi, l’imminente funzione di decriptazione compie le due operazioni in senso contrario.

Il codice de-criptante

Si trova nel Modulo2.  È riportato qui di seguito, a questo punto affidando commenti dettagliati all’esegesi-self di quanti hanno compreso  il codice precedente, di cui questo è stretto parente.

Function TestoDecript(ByVal Testo As String, Sh1 As Integer, Sh2 As Integer, Sh3 As Integer, Sh4 As Integer) As String
Dim VettShift(1 To 4) As Integer
  Dim i As Integer, j As Integer
  ' Carica Shift in VettShift, con segno opposto
  VettShift(1) = -Sh1
  VettShift(2) = -Sh2
  VettShift(3) = -Sh3
  VettShift(4) = -Sh4
  Dim NuovoTesto As String, Car As String
  j = 1
  Testo = StrReverse(Testo)
  For i = 1 To Len(Testo)
    Car = _
    Chr(Asc(Mid(Testo, i, 1)) + VettShift(j))
    j = IIf(j = 4, 1, j + 1)
    NuovoTesto = NuovoTesto & Car
  Next
  TestoDecript = NuovoTesto
End Function

Come testé anticipato, è necessario e sufficiente far notare che l’istruzione
Testo = StrReverse(Testo)

In questo caso precede il ciclo For ...  Next di decriptazione.

Come usare il modello

Il suo scopo primario era quello di offrire una palestra per comprendere certi principi. L’applicazione pratica, nel caso di un dialogo con un collega fidato potrebbe procedere con i passaggi seguenti.

1. Tradurre le formule dei brani criptati in valori.

2. Copiare tutte le colonne del modello esclusa la prima.

3. Incollare tale materiale in un nuovo spreadsheet, per salvarlo e spedirlo al partner.

Mi è mancata la voglia e il tempo di automatizzare tali operazioni. Comunque agl’interessati suggerisco questo codice che svolge il primo mestiere. Corrisponde a un utilizzo manuale per abilissimi: 1) copiare l’intervallo; 2) spostarlo un pochino col clic destro senza lasciare la presa; 3) riportalo nella posizione di partenza; 4) scegliere Copia qui come valori.

Range("F2:F16").Copy
Range("F2:F16").Select
Selection.PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False

NOTA.  I più diffidenti potrebbero occultare le colonnine degli shift, magari con larghezza minima e caratteri bianchi, e soprattutto proteggendone l’accesso con mosse che do per note e passward nota al nostro amico.

Senza l’operazione predetta il neonato foglio di lavoro si presenta con l’angosciante ma non imprevista domanda sull’estrema colonna.

Shift1

Shift2

Shift3

Shift4

Brani criptati

Brani decriptati

4

3

3

2

gqrin#qy"dfmtiD+nohh"rwvgvhh"ohR

#NOME?

2

4

1

4

ieikt!vc$pvvrfh"she"rv$qxbvvrf$cvf+l$fle

#NOME?

5

4

1

3

1frtl{~fuftt*m$whq$jwoishu$sx!ördjlh

#NOME?

5

4

2

5

3tk~ftksnte,y"sn%/$tursi%gwxnf$jo"1%&gmftK'

#NOME?

5

1

5

2

qn{cwux",pyu%bi"tuftjcgkq!jorf{c%fi

#NOME?

3

4

1

3

1hurhftsqrdmud!öudt$hw!ikf!mdueiY

#NOME?

3

2

4

4

Csuvsqqut$gvwi)G$Cqxx$quimuqit"ui$ê#pewT

#NOME?

2

2

5

5

'0qsfo"fs"ôwff"jy".txuqu%qk,x".ígoG

#NOME?

3

5

5

2

cxxhvx%dtjx#cqqhwv%H"3twvfk#pz%h"tywgi%qw%zI

#NOME?

4

5

2

3

rpfmwunvf"sy*f%smgr$üku$duxipqwt#cq$hpsiwpfq

#NOME?

1

5

4

1

0tdjqF#!>jttmi!f$juoisfu$wbe$jefrlB

#NOME?

3

1

1

4

#sdjg$pm#iu!h$-bwvfd#ì!fqsj{rqpss$bm#

#NOME?

2

1

2

2

#0qpbvkrbe"tf"qvbpicn"qu!go"êjetfr

#NOME?

2

5

5

3

<LQFKFJUU#NSIHX%G#JWHLH%PRH%CYTWR

#NOME?

2

1

1

4

*z.63.4!,"5)>{$'&__¨éëä""qspO"C55"A?!57!4`7+33

#NOME?

 

A questo punto non resta altro da fare:

3. Spedire al partner il Modulo2, che costituisce la vera chiave decriptante!

Costui potrà semplicemente importarla vedendo così risuscitare i brani originali al posto dei vari angoscianti #NOME?.

Ricordo in fine che la cosa funziona anche con un formato .xlsx (ovviamente la fatidica funzione si perde al salvataggio, ma se rispondiamo giusto alla segnalazione di Excel possiamo sempre imporre il formato .xlsm.

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

Powered by:
Powered By Subtext Powered By ASP.NET