生成 AES 256 位密钥值

本文关键字:密钥 AES 生成 | 更新日期: 2023-09-27 18:19:00

有谁知道从任何长度的密码短语生成的 256 位密钥值的方法?加密不能加盐,因为加密值需要再次生成并在数据库中进行比较。因此,值每次加密时都必须生成相同的加密字符串。

目前我正在使用 32 个字符的密钥,可能不正确的假设是 256 位?

那么,我希望将"快速棕色狐狸"转换为合适的AES 256位密钥?

生成 AES 256 位密钥值

您可以使用

任意大小的密码构造Rfc2898DeriveBytes Class,然后派生所需大小的密钥,在这种情况下,256位(32字节(:

private static byte[] CreateKey(string password, int keyBytes = 32)
{
    const int Iterations = 300;
    var keyGenerator = new Rfc2898DeriveBytes(password, Salt, Iterations);
    return keyGenerator.GetBytes(keyBytes);
}

为了产生确定性输出(即相同的输入将产生相同的输出(,您需要对盐进行硬编码。盐必须至少为 8 个字节:

private static readonly byte[] Salt = 
    new byte[] { 10, 20, 30 , 40, 50, 60, 70, 80};

可能最好的方法是使用 SHA256(将生成 256 位输出(和特定于应用程序的 salt 和迭代计数的 PBKDF2。您应该知道,使用特定于应用程序的盐会从 PBKDF2 中删除很多保护,因此您可能需要额外的保护来缓解此问题。一种方法是确保数据库是安全的,并且可以使用最大尝试次数。

您规定 32 个字符的密码短语不是 256 位密钥是正确的。它不包含足够的熵,某些字节甚至可能没有有效的字符表示形式。

public static string GenerateBitKey(int letterCount = 44)
    {
        // Get the number of words and letters per word.
        int num_letters = letterCount;
        // Make an array of the letters we will use.
        char[] letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
        // Make a random number generator.
        Random rand = new Random();
        // Make the words.
        // Make a word.
        string word = "";
        for (int j = 1; j <= num_letters; j++)
        {
            // Pick a random number between 0 and 25
            // to select a letter from the letters array.
            int letter_num = rand.Next(0, letters.Length - 1);
            // Append the letter.
            word += letters[letter_num];
        }
        return word;
    }
 private static IBuffer GetMD5Hash(string key)
    {
        IBuffer bufferUTF8Msg = CryptographicBuffer.ConvertStringToBinary(key, BinaryStringEncoding.Utf8);
        HashAlgorithmProvider hashAlgorithmProvider = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Md5);
        IBuffer hashBuffer = hashAlgorithmProvider.HashData(bufferUTF8Msg);
        if (hashBuffer.Length != hashAlgorithmProvider.HashLength)
        {
            throw new Exception("There was an error creating the hash");
        }
        return hashBuffer;
    }
    #region Static
    public static string GenerateKey(string password, int resultKeyLength = 68)
    {
        if (password.Length < 6)
            throw new ArgumentException("password length must atleast 6 characters or above");
        string key = "";
        var hashKey = GetMD5Hash(password);
        var decryptBuffer = CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8);
        var AES = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesEcbPkcs7);
        var symmetricKey = AES.CreateSymmetricKey(hashKey);
        var encryptedBuffer = CryptographicEngine.Encrypt(symmetricKey, decryptBuffer, null);
        key = CryptographicBuffer.EncodeToBase64String(encryptedBuffer);
        string cleanKey  = key.Trim(new char[] { ' ', ''r', ''t', ''n', '/', '+', '=' });
        cleanKey = cleanKey.Replace("/", string.Empty).Replace("+", string.Empty).Replace("=", string.Empty);
        key = cleanKey;
        if(key.Length > resultKeyLength)
        {
           key = key.Substring(0, Math.Min(key.Length, resultKeyLength));
        }
        else if(key.Length == resultKeyLength)
        {
            return key;
        }
        else if (key.Length < resultKeyLength)
        {
            key = GenerateKey(key);
        }
        return key;
    }

获取 AES 密钥的前 44 个字符和 AES IV 的剩余字符

您可以使用一些哈希函数,从任何长度的输入提供 256 位输出,例如 SHA256。

我的版本。我只想要没有密码的密钥。

    public static string GenerateBitKey(int letterCount = 44)
    {
        // Get the number of words and letters per word.
        int num_letters = letterCount;
        // Make an array of the letters we will use.
        char[] letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrsruvwxyz+".ToCharArray();
        int lettersLength =  letters.Length;
        // Make a word.
        string word = "";
        //Use Cryptography to generate random numbers rather than Psuedo Random Rand
        // Deliberate overkill here
        byte[] randomBytes = new byte[num_letters*256];

        List<int> rands = new List<int>();
        do
        {
            using (System.Security.Cryptography.RNGCryptoServiceProvider rngCsp = new
                        System.Security.Cryptography.RNGCryptoServiceProvider())
            {
                // Fill the array with a random value.
                rngCsp.GetBytes(randomBytes);
            }

            // Truncate the set of random bytes to being in range 0 .. (lettersLength-1)
            // Nb Using mod of randomBytes will reduce entropy of the set
            foreach (var x in randomBytes)
            {
                if (x < lettersLength)
                    rands.Add((int)x);
                if (rands.Count()==num_letters)
                     break;
            }
        }
        while (rands.Count < letterCount);

        int[] randsArray = rands.ToArray();
        // Get random selection of characters from letters
        for (int j = 0; j < num_letters; j++)
        {
            int letter_num = randsArray[j];
            // Append the letter.
            word += letters[letter_num];
        }
        return word;
    }