C# 生成 AES 256 位密钥值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17195969/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 08:48:15  来源:igfitidea点击:

generating AES 256 bit key value

c#hashaesencryption-symmetric

提问by bhs

Does anyone know of a way to get a 256 bit key value generated from a pass phrase of any length? The encryption cannot be salted as the encrypted values need to be generated again and compared in the database. So a value must generate the same encrypted string each time it is encrypted.

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

Currently I'm using a 32 char key working on the possibly incorrect assumption this is 256 bits?

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

So, I would want 'the quick brown fox' to be converted to a suitable AES 256 bit key?

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

采纳答案by User 12345678

You can construct the Rfc2898DeriveBytes Classwith an arbitrary sized password and then derive a key of your desired size in this case, 256 bits (32 bytes):

您可以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);
}

In order to produce a deterministic output (i.e. same input will produce the same output) you will need to hard-code the salt. The salt must be at least 8 bytes:

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

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

回答by alex

You can use some hash function that provides 256 bit outuput from input of any length, for example SHA256.

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

回答by Maarten Bodewes

Probably the best way is to use PBKDF2 using SHA256 (which will generate 256 bit output) and a application specific salt & iteration count. You should be aware that using an application specific salt removed quite a lot of the protection from PBKDF2, so you may require additional protection to alleviate this issue. One method would be to make sure that the database is safe, and that a maximum amount of tries can be used.

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

You are correct in stipulating that a 32 char passphrase is not a 256 bit key. It does not contain enough entropy, and some bytes may not even have valid character representations.

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

回答by Minute V

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

回答by Minute V

 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;

    }

//Get the first 44 charaters for the AES Key and the remaining chars for AES IV

//获取AES Key的前44个字符和AES IV的剩余字符

回答by David Jones

My version. I just wanted keys without a password.

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

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