【问题标题】:Why to create a derived password of 256 bytes and later get bytes from result?为什么要创建 256 字节的派生密码,然后从结果中获取字节?
【发布时间】:2019-01-01 11:04:43
【问题描述】:

我找到了一个使用 AES 加密来加密文本的示例。代码是这样的:

public static string Encrypt(string PlainText, string Password,
    string Salt = "Kosher", string HashAlgorithm = "SHA1",   
    int PasswordIterations = 2, string InitialVector = "OFRna73m*aze01xY",    
    int KeySize = 256)    
{    
    if (string.IsNullOrEmpty(PlainText))    
        return "";

    byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);    
    byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);    
    byte[] PlainTextBytes = Encoding.UTF8.GetBytes(PlainText);    
    PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);    
    byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);    
    RijndaelManaged SymmetricKey = new RijndaelManaged();    
    SymmetricKey.Mode = CipherMode.CBC;    
    byte[] CipherTextBytes = null;    
    using (ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes))    
    {    
        using (MemoryStream MemStream = new MemoryStream())    
        {    
            using (CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write))    
            {    
                CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);    
                CryptoStream.FlushFinalBlock();    
                CipherTextBytes = MemStream.ToArray();    
                MemStream.Close();    
                CryptoStream.Close();    
            }    
        }    
    }

    SymmetricKey.Clear();    
    return Convert.ToBase64String(CipherTextBytes);
}

我的问题是:AES 算法的密钥是如何生成的?这两行:

    PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);

    byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);

首先,它创建一个 256 字节的派生密钥,然后,创建一个获取该派生密钥的伪随机字节的密钥。它必须除以 8,因为 AES 算法需要 128、182 或 256 位,而不是字节。在这种情况下,如何派生密钥是 256 字节,AES 的密钥将是 256 位。

但它为什么要这样做呢?创建具有所需长度而不是 256 字节而是 256 位(256 字节 / 8)的派生密钥不是更好吗?因此不需要使用派生密钥的 1/8 字节创建新密钥。

另外,getBytes() 方法,在该方法的描述中,它说它返回伪随机密钥字节。那么在每种情况下,AES密钥不是不同吗?如果是伪随机密钥字节,如何从解密中再次生成 AES 密钥?

谢谢。

【问题讨论】:

  • 我不清楚你在问什么。它使用它获得的所有信息创建PasswordDerivedBytes,然后要求从该信息生成KeySize / 8 字节。大概KeySize 是以位为单位的,但PasswordDerivedBytes.GetBytes 是以字节为单位的。 (很多代码都是非常规的,特别是在参数/变量名称方面,这无济于事 - 您可能想找到另一个示例。)
  • 注意:你应该使用Rfc2898DeriveBytes,因为PasswordDeriveBytes已经过时了。

标签: c# aes


【解决方案1】:

首先,它创建一个 256 字节的派生密钥

在哪里?我没有看到任何 256 字节的密钥被创建。

然后,创建一个获取此派生密钥的伪随机字节的密钥。它必须除以 8,因为 AES 算法需要 128、182 或 256 位,而不是字节

是的,KeySize 的函数输入(按照正常的 C# 命名约定应该是 keySize)以位为单位,但GetBytes 需要以字节为单位的输入。 x / 8 是该转换的三个正确答案之一((x + 7) / 8 是另一个,x & 7 == 0 ? x / 8 : throw new ArgumentException(nameof(x)) 是第三个)

但它为什么要这样做呢?创建具有所需长度而不是 256 字节而是 256 位(256 字节 / 8)的派生密钥不是更好吗?因此不需要使用派生密钥的 1/8 字节创建新密钥。

这样做会很好。但既然它已经这样做了,那就没有“更好”了。

另外,getBytes() 方法,在该方法的描述中,它说它返回伪随机密钥字节。那么在每种情况下,AES 密钥是否会有所不同?如果是伪随机密钥字节,如何从解密中再次生成 AES 密钥?

我必须提出一个迂腐的观点:没有getBytes 方法。 C#是区分大小写的语言,方法名是GetBytes

pseudorandom:注意或属于通过确定的计算过程生成的随机数以满足统计测试。

PasswordDeriveBytesPBKDF1 的实现(除非它继续超出 PBKDF1 的限​​制),这是一种确定性算法。给定相同的输入(密码、种子、迭代计数、伪随机函数(散列算法)),会产生相同的输出。稍微改变任何一个输入,输出就会有很大的不同。

Rfc2898DeriveBytesPBKDF2 的实现)也是一种确定性但混乱的算法。

因此,通过提供所有相同的输入,您可以在其中任何一个(但不是在它们之间)再次产生相同的答案。

当使用基于密码的加密 (PKCS#5) 时,流程是

  • 选择 PRF
  • 选择迭代次数
  • 生成随机盐
  • 写下这些选择
  • 应用这三样东西,加上密码生成密钥
  • 加密数据
  • 记下加密数据

解密时

  • 阅读 PRF
  • 读取迭代次数
  • 读盐
  • 应用这三样东西,加上密码生成密钥
  • 读取加密数据
  • 解密
  • 派对开始

虽然这段代码正确地完成了该部分,但 IV 和 Salt 不应该是 ASCII(或 UTF8)字符串,它们应该是“只是字节”(byte[])。如果它们需要作为字符串传输,那么它们应该是 base64 或其他一些“任意”binary-to-text encoding

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-28
    • 1970-01-01
    • 2020-08-25
    • 2015-01-19
    • 1970-01-01
    • 1970-01-01
    • 2013-02-18
    相关资源
    最近更新 更多