Sono completamente nuovo alla crittografia, ma sto imparando. Ho messo insieme molti suggerimenti diversi dalla mia ricerca online, e ho creato la mia classe per gestire l'hash, il sale, lo stretching chiave e il confronto/conversione dei dati associati.Come utilizzare SHA-512 con Rfc2898DeriveBytes nel mio codice salina e hash?
Dopo aver ricercato la libreria .NET integrata per la crittografia, ho scoperto che quello che ho è ancora solo SHA-1. Ma sto arrivando alla conclusione che non è male visto che sto usando più iterazioni del processo di hash. È corretto?
Ma se volessi iniziare con il più robusto SHA-512, come potrei implementarlo nel mio codice qui sotto? Grazie in anticipo.
using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
public class CryptoSaltAndHash
{
private string strHash;
private string strSalt;
public const int SaltSizeInBytes = 128;
public const int HashSizeInBytes = 1024;
public const int Iterations = 3000;
public string Hash { get { return strHash; } }
public string Salt { get { return strSalt; } }
public CryptoSaltAndHash(SecureString ThisPassword)
{
byte[] bytesSalt = new byte[SaltSizeInBytes];
using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
{
crypto.GetBytes(bytesSalt);
}
strSalt = Convert.ToBase64String(bytesSalt);
strHash = ComputeHash(strSalt, ThisPassword);
}
public static string ComputeHash(string ThisSalt, SecureString ThisPassword)
{
byte[] bytesSalt = Convert.FromBase64String(ThisSalt);
Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(
convertSecureStringToString(ThisPassword), bytesSalt, Iterations);
using (pbkdf2)
{
return Convert.ToBase64String(pbkdf2.GetBytes(HashSizeInBytes));
}
}
public static bool Verify(string ThisSalt, string ThisHash, SecureString ThisPassword)
{
if (slowEquals(getBytes(ThisHash), getBytes(ComputeHash(ThisSalt, ThisPassword))))
{
return true;
}
return false;
}
private static string convertSecureStringToString(SecureString MySecureString)
{
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.SecureStringToGlobalAllocUnicode(MySecureString);
return Marshal.PtrToStringUni(ptr);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(ptr);
}
}
private static bool slowEquals(byte[] A, byte[] B)
{
int intDiff = A.Length^B.Length;
for (int i = 0; i < A.Length && i < B.Length; i++)
{
intDiff |= A[i]^B[i];
}
return intDiff == 0;
}
private static byte[] getBytes(string MyString)
{
byte[] b = new byte[MyString.Length * sizeof(char)];
System.Buffer.BlockCopy(MyString.ToCharArray(), 0, b, 0, b.Length);
return b;
}
}
Note: ho fatto riferimento un sacco di pratiche da https://crackstation.net/hashing-security.htm. Il metodo di confronto slowEquals consiste nel normalizzare i tempi di esecuzione prevenendo la ramificazione. L'uso di SecureString consiste nel disporre di una forma crittografata della password che passa tra questa classe e altre classi e pagine all'interno della mia applicazione web. Mentre questo sito sarà su HTTPS, è sempre bello fare il possibile per assicurarsi che le cose siano il più sicure possibili pur rimanendo nei limiti della ragionevolezza.
Nel mio codice, ho impostato la stringa della chiave su 128 byte (anche se a volte diventa più grande, che va bene), la dimensione dell'hash su 1 KB e il numero di iterazioni su 3.000. È un po 'più grande del tipico sale da 64 byte, hash di 512 byte e 1.000 o 2.000 iterazioni, ma anche in questo caso la velocità di accesso e le prestazioni delle app sono una priorità estremamente bassa.
Pensieri?
Domanda simile sulla revisione del codice: [Secure password hashing] (http://codereview.stackexchange.com/questions/32856/secure-password-hashing) – CodesInChaos