2012-01-15 17 views
19

Desidero fornire all'utente la possibilità di salvare i dati personali crittografati. Questo potrebbe essere banale o potrebbe essere già stato chiesto, ma non sono in grado di trovare un esempio di un modo facile da usare per crittografare/decrittografare una password.Come posso crittografare le impostazioni dell'utente (come le password) nella mia applicazione?

Non ho davvero bisogno di alcuna password super-magic-unbreakable. Ho solo bisogno che la password sia difficile da rompere.

Ho visto alcune domande msdn e SO ma non ho trovato qualcosa da usare.

+0

questione connessa: [? Come crittografare una password per il salvataggio in un secondo momento in un file di database o di testo] (http://stackoverflow.com/questions/ 541.219/how-to-crittografare-a-parola-per-salvare-it-tardi-in-a-database o file di testo-). E molto, molto di più: [Domande contenenti 'C# cripta password'] (http://stackoverflow.com/search?q=c%23+encrypt+password). –

+4

Nota che qualunque cosa tu faccia, tu * non * decifri * le password **. Piuttosto, ti assicuri che i due hash corrispondano. –

+1

@CodyGray c'è un modo per inviare la password con hash nella stringa di connessione sql? – Odys

risposta

31

David, ho pensato your answer era ingegnoso, ma ho pensato che quelli sarebbero niftier come metodi di estensione . Ciò consentirebbe tale sintassi:

string cypherText; 
string clearText; 

using (var secureString = "Some string to encrypt".ToSecureString()) 
{ 
    cypherText = secureString.EncryptString(); 
} 

using (var secureString = cypherText.DecryptString()) 
{ 
    clearText = secureString.ToInsecureString(); 
} 

Ecco il codice aggiornato:

using System; 
using System.Collections.Generic; 
using System.Runtime.InteropServices; 
using System.Security; 
using System.Security.Cryptography; 
using System.Text; 

public static class SecureIt 
{ 
    private static readonly byte[] entropy = Encoding.Unicode.GetBytes("Salt Is Not A Password"); 

    public static string EncryptString(this SecureString input) 
    { 
     if (input == null) 
     { 
      return null; 
     } 

     var encryptedData = ProtectedData.Protect(
      Encoding.Unicode.GetBytes(input.ToInsecureString()), 
      entropy, 
      DataProtectionScope.CurrentUser); 

     return Convert.ToBase64String(encryptedData); 
    } 

    public static SecureString DecryptString(this string encryptedData) 
    { 
     if (encryptedData == null) 
     { 
      return null; 
     } 

     try 
     { 
      var decryptedData = ProtectedData.Unprotect(
       Convert.FromBase64String(encryptedData), 
       entropy, 
       DataProtectionScope.CurrentUser); 

      return Encoding.Unicode.GetString(decryptedData).ToSecureString(); 
     } 
     catch 
     { 
      return new SecureString(); 
     } 
    } 

    public static SecureString ToSecureString(this IEnumerable<char> input) 
    { 
     if (input == null) 
     { 
      return null; 
     } 

     var secure = new SecureString(); 

     foreach (var c in input) 
     { 
      secure.AppendChar(c); 
     } 

     secure.MakeReadOnly(); 
     return secure; 
    } 

    public static string ToInsecureString(this SecureString input) 
    { 
     if (input == null) 
     { 
      return null; 
     } 

     var ptr = Marshal.SecureStringToBSTR(input); 

     try 
     { 
      return Marshal.PtrToStringBSTR(ptr); 
     } 
     finally 
     { 
      Marshal.ZeroFreeBSTR(ptr); 
     } 
    } 
} 
+0

Bel miglioramento. Ho copiato il codice da un vecchio progetto di test unitario in cui stavo usando account utente e password per test. Volevo archiviare le password in modo sicuro in modo da poter eseguire i test senza dover visualizzare o registrare le password in chiaro. –

+0

Vedere la nota che ho lasciato in basso sulla risposta di @DavidClarke, e vedere questo rilevante [msdn link] (https://msdn.microsoft.com/en-us/library/system.security.securestring (v = vs.110) aspx) – Matt

16

Quanto segue è tanto semplice quanto si ottiene, presupponendo che si voglia veramente essere in grado di crittografare/decrittografare una stringa e memorizzarla su disco. Si noti che non utilizza una password, ma utilizza il contesto di sicurezza dell'utente connesso System.Security.Cryptography.DataProtectionScope.CurrentUser per proteggere i dati.

public class SecureIt 
{ 
    static byte[] entropy = System.Text.Encoding.Unicode.GetBytes("Salt Is Not A Password"); 

    public static string EncryptString(System.Security.SecureString input) 
    { 
     byte[] encryptedData = System.Security.Cryptography.ProtectedData.Protect(
      System.Text.Encoding.Unicode.GetBytes(ToInsecureString(input)), 
      entropy, 
      System.Security.Cryptography.DataProtectionScope.CurrentUser); 
     return Convert.ToBase64String(encryptedData); 
    } 

    public static SecureString DecryptString(string encryptedData) 
    { 
     try 
     { 
      byte[] decryptedData = System.Security.Cryptography.ProtectedData.Unprotect(
       Convert.FromBase64String(encryptedData), 
       entropy, 
       System.Security.Cryptography.DataProtectionScope.CurrentUser); 
      return ToSecureString(System.Text.Encoding.Unicode.GetString(decryptedData)); 
     } 
     catch 
     { 
      return new SecureString(); 
     } 
    } 

    public static SecureString ToSecureString(string input) 
    { 
     SecureString secure = new SecureString(); 
     foreach (char c in input) 
     { 
      secure.AppendChar(c); 
     } 
     secure.MakeReadOnly(); 
     return secure; 
    } 

    public static string ToInsecureString(SecureString input) 
    { 
     string returnValue = string.Empty; 
     IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input); 
     try 
     { 
      returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr); 
     } 
     finally 
     { 
      System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr); 
     } 
     return returnValue; 
    } 

} 

Poi per crittografare una stringa:

var clearText = "Some string to encrypt"; 
    var cypherText = SecureIt.EncryptString(SecureIt.ToSecureString(clearText)); 

E per decifrare successivamente:

var clearText = SecureIt.ToInsecureString(SecureIt.DecryptString(cypherText)); 
+2

Se decrittografate una stringa sicura non ha senso usare una stringa sicura. L'intero scopo è di mantenere la stringa completa da un singolo blocco di memoria. Non è meglio usare questo metodo di quanto lo sarebbe se si prendesse una stringa e la si crittografasse: 'Un oggetto SecureString non dovrebbe mai essere costruito da una stringa, perché i dati sensibili sono già soggetti alle conseguenze di persistenza della memoria del Classe String immutabile. Il modo migliore per costruire un oggetto SecureString proviene da una fonte non gestita alla volta, come la Console.Metodo ReadKey. – Matt

+0

Questo è un buon punto. Non sto suggerendo che tutti i metodi dovrebbero essere utilizzati nella stessa applicazione. Stavo usando un'app console separata per acquisire la stringa e crittografarla prima di archiviarla in modo sicuro nelle impostazioni per un progetto di test dell'unità. L'intenzione era quella di fornire una sicurezza sufficiente per il contesto in cui veniva utilizzato. –

1

Per il mio scopo modifico Jesse C. Slicer soluzione non utilizzare per SecureString come non è importante per me proteggere la memoria. Ho solo bisogno di serializzare le stringhe cifrate. Per fare in modo che questo progetto di lavoro abbia bisogno di fare riferimento a System.Security (non solo usando la dichiarazione).

public static class StringSecurityHelper 
{ 
    private static readonly byte[] entropy = Encoding.Unicode.GetBytes("5ID'&mc %[email protected]%n!G^ fiVn8 *tNh3eB %rDaVijn!.c b"); 

    public static string EncryptString(this string input) 
    { 
     if (input == null) 
     { 
      return null; 
     } 

     byte[] encryptedData = ProtectedData.Protect(Encoding.Unicode.GetBytes(input), entropy, DataProtectionScope.CurrentUser); 

     return Convert.ToBase64String(encryptedData); 
    } 

    public static string DecryptString(this string encryptedData) 
    { 
     if (encryptedData == null) 
     { 
      return null; 
     } 

     try 
     { 
      byte[] decryptedData = ProtectedData.Unprotect(Convert.FromBase64String(encryptedData), entropy, DataProtectionScope.CurrentUser); 

      return Encoding.Unicode.GetString(decryptedData); 
     } 
     catch 
     { 
      return null; 
     } 
    } 
} 

E per usarlo:

string cypherText = "My string".EncryptString(); 
string clearText = cypherText.DecryptString(); 
Problemi correlati