web-dev-qa-db-ja.com

パスフレーズを使用してRijndael KEYおよびIVを生成する方法

パスフレーズを使用してRijndael KEYおよびIVを生成する方法キーの長さは256ビットでなければなりません。

26
Predator

これは、インターネットで見つけたプラグアンドプレイコードです。それだけで動作します:

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

パスワードベースのキー派生を探していると思います。有る Rfc2898DeriveBytesそれを実装するクラス。

Rfc2898DeriveBytesは、パスワード、ソルト、および反復カウントを受け取り、GetBytesメソッドの呼び出しを通じてキーを生成します。

RFC 2898には、パスワードとソルトからキーと初期化ベクトル(IV)を作成する方法が含まれています。パスワードベースのキー派生関数であるPBKDF2を使用して、実質的に無制限の長さのキーを生成できる擬似ランダム関数を使用してキーを派生できます。 Rfc2898DeriveBytesクラスを使用して、ベースキーおよびその他のパラメーターから派生キーを生成できます。パスワードベースのキー派生関数では、ベースキーはパスワードであり、他のパラメーターはソルト値と反復カウントです。

PBKDF2の詳細については、RFC 2898「PKCS#5:Password-Based Cryptography Specification Version 2.0」を参照してください。

例:

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);
}

DeriveBytesだけでなく、任意の対称アルゴリズムでRijndaelを使用できます。
例:

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();
    }
}

使用法:

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);
    }
}

saltおよびiterationsパラメーターを必ず変更してください。

57
Alex Aza

IVはランダムである必要があります(予測不可能なランダムである必要はなく、再利用されない程度にランダムである必要があります)。

パスワードからキーを生成することに関しては、 キー派生関数 を探していますが、最近では少なくとも3つの適切な選択肢(PBKDF2、bcrypt、scrypt)があり、以前のように非反復ハッシュを使用していますポスターは、多くの場合、安全でないシステムにつながることを示唆しています。

また、AESとRijndaelを使用します。これはまったく同じものではありません。 AESの一部ではないRijndaelの組み合わせを使用することは、後で相互運用性の悪夢になる可能性があり、これらの機能の組み合わせのセキュリティはとにかくよく研究されていません。

9
Bruno Rohée

IVはランダムである必要があり(通常は暗号化されたデータと一緒に渡します)、キーはさまざまな方法で導出できます:パスワードをキーの長さ(パスワードが32文字より短い場合)にパディングするか、または(より信頼性が高い)SHA2ハッシュアルゴリズムを使用してキーを導出するか、より高度な方法を使用します。

これを使用します Rfc2898DeriveBytes Class

ただし、セキュリティレベルはパスフレーズの長さ/強度によって低下/制限されています。だから、それをしないでください。

2
user774411