【问题标题】:generating AES 256 bit key value生成 AES 256 位密钥值
【发布时间】:2013-06-16 06:24:10
【问题描述】:

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

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

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

【问题讨论】:

  • “加密无法加盐,因为需要再次生成加密值”这就是为什么通常将加盐与散列密码一起存储的原因。这样,如果两个不同的用户有相同的密码,它会产生不同的哈希值,但对于单个用户,相同的密码总是会产生相同的哈希值。
  • 坦率地说,没有盐,它根本没有真正加密。应该不可能对加密值进行直接数据库查找。

标签: c# hash aes encryption-symmetric


【解决方案1】:

您可以使用任意大小的密码构造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);
}

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

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

【讨论】:

  • 请参阅我的解释以获得上述更多理论描述。请注意,Rfc2898DeriveBytes 实现了 PBKDF2 :)
  • 谢谢 - 这很有帮助。 keySize 是否应该为 32 才能获得 32 字节的密钥数组?
  • 是的,我想这是 ByteBlast 的一个错误。我还建议您使用 UTF-8 编码将密码编码为字节,因为 Rfc2898DeriveBytes 函数没有明确指定它使用的编码。当您从另一个运行时使用该函数时,这很棘手。
【解决方案2】:

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

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

【讨论】:

  • 查看 ByteBlasts 答案以了解上述实现:)
  • 谢谢 - 所以上述方法中的 32 字节数组是 256 位密钥?
  • 这是一个基于密码的密钥派生函数,这就是 PBKDF 的意思。你输入一个密码,你会得到一个密钥(作为字节)。它使用盐和多次迭代进行保护,这使得计算密钥相对困难(对您和攻击者而言)。不过,攻击者可能需要做很多事情才能获得密钥。但是,最好使用 SHA-256 或更高版本,因为它需要对超过一个哈希输出的任何内容进行全部迭代 - 这可能只会给您带来麻烦,而不是攻击者。
【解决方案3】:
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;
    }

【讨论】:

  • 这看起来更像是生成 随机 密钥的代码,而不是将密码字符串重复地转换为派生密钥。
  • 要从密码生成密钥,请看下面的回复
【解决方案4】:
 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 的剩余字符

【讨论】:

    【解决方案5】:

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

    【讨论】:

    • 正式哈希不是基于密码的密钥派生函数,不应该直接使用。
    【解决方案6】:

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

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

    【讨论】:

      猜你喜欢
      • 2017-02-12
      • 2017-06-07
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 2020-07-26
      • 1970-01-01
      • 2019-06-17
      相关资源
      最近更新 更多