web-dev-qa-db-fra.com

Comment générer des clés Rijndael et IV à l'aide d'une phrase secrète?

Comment générer Rijndael KEY et IV en utilisant un mot de passe? La longueur de clé doit être de 256 bits.

26
Predator

Il s'agit du code plug and play que j'ai trouvé sur Internet. Cela fonctionne:

using System.IO;
using System.Security.Cryptography;

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

public static byte[] Encrypt(byte[] plain, string password)
{
    MemoryStream memoryStream;
    CryptoStream cryptoStream;
    Rijndael rijndael = Rijndael.Create();
    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, SALT);
    rijndael.Key = pdb.GetBytes(32);
    rijndael.IV = pdb.GetBytes(16);
    memoryStream = new MemoryStream();
    cryptoStream = new CryptoStream(memoryStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write);
    cryptoStream.Write(plain, 0, plain.Length);
    cryptoStream.Close();
    return memoryStream.ToArray();
}

public static byte[] Decrypt(byte[] cipher, string password)
{
    MemoryStream memoryStream;
    CryptoStream cryptoStream;
    Rijndael rijndael = Rijndael.Create();
    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, SALT);
    rijndael.Key = pdb.GetBytes(32);
    rijndael.IV = pdb.GetBytes(16);
    memoryStream = new MemoryStream();
    cryptoStream = new CryptoStream(memoryStream, rijndael.CreateDecryptor(), CryptoStreamMode.Write);
    cryptoStream.Write(cipher, 0, cipher.Length);
    cryptoStream.Close();
    return memoryStream.ToArray();
}
37
Pan Pizza

Je pense que vous recherchez une dérivation de clé basée sur un mot de passe. Il y a Rfc2898DeriveBytes classe qui l'implémente.

Rfc2898DeriveBytes prend un mot de passe, un sel et un nombre d'itérations, puis génère des clés via des appels à la méthode GetBytes.

La RFC 2898 comprend des méthodes pour créer une clé et un vecteur d'initialisation (IV) à partir d'un mot de passe et d'un sel. Vous pouvez utiliser PBKDF2, une fonction de dérivation de clé basée sur un mot de passe, pour dériver des clés à l'aide d'une fonction pseudo-aléatoire qui permet de générer des clés de longueur pratiquement illimitée. La classe Rfc2898DeriveBytes peut être utilisée pour produire une clé dérivée à partir d'une clé de base et d'autres paramètres. Dans une fonction de dérivation de clé basée sur un mot de passe, la clé de base est un mot de passe et les autres paramètres sont une valeur de sel et un nombre d'itérations.

Pour plus d'informations sur PBKDF2, voir RFC 2898, "PKCS # 5: Password-Based Cryptography Specification Version 2.0,".

Exemple:

public static byte[] CreateKey(string password)
{
    var salt = new byte[] { 1, 2, 23, 234, 37, 48, 134, 63, 248, 4 };

    const int Iterations = 9872;
    using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, Iterations))
        return rfc2898DeriveBytes.GetBytes(32);
}

Vous pouvez utiliser DeriveBytes dans n'importe quel algorithme symétrique, pas seulement Rijndael.
Exemple:

public static SymmetricAlgorithm InitSymmetric(SymmetricAlgorithm algorithm, string password, int keyBitLength)
{
    var salt = new byte[] { 1, 2, 23, 234, 37, 48, 134, 63, 248, 4 };

    const int Iterations = 234;
    using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, Iterations))
    {
        if (!algorithm.ValidKeySize(keyBitLength))
            throw new InvalidOperationException("Invalid size key");

        algorithm.Key = rfc2898DeriveBytes.GetBytes(keyBitLength / 8);
        algorithm.IV = rfc2898DeriveBytes.GetBytes(algorithm.BlockSize / 8);
        return algorithm;
    }
}

private static byte[] Transform(byte[] bytes, Func<ICryptoTransform> selectCryptoTransform)
{
    using (var memoryStream = new MemoryStream())
    {
        using (var cryptoStream = new CryptoStream(memoryStream, selectCryptoTransform(), CryptoStreamMode.Write))
            cryptoStream.Write(bytes, 0, bytes.Length);
        return memoryStream.ToArray();
    }
}

Usage:

public static void Main()
{
    using (var rijndael = InitSymmetric(Rijndael.Create(), "TestPassword", 256))
    {
        var text = "Some text to encrypt";
        var bytes = Encoding.UTF8.GetBytes(text);

        var encryptedBytes = Transform(bytes, rijndael.CreateEncryptor);
        var decryptedBytes = Transform(encryptedBytes, rijndael.CreateDecryptor);

        var decryptedText = Encoding.UTF8.GetString(decryptedBytes);
        Debug.Assert(text == decryptedText);
    }
}

Assurez-vous de modifier les paramètres salt et iterations.

57
Alex Aza

L'IV doit être aléatoire (n'a pas besoin d'être aléatoire, juste assez aléatoire pour ne pas être réutilisé).

Quant à la génération de la clé à partir du mot de passe, vous recherchez une fonction de dérivation de clé pour laquelle il existe aujourd'hui au moins trois bons choix (PBKDF2, bcrypt, scrypt), en utilisant un hachage non itéré comme précédent affiche suggère le plus souvent conduit à des systèmes peu sûrs.

Utilisez également AES ni Rijndael, ce n'est pas exactement la même chose. L'utilisation d'une combinaison Rijndael ne faisant pas partie d'AES pourrait être un cauchemar d'interopérabilité plus tard, et la sécurité de cette combinaison de fonctions n'est pas bien étudiée de toute façon.

9
Bruno Rohée

IV doit être aléatoire (vous le transmettez généralement avec les données chiffrées), et la clé peut être dérivée de plusieurs façons: remplissez simplement le mot de passe de la longueur de la clé (si le mot de passe est inférieur à 32 caractères) ou ( qui est plus fiable) dériver une clé en utilisant l'algorithme de hachage SHA2 ou utiliser une manière plus sophistiquée.

Utilisez ceci classe Rfc2898DeriveBytes .

Un conseil cependant, votre niveau de sécurité a baissé/limité par la longueur/force de la phrase secrète. Alors ne le fais pas.

2
user774411