Cifrado simétrico (AES): ¿Es seguro y adecuado guardar el IV y el Salt junto con los datos cifrados?


Estoy tratando de dar sentido a cómo manejar y administrar un vector de inicialización y salt (cuando corresponda) al cifrar y descifrar datos utilizando un algoritmo de cifrado simétrico, en este caso AES.

He deducido de diferentes hilos de SO y varios otros sitios web que ni el IV o salt necesitan ser secretos, solo únicos para defenderse contra ataques criptoanalíticos como un ataque de fuerza bruta. Con esto en mente pensé que sería viable almacenar mi pseudo IV aleatorio con los datos cifrados. Estoy preguntando si el método que estoy usando es adecuado y, además, ¿debería tratar mi sal codificada actualmente de la misma manera? Que está escribiendo a la corriente de la memoria a lo largo del lado del IV

Mi código:

private const ushort ITERATIONS = 300;
private static readonly byte[] SALT = new byte[] { 0x26, 0xdc, 0xff, 0x00, 0xad, 0xed, 0x7a, 0xee, 0xc5, 0xfe, 0x07, 0xaf, 0x4d, 0x08, 0x22,  0x3c };

private static byte[] CreateKey(string password, int keySize)
{
    DeriveBytes derivedKey = new Rfc2898DeriveBytes(password, SALT, ITERATIONS);
    return derivedKey.GetBytes(keySize >> 3);
}

public static byte[] Encrypt(byte[] data, string password)
{
    byte[] encryptedData = null;
    using (AesCryptoServiceProvider provider = new AesCryptoServiceProvider())
    {
        provider.GenerateIV();
        provider.Key = CreateKey(password, provider.KeySize);
        provider.Mode = CipherMode.CBC;
        provider.Padding = PaddingMode.PKCS7;

        using (MemoryStream memStream = new MemoryStream(data.Length))
        {
            memStream.Write(provider.IV, 0, 16);
            using (ICryptoTransform encryptor = provider.CreateEncryptor(provider.Key, provider.IV))
            {
                using (CryptoStream cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(data, 0, data.Length);
                    cryptoStream.FlushFinalBlock();
                }
            }
            encryptedData = memStream.ToArray();
        }
    }
    return encryptedData;
}

public static byte[] Decrypt(byte[] data, string password)
{
    byte[] decryptedData = new byte[data.Length];
    using (AesCryptoServiceProvider provider = new AesCryptoServiceProvider())
    {
        provider.Key = CreateKey(password, provider.KeySize);
        provider.Mode = CipherMode.CBC;
        provider.Padding = PaddingMode.PKCS7;
        using (MemoryStream memStream = new MemoryStream(data))
        {
            byte[] iv = new byte[16];
            memStream.Read(iv, 0, 16);
            using (ICryptoTransform decryptor = provider.CreateDecryptor(provider.Key, iv))
            {
                using (CryptoStream cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read))
                {
                    cryptoStream.Read(decryptedData, 0, decryptedData.Length);
                }
            }
        }
    }
    return decryptedData;
}

También estoy abierto a cualquier otra información sobre el cifrado simétrico con respecto a la práctica adecuada.

Author: CodesInChaos, 2012-12-16

2 answers

Almacenar el IV y la Sal junto con el texto cifrado es apropiado y una buena práctica. Codificación dura la sal no es útil, ser aleatorio es importante, codificación dura las iteraciones está perfectamente bien, pero es típicamente mucho más alto que 300 (de hecho, al menos 1000 y por lo general ir mucho más alto si su máquina/uso puede manejarlo como en 10s de miles).

Debido a que he visto tantos malos (o viejos) ejemplos de cifrado c # de stack overflow cortar y pegar en código fuente abierto, escribí un corto bit de cortar y pegar código de cifrado Ejemplos modernos de Cifrado Simétrico Autenticado de una cadena. que trato de mantener actualizado y revisado. Almacena el iv y salt con el texto cifrado también autentica el texto cifrado y los valores incluidos con el texto cifrado.

Idealmente, aunque una mejor práctica sería utilizar una biblioteca de cifrado de alto nivel que maneje las mejores prácticas como la iv para usted, sin embargo, normalmente no han existido para csharp. He estado trabajando en una versión nativa de csharp de la biblioteca de google keyczar. Si bien está funcionalmente listo para su uso, he querido tener más ojos en el código antes de la primera versión estable oficial.

 26
Author: jbtule,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-04 22:58:58

Sí, tanto el IV como el salt son valores públicos. Lo que es más importante es garantizar que estos sean valores aleatorios para cada operación de cifrado.

Para dar un ejemplo de esto en la naturaleza, echar un vistazo a la rncryptor formato de datos. Aquí el salt y IV se empaquetan en un formato de datos, junto con el texto cifrado y un valor MAC. (Nota: este es un ejemplo de objective-c).

 13
Author: Duncan Jones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-16 13:36:36