Saltar a actualización a continuación < no estoy seguro de cómo hacer un enlace :(
He hecho algunas mejoras en el código de: Csharp- AES-bits-Encryption-Library-with-Salt
- saltBytes ahora es el SHA512 de la contraseña.
- Random IV para cada llamada de cifrado. (La longitud 16 de IV se agrega al archivo encriptado, se elimina del archivo antes del descifrado)
¿Ves algún defecto, algo que necesite optimización? En particular, mis preguntas son:
¿Está mi método
generateIV()
a continuación en el "Código de cifrado" seguro y protegido? Tenga en cuenta que su única dependencia es en .NETRNGCryptoServiceProvider Class
.¿Es seguro usar el hash de contraseña como un salt? o debería ser aleatorio como el IV y almacenado junto con el texto cifrado?
Solo para referencia, aquí está mi código.
El siguiente código está funcionando. He realizado una prueba para cifrar dos archivos de texto con exactamente el mismo texto dentro de cada uno. El resultado es que ambos tienen datos diferentes, y descifran con éxito.
También verifiqué antes de que el IV aleatorio, ambos archivos tuvieran el mismo texto cifrado y obtuvieran los mismos datos.
Código de cifrado:
private static int IV_LENGTH = 16;
public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
byte[] encryptedBytesAndIV = null;
byte[] saltBytes = SHA512.Create().ComputeHash(passwordBytes);
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
using (AesCryptoServiceProvider AES = new AesCryptoServiceProvider())
{
AES.KeySize = 256;
//AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 100);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = generateIV();
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
encryptedBytesAndIV = new byte[encryptedBytes.Length + AES.IV.Length];
AES.IV.CopyTo(encryptedBytesAndIV, 0);
encryptedBytes.CopyTo(encryptedBytesAndIV, IV_LENGTH);
}
}
return encryptedBytesAndIV;
}
private static byte[] generateIV()
{
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
byte[] nonce = new byte[IV_LENGTH];
rng.GetBytes(nonce);
return nonce;
}
}
Código de descifrado:
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
byte[] saltBytes = SHA512.Create().ComputeHash(passwordBytes);
using (MemoryStream ms = new MemoryStream())
{
using (AesCryptoServiceProvider AES = new AesCryptoServiceProvider())
{
AES.KeySize = 256;
//AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 100);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = getIV(bytesToBeDecrypted);
bytesToBeDecrypted = removeTagAndIV(bytesToBeDecrypted);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
private static byte[] removeTagAndIV(byte[] arr)
{
byte[] enc = new byte[arr.Length - IV_LENGTH];
Array.Copy(arr, IV_LENGTH, enc, 0, arr.Length - IV_LENGTH);
return enc;
}
private static byte[] getIV(byte[] arr)
{
byte[] IV = new byte[IV_LENGTH];
Array.Copy(arr, 0, IV, 0, IV_LENGTH);
return IV;
}
Actualizar:
Aquí hay un código actualizado basado en comentarios / recomendaciones / consejos
- Sal aleatoria Verdadera
- iteraciones 100000
Encriptación:
public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
byte[] encryptedBytesFinal = null;
byte[] saltBytes = generateIVandSalt(16);
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
using (AesCryptoServiceProvider AES = new AesCryptoServiceProvider())
{
AES.KeySize = 256;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 100000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = generateIVandSalt(16);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
encryptedBytesFinal = new byte[encryptedBytes.Length + AES.IV.Length + saltBytes.Length];
AES.IV.CopyTo(encryptedBytesFinal, 0);
saltBytes.CopyTo(encryptedBytesFinal, 16);
encryptedBytes.CopyTo(encryptedBytesFinal, 16 + 16);
}
}
return encryptedBytesFinal;
}
private static byte[] generateIVandSalt(int len)
{
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
byte[] nonce = new byte[len];
rng.GetBytes(nonce);
return nonce;
}
}
Descifrado:
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
byte[] saltBytes = getSalt(bytesToBeDecrypted);
using (MemoryStream ms = new MemoryStream())
{
using (AesCryptoServiceProvider AES = new AesCryptoServiceProvider())
{
AES.KeySize = 256;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 100000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = getIV(bytesToBeDecrypted);
bytesToBeDecrypted = removeIVandSalt(bytesToBeDecrypted);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
private static byte[] removeIVandSalt(byte[] arr)
{
byte[] enc = new byte[arr.Length - 16 - IV_LENGTH];
Array.Copy(arr, IV_LENGTH + 16, enc, 0, arr.Length - IV_LENGTH - 16);
return enc;
}
private static byte[] getIV(byte[] arr)
{
byte[] IV = new byte[IV_LENGTH];
Array.Copy(arr, 0, IV, 0, IV_LENGTH);
return IV;
}
private static byte[] getSalt(byte[] arr)
{
byte[] salt = new byte[16];
Array.Copy(arr, IV_LENGTH, salt, 0, 16);
return salt;
}