Newsgroup: it.comp.appl.access
Titolo: Criptare Decriptare dati sensibili

 
Di seguito una funzione per criptare o decriptare i dati sensibili di 
un'ipotetica tabella "Clienti" che contiene dati sensibili.
La funzione può essere applicata a qualsiasi tabella modificando 
opportunamente il codice. Può essere eseguita all'apertura e alla chiusura 
del db o all'apertura di una maschera lasciando sempre criptati i dati e 
decriptandoli solo su rischiesta e con password.
I suoi limiti sono nell'impossibilità di criptare campi di testo superiori a 
255 caratteri o vuoti; pertanto accertatevi che queste caratteristiche siano 
rispettate.
Fate sempre una copia del db con i dati perchè se qualcosa va storto non 
posso assumermi responsabilità.
Per la realizzazione ho utilizzato in parte il codice messo a disposizione 
da Dima Mnushkin
Option Compare Database
Option Explicit
Const PASSWORD_KEY = "QuEStA ChIaVe12345PassAT"
'modificare la chiave con una a piacimento
'================================================
' Function: encrypt
'
' Purpose:  To encrypt or decrypt a string using
'           a predefined key value stored as
'           the constant PASSWORD_KEY.  The same
'           string encrypted twice won't always
'           look the same because the function
'           chooses a random starting position
'           within the key to encrypt values.
'
' Call:     gResult = encryt("Hello World", true)
'
' In:       strFull -   String containing the
'                       text to encrypt/decrypt
'
'           fEncrypt -  Boolean set to TRUE to
'                       encrypt the string, FALSE
'                       to decrypt it.
'
' Out:      none
'
' Returns:  String -    The encrypted/decrypted
'                       value if successful, ""
'                       otherwise
'
' History:  98/06/10 created by Dima Mnushkin
'
'================================================
Public Function encrypt(strFull As String, _
                   fEncrypt As Boolean) As String
On Error GoTo Err_encrypt
Dim intInputPos As Integer
Dim intPassKeyPos As Integer
Dim strOutput As String
Dim intTemp As Integer
Dim strStartingPos As String
If strFull = "" Then GoTo Exit_encrypt
' Encrypt a value
If fEncrypt Then
  ' Initialize the random function
  Randomize
  ' Determine the starting position to use in
  ' the encryption string
  intPassKeyPos = Int(Len(PASSWORD_KEY) * _
                          Rnd + 1)
  ' Encrypt the starting position used in
  ' preparation to storing it in the middle of
  ' the encrypted result
  intTemp = intPassKeyPos + _
            Asc(Left(PASSWORD_KEY, 1))
  If intTemp > 255 Then intTemp = intTemp - 255
  strStartingPos = Chr(intTemp)
  ' Encrypt the full string
  For intInputPos = 1 To Len(strFull)
    intPassKeyPos = intPassKeyPos + 1
    ' Wrap to the beginning of the key if we have
    ' have used up the last character.
    If intPassKeyPos > Len(PASSWORD_KEY) Then
      intPassKeyPos = 1
    End If
    ' Add the value of the character to be
    ' encrypted to the value of the character
    ' stored at the current position in the key
    intTemp = Asc(Mid(strFull, intInputPos, 1) _
                 ) + Asc(Mid(PASSWORD_KEY, _
                             intPassKeyPos, 1))
    If intTemp > 255 Then intTemp = intTemp - 255
    ' If we are at middle of the result string,
    ' insert our encrypted starting position so
    ' we can decrypt this string later.
    If CInt(Len(strFull) / 2) + 1 = intInputPos _
       Then strOutput = strOutput & strStartingPos
    strOutput = strOutput & Chr(intTemp)
  Next intInputPos
' Decrypt a value
Else
  ' Retrieve the encrypted starting position from
  ' the middle of the string to be decrypted
  intPassKeyPos = Asc(Mid(strFull, _
    CInt((Len(strFull) - 1) / 2) + 1, 1)) - _
    Asc(Left(PASSWORD_KEY, 1))
  If intPassKeyPos < 0 Then _
    intPassKeyPos = intPassKeyPos + 255
  ' Decrypt the full string
  For intInputPos = 1 To Len(strFull)
    intPassKeyPos = intPassKeyPos + 1
    If intPassKeyPos > Len(PASSWORD_KEY) Then _
      intPassKeyPos = 1
    ' Decrypt each character by subtracting the
    ' value of the corresponding character stored
    ' in the key.
    intTemp = Asc(Mid(strFull, intInputPos, 1)) - _
      Asc(Mid(PASSWORD_KEY, intPassKeyPos, 1))
    If intTemp <= 0 Then intTemp = intTemp + 255
    ' If we are looking at the middle character,
    ' ignore it since its the encrypted starting
    ' position.
    If intInputPos = CInt((Len(strFull) - 1) / 2) + _
       1 Then
      intPassKeyPos = intPassKeyPos - 1
    Else
      strOutput = strOutput & Chr(intTemp)
    End If
  Next intInputPos
End If
encrypt = strOutput
Exit_encrypt:
  Exit Function
Err_encrypt:
  encrypt = ""
  MsgBox Error
  Resume Exit_encrypt
End Function
Public Sub CifraDatiClienti()
'Cifra i dati del Cognome
Dim db As Database
Dim rcs As Recordset
Dim i As Integer
Set db = CurrentDb
Set rcs = db.OpenRecordset("Clienti")
rcs.MoveLast
rcs.MoveFirst
For i = 1 To rcs.RecordCount
With rcs
.Edit
!Cognome = encrypt(!Cognome, True)
.Update
End With
rcs.MoveNext
Next i
rcs.Close
Set rcs = Nothing
Set db = Nothing
End Sub
Public Sub DeCifraDatiClienti()
'decifra i dati precedentemente criptati
Dim db As Database
Dim rcs As Recordset
Dim i As Integer
Set db = CurrentDb
Set rcs = db.OpenRecordset("Clienti")
rcs.MoveLast
rcs.MoveFirst
For i = 1 To rcs.RecordCount
With rcs
.Edit
!Cognome = encrypt(!Cognome, False)
.Update
End With
rcs.MoveNext
Next i
rcs.Close
Set rcs = Nothing
Set db = Nothing
End Sub
Sperando di aver fatto cosa gradita e se il sitocomune dovesse ritenerla 
valida ne autorizzo la pubblicazione.
Attendo commenti.
Ciao, Carlo 

 Attendo commenti.
Il problema dell'utilizzo degli algoritmi di crittazione (ed è importante
premettere che la pseudo normativa sulla sicurezza ne "chiede" l'utilizzo in
ambito sanitario, non in generale) è come e quando utilizzarli.
Obiettivo: impedire a estranei di accedere ai DataBase, con un qualunque
sistema, e leggere dati relativi alla salute dei pazienti, preferenze
sessuali, etc.
Ora, se i dati di una o più tabelle fossero decrittati su apertura del DB,
questo comporterebbe che per tutto il periodo d'utilizzo del DB tali dati
sarebbero visibili a tutti ... anche a chi si collegasse alle tabelle con
tools d'amministrazione esterni (tipo Access o Enterprise Manager).
Soluzione non accettabile.
Ma anche decrittando su apertura delle maschere la sicurezza non è
garantita: per tutto il tempo in cui tale maschera sarà aperta i dati della
tabella/e sottostante/i saranno visibili a tutti.
Una soluzione che possa garantire maggiore sicurezza (fino a un certo punto)
consiste nel traslare su temporanei locali i dati del server, decrittare
localmente e dare in pasto alla Form/Report la tabella ottenuta.
E viceversa quando le modifiche sull'area locale saranno terminate e i dati
devono essere riportati sul Server.
Ma in questo modo la programmazione si complica notevolmente e i vecchi
programmi andrebbero riscritti.
Ciao


Voglio solo aggiungere che l'algoritmo proposto può servire anche a tanti 
altri scopi, primo fra tutti la possibilità di criptare password, dati 
utilizzati dal programmatore in tabelle temporanee, criptare seriali di 
utilizzo, ecc.
Ha il limite dei 255 caratteri ma in normali campi testo svolge bene il suo 
compito.
Ciao e grazie per le tue utilissime osservazioni.
Carlo

 Anche in questo caso sono visibili i dati temporanei!
Ma certo è chiaro che sono visibili: infatti ho scritto "una soluzione che
possa garantire maggiore sicurezza (fino a un certo
punto)"
Probabilmente anche questa non è accettabile ma assicura che il DB condiviso
sia sempre crittato, anche con archivi JET.
Il problema della soluzione che hai proposto (e lo hai giustamente accennato
nel post originale) è che se qualcosa va storto durante il processo di
"crittazione"/"decrittazione" sul DB condiviso, i dati sul Server restano
disallineati: terribile!
Ora la soluzione sarebbe racchiudere in una transazione esplicita la routine
di "crittazione/decrittazione": aggiornamento tutto o niente.
Ma le transazioni non sono affidabili in logica "tutto o niente" con un
file-Server come jet privo di componente Ram resident sul PC Server.
Quindi si dovrebbe per forza adottare un Database Server ed escludere
totalmente Jet.
Magari nel caso tuo è proprio così, ma converrai che in generale il motore
Jet di Access è ancora molto utilizzato.
Ciao: Simone


Cut
Ciao Simone
condivido quasi tutto.
Vanno criptati solo i dati sensibili: abitudini sessuali, religione, esami 
medici, diagnosi, ecc.
Questi dati possono essere criptati una volta per tutte e solo 
all'occorrenza vanno decriptati (solo il record che interessa) in una 
maschera temporanea (tabella temporanea) e visualizzati. Alla chiusura non 
rimane nulla.
Una ipotetica ricerca va fatta sul cognome e il nome in chiaro. Anche la 
stampa (per esempio del ricovero) va fatta "al volo", decriptando i valori 
sul report (non collegato). Cosě per i certificati. In pratica i dati 
sensibili restano sempre criptati...si lavora per cosě dire in memoria...
Ognuno si regola come vuole. Per gli ospedali la cosa č veramente piů 
stringente...nella mia azienda stiamo migrando a sqlserver ma anche qui chi 
accede (p.e. in manutenzione) al db ha campo libero...fatto salvo la 
protezione di sistema
La criptazione non serve solo agli ospedali o ai medici di base, per esempio 
serve alla ditte per i loro prezzi riservati o per l'elenco dei dipendenti o 
dei contatti.
Per chi volesse usare la funzione proposta, per maggiore sicurezza 
aggiungerei alla tabella da criptare un campo "Criptato" Si/No, onde evitare 
di ripetere l'operazione con danni quasi irreparabili.
Ciao, Carlo 

 post.
Concordo, e ci sono altre casistiche in cui si verificherebbero problemi.
Anzitutto i backup: in molte aziende è necessario che vengano effettuati "a
caldo" perchè ci sono sempre utenti collegati ... se i dati venissero
decrittati nel DB come suggeriva Carlo, le copie risultanti sarebbero un
macello: conterrebbero dati crittati e altri decrittati.
E poi non dimentichiamo che nelle grandi aziende c'è sempre la necessità di
realizzare piccole verticalizzazioni, quindi è normale che ci sia un utente
esperto (spesso un programmatore interno) che abbia licenza di collegarsi
via ODBC alle tabelle sul Server, magari per estrapolare statistiche
personalizzate.
E dopo aver collegato le tabelle si ritroverebbe con ogni probabilità
records ben leggibili in mezzo ad altri crittati...
Saluti.