对 Key 和 IV 使用相同值的缺点?
Downsides to Using the Same Value for Key and IV?
我正在为 .NET 实现一些 类,它(除其他外)简化了加密和解密。
我当前的算法创建了一个 8 字节的盐,并使用该盐和密码生成密钥和 IV。然后我将未加密的盐与我的加密数据一起存储。
这很好,因为盐似乎总是 8 个字节,这是它添加到我的加密数据中的所有开销。但是,对我的密钥和 IV 使用相同的值有什么缺点吗?有没有更好的方法?
相关代码:
SymmetricAlgorithm algorithm = CreateAlgorithm();
byte[] salt = CreateSalt();
byte[] keyBytes = DeriveBytes(salt, algorithm.KeySize >> 3);
byte[] ivBytes = DeriveBytes(salt, algorithm.BlockSize >> 3);
支持代码:
private static readonly int SaltLength = 8;
internal byte[] CreateSalt()
{
byte[] salt = new byte[SaltLength];
using (RNGCryptoServiceProvider generator = new RNGCryptoServiceProvider())
{
generator.GetBytes(salt);
}
return salt;
}
public byte[] DeriveBytes(byte[] salt, int bytes)
{
Rfc2898DeriveBytes derivedBytes = new Rfc2898DeriveBytes(Password, salt, 1000);
return derivedBytes.GetBytes(bytes);
}
是的,它违背了 IV 的目的。使用 IV 因此,如果您使用相同的密钥加密相同的消息,您将不会获得相同的密文。您也可以只使用常量值 0
,它增加了相同的安全性。
在您的例子中,您为
使用了相同的值
- 密钥
- 四
从概念上讲,这是一个坏主意,因为 IV 应该是非机密的,并且每次加密都不同。您已经解决了 "different for each encryption",但您的密钥与您的密钥相同。
您要防御的是确保使用相同密钥的两次加密不会给出相同的密文。在您的情况下,只有当 RNG 生成两个相同的 128 位 AES 密钥时才会发生这种情况。
虽然这种可能性很低,但你不应该拥有它。
好的,只要你为每条消息使用一个新的、随机创建的盐,你就接近我可能做的了。随机盐意味着 IV 将随着每条新消息而变化,这意味着完全相同的消息每次传输将是不同的加密文本。都好。如果我是你,我会改变的一件事是不使用 DeriveBytes 获取密钥然后获取 IV,我会让 DeriveBytes 给出一组字节的密钥和 IV 的大小,然后拆分它们并使用它们分别地。 IV 不应该对任何人保密。关键一定是。因此,如果您从相同的 salt 和密码中 DeriveBytes 一次,然后将这些字节拆分为密钥和 IV,攻击者在查看 IV 后仍然比以前更了解密钥。
或者,您可以使用随机数在 IV 字节和密钥字节之间创建已知排列。例如,请原谅我的伪代码:
IV = DeriveBytes(salt + password + "IV")
key = DeriveBytes(salt + password + "key")
任何一种方式都是安全的。但是我只会 DeriveBytes,比如 32 个字节,然后将其中的 16 个用于 IV,将其中的 16 个用于密钥。前 16 个字节中没有任何信息可以帮助攻击者计算接下来的 16 个字节。
我正在为 .NET 实现一些 类,它(除其他外)简化了加密和解密。
我当前的算法创建了一个 8 字节的盐,并使用该盐和密码生成密钥和 IV。然后我将未加密的盐与我的加密数据一起存储。
这很好,因为盐似乎总是 8 个字节,这是它添加到我的加密数据中的所有开销。但是,对我的密钥和 IV 使用相同的值有什么缺点吗?有没有更好的方法?
相关代码:
SymmetricAlgorithm algorithm = CreateAlgorithm();
byte[] salt = CreateSalt();
byte[] keyBytes = DeriveBytes(salt, algorithm.KeySize >> 3);
byte[] ivBytes = DeriveBytes(salt, algorithm.BlockSize >> 3);
支持代码:
private static readonly int SaltLength = 8;
internal byte[] CreateSalt()
{
byte[] salt = new byte[SaltLength];
using (RNGCryptoServiceProvider generator = new RNGCryptoServiceProvider())
{
generator.GetBytes(salt);
}
return salt;
}
public byte[] DeriveBytes(byte[] salt, int bytes)
{
Rfc2898DeriveBytes derivedBytes = new Rfc2898DeriveBytes(Password, salt, 1000);
return derivedBytes.GetBytes(bytes);
}
是的,它违背了 IV 的目的。使用 IV 因此,如果您使用相同的密钥加密相同的消息,您将不会获得相同的密文。您也可以只使用常量值 0
,它增加了相同的安全性。
在您的例子中,您为
使用了相同的值- 密钥
- 四
从概念上讲,这是一个坏主意,因为 IV 应该是非机密的,并且每次加密都不同。您已经解决了 "different for each encryption",但您的密钥与您的密钥相同。
您要防御的是确保使用相同密钥的两次加密不会给出相同的密文。在您的情况下,只有当 RNG 生成两个相同的 128 位 AES 密钥时才会发生这种情况。
虽然这种可能性很低,但你不应该拥有它。
好的,只要你为每条消息使用一个新的、随机创建的盐,你就接近我可能做的了。随机盐意味着 IV 将随着每条新消息而变化,这意味着完全相同的消息每次传输将是不同的加密文本。都好。如果我是你,我会改变的一件事是不使用 DeriveBytes 获取密钥然后获取 IV,我会让 DeriveBytes 给出一组字节的密钥和 IV 的大小,然后拆分它们并使用它们分别地。 IV 不应该对任何人保密。关键一定是。因此,如果您从相同的 salt 和密码中 DeriveBytes 一次,然后将这些字节拆分为密钥和 IV,攻击者在查看 IV 后仍然比以前更了解密钥。
或者,您可以使用随机数在 IV 字节和密钥字节之间创建已知排列。例如,请原谅我的伪代码:
IV = DeriveBytes(salt + password + "IV")
key = DeriveBytes(salt + password + "key")
任何一种方式都是安全的。但是我只会 DeriveBytes,比如 32 个字节,然后将其中的 16 个用于 IV,将其中的 16 个用于密钥。前 16 个字节中没有任何信息可以帮助攻击者计算接下来的 16 个字节。