是否可以从密码中获取初始化向量(与密钥一样),因为盐将是随机的?

时间:2020-12-11 18:25:59

Cryptography gurus please help.

密码大师请帮忙。

I've learned that encryption key with symmetric algorithms (e.g. AES) should be derived from password via the PBKDF2 function, using the random salt in each encryption. I've also learned that IV should not be hard-coded, or directly bound to (derived from) password string or encryption key. Until now I was generating both key derivation salt and IV randomly, 16 bytes each for my AES-256 encryption, and storing them along with encrypted payload.

我已经了解到,使用对称算法(例如AES)的加密密钥应该通过PBKDF2函数从密码派生,使用每个加密中的随机盐。我还了解到,IV不应该是硬编码的,也不应该直接绑定到(派生自)密码字符串或加密密钥。到目前为止,我随机生成密钥派生盐和IV,每个16字节用于我的AES-256加密,并将它们与加密的有效负载一起存储。

Now I'm thinking random-generation of IV is redundant, if I use random salt, as I can derive both key and IV from password string with that salt. Or maybe I shouldn't?

现在我认为随机生成IV是多余的,如果我使用随机盐,因为我可以从密码字符串中获取密钥和IV。或许我不应该?

So my question is ultimately this:

所以我的问题最终是:

Can I derive initialization vector from password (as I do with key), or should I generate random IV each time, given the fact that I use random salt in each encryption?

我可以从密码中获取初始化向量(就像我使用密钥一样),或者我应该每次都生成随机IV,因为我在每次加密时都使用随机盐吗?

So can I use the below C# code?

那么我可以使用下面的C#代码吗?

// Derive key and initialization vector from password:

// ---> NOTE: _salt is random 16 bytes in each encryption.

byte[] key, iv;

using (Rfc2898DeriveBytes derivedBytes = new Rfc2898DeriveBytes(password, _salt, _iterations))
{
    key = derivedBytes.GetBytes(32);
    iv = derivedBytes.GetBytes(16);
}

4 个解决方案

#1


3  

Yes you can use it that way, as long as you never ever use the same salt for the same password (even in time) to calculate the key and IV. The IV only has to be unique when you encrypt with the same key, and you would calculate a new key each time. In principle you could even use an all zero IV, as the key is never repeated, but you are better off using a derived one.

是的,你可以这样使用它,只要你从来没有使用相同的盐用于相同的密码(即使在时间上)来计算密钥和IV。当您使用相同的密钥加密时,IV只需要是唯一的,并且您每次都会计算一个新密钥。原则上你甚至可以使用全零IV,因为密钥永远不会重复,但你最好使用派生的密钥。

Note that if one of your colleagues decides that PasswordDeriveBytes - the broken implementation of PBKDF1 from Microsoft - would be better suited for the task, then you may very well be vulnerable to all kinds of attacks. This is just an example what can go wrong if your security margins are tight...

请注意,如果您的某位同事认定PasswordDeriveBytes(来自Microsoft的PBKDF1的破坏实施)更适合该任务,那么您很可能容易受到各种攻击。这只是一个例子,如果您的安全边际紧张,可能会出错...

Fully random IV's should certainly be preferred.

完全随机的IV应该是首选。

#2


0  

What do you mean " using the random salt in each encryption"? It is best to derive the salt and IV randomly, such as the output from a cryptography standard random number generator and store it with the derived bytes. Generate a new IV and salt for each password.

你是什​​么意思“在每次加密中使用随机盐”?最好随机导出salt和IV,例如加密标准随机数生成器的输出,并将其与派生字节一起存储。为每个密码生成一个新的IV和salt。

Why from a cryptography standard RNG? Deriving from the password means any weakness in the derive bytes function is reflected in both the bytes and the IV. It is not difficult in modern programming languages to generate it from a RNG and using a RNG ensures the IV for new passwords encrypted is not predictable. There are probably better reasons but I am drawing a blank.

为什么使用加密标准RNG?从密码派生意味着派生字节函数中的任何弱点都反映在字节和IV中。在现代编程语言中从RNG生成它并使用RNG并不难确保加密的新密码的IV是不可预测的。可能有更好的理由,但我画了一个空白。

#3


0  

The more links there are between different parts of any crypto system then the easier it will be for any attacker to use those links as a back door from one part of the system to another. Remember that the IV is sent in the clear while the key must be kept secret, so any sort of link between them is a huge risk to take.

任何加密系统的不同部分之间的链接越多,那么任何攻击者就越容易将这些链接用作从系统的一个部分到另一个部分的后门。请记住,IV是以明文发送的,而密钥必须保密,因此它们之间的任何类型的链接都是一个巨大的风险。

Use Rfc2898DeriveBytes to generate your key and use a good crypto RNG to generate the IV. Remember that the attacker will see the IV so there is no need to go through the full RFC 2898 process. Use the standard crypto RNG for the IV that will probably be faster than the RFC 2898 process because it does not have the iterations.

使用Rfc2898DeriveBytes生成密钥并使用一个好的加密RNG来生成IV。请记住,攻击者将看到IV,因此无需完成整个RFC 2898流程。使用标准加密RNG进行IV可能比RFC 2898进程更快,因为它没有迭代。

#4


0  

The most important part of semantic security for the initialization vector when using AES-CBC is that it should not be predictable.

使用AES-CBC时初始化向量的语义安全性最重要的部分是它不应该是可预测的。

With your suggested implementation a given key will always have the same initialization vector, but you wouldn't be using the same keys because of your 128 bit salt. Seems pretty unpredictable, that said, it's not a best practice, and generally when you do something clever to save 16 bytes of space your are losing some security of some sort or opening yourself up to some unknown attack vector.

根据您建议的实现,给定的密钥将始终具有相同的初始化向量,但由于您的128位盐,您将不会使用相同的密钥。似乎非常不可预测,这说,这不是一个最佳实践,通常当你做一些聪明的事情来节省16个字节的空间时,你会失去一些某种安全性或者让自己打开一些未知的攻击向量。

I think you should use RNG and take the space 16 byte hit, being conservative is the name of the game when dealing with encryption. There are other things such as authenticated encryption that you should probably look into as well, I have an example implementation on codereview.

我认为你应该使用RNG并占用空格16字节,保守是处理加密时游戏的名称。还有一些其他的东西,比如你应该考虑的经过身份验证的加密,我在codereview上有一个示例实现。

Ultimately there are other things that are important that provide additional overhead beyond the iv for security such as authenticated encryption, versioning, and keyrotation, and there really haven't been any high level encryption frameworks for C#. I've been working a C# implemenation of Google's Keyczar framework. You can follow it, if you like, on github Keyczar-dotnet. It's pretty much feature complete, and has 90% test coverage, but conservatively, I wouldn't recommend using it until it gets officially accepted as part of the project, and then will likely have a larger group of eyes on it in the future.

最终还有其他一些重要的事情,除了安全性之外,还提供额外的开销,例如经过身份验证的加密,版本控制和密钥旋转,并且C#确实没有任何高级加密框架。我一直在研究Google的Keyczar框架的C#实现。如果你愿意,你可以在github Keyczar-dotnet上关注它。它的功能非常齐全,并且有90%的测试覆盖率,但保守地说,我不建议在它被正式接受为项目的一部分之前使用它,然后将来可能会有更多的眼睛。

#1


3  

Yes you can use it that way, as long as you never ever use the same salt for the same password (even in time) to calculate the key and IV. The IV only has to be unique when you encrypt with the same key, and you would calculate a new key each time. In principle you could even use an all zero IV, as the key is never repeated, but you are better off using a derived one.

是的,你可以这样使用它,只要你从来没有使用相同的盐用于相同的密码(即使在时间上)来计算密钥和IV。当您使用相同的密钥加密时,IV只需要是唯一的,并且您每次都会计算一个新密钥。原则上你甚至可以使用全零IV,因为密钥永远不会重复,但你最好使用派生的密钥。

Note that if one of your colleagues decides that PasswordDeriveBytes - the broken implementation of PBKDF1 from Microsoft - would be better suited for the task, then you may very well be vulnerable to all kinds of attacks. This is just an example what can go wrong if your security margins are tight...

请注意,如果您的某位同事认定PasswordDeriveBytes(来自Microsoft的PBKDF1的破坏实施)更适合该任务,那么您很可能容易受到各种攻击。这只是一个例子,如果您的安全边际紧张,可能会出错...

Fully random IV's should certainly be preferred.

完全随机的IV应该是首选。

#2


0  

What do you mean " using the random salt in each encryption"? It is best to derive the salt and IV randomly, such as the output from a cryptography standard random number generator and store it with the derived bytes. Generate a new IV and salt for each password.

你是什​​么意思“在每次加密中使用随机盐”?最好随机导出salt和IV,例如加密标准随机数生成器的输出,并将其与派生字节一起存储。为每个密码生成一个新的IV和salt。

Why from a cryptography standard RNG? Deriving from the password means any weakness in the derive bytes function is reflected in both the bytes and the IV. It is not difficult in modern programming languages to generate it from a RNG and using a RNG ensures the IV for new passwords encrypted is not predictable. There are probably better reasons but I am drawing a blank.

为什么使用加密标准RNG?从密码派生意味着派生字节函数中的任何弱点都反映在字节和IV中。在现代编程语言中从RNG生成它并使用RNG并不难确保加密的新密码的IV是不可预测的。可能有更好的理由,但我画了一个空白。

#3


0  

The more links there are between different parts of any crypto system then the easier it will be for any attacker to use those links as a back door from one part of the system to another. Remember that the IV is sent in the clear while the key must be kept secret, so any sort of link between them is a huge risk to take.

任何加密系统的不同部分之间的链接越多,那么任何攻击者就越容易将这些链接用作从系统的一个部分到另一个部分的后门。请记住,IV是以明文发送的,而密钥必须保密,因此它们之间的任何类型的链接都是一个巨大的风险。

Use Rfc2898DeriveBytes to generate your key and use a good crypto RNG to generate the IV. Remember that the attacker will see the IV so there is no need to go through the full RFC 2898 process. Use the standard crypto RNG for the IV that will probably be faster than the RFC 2898 process because it does not have the iterations.

使用Rfc2898DeriveBytes生成密钥并使用一个好的加密RNG来生成IV。请记住,攻击者将看到IV,因此无需完成整个RFC 2898流程。使用标准加密RNG进行IV可能比RFC 2898进程更快,因为它没有迭代。

#4


0  

The most important part of semantic security for the initialization vector when using AES-CBC is that it should not be predictable.

使用AES-CBC时初始化向量的语义安全性最重要的部分是它不应该是可预测的。

With your suggested implementation a given key will always have the same initialization vector, but you wouldn't be using the same keys because of your 128 bit salt. Seems pretty unpredictable, that said, it's not a best practice, and generally when you do something clever to save 16 bytes of space your are losing some security of some sort or opening yourself up to some unknown attack vector.

根据您建议的实现,给定的密钥将始终具有相同的初始化向量,但由于您的128位盐,您将不会使用相同的密钥。似乎非常不可预测,这说,这不是一个最佳实践,通常当你做一些聪明的事情来节省16个字节的空间时,你会失去一些某种安全性或者让自己打开一些未知的攻击向量。

I think you should use RNG and take the space 16 byte hit, being conservative is the name of the game when dealing with encryption. There are other things such as authenticated encryption that you should probably look into as well, I have an example implementation on codereview.

我认为你应该使用RNG并占用空格16字节,保守是处理加密时游戏的名称。还有一些其他的东西,比如你应该考虑的经过身份验证的加密,我在codereview上有一个示例实现。

Ultimately there are other things that are important that provide additional overhead beyond the iv for security such as authenticated encryption, versioning, and keyrotation, and there really haven't been any high level encryption frameworks for C#. I've been working a C# implemenation of Google's Keyczar framework. You can follow it, if you like, on github Keyczar-dotnet. It's pretty much feature complete, and has 90% test coverage, but conservatively, I wouldn't recommend using it until it gets officially accepted as part of the project, and then will likely have a larger group of eyes on it in the future.

最终还有其他一些重要的事情,除了安全性之外,还提供额外的开销,例如经过身份验证的加密,版本控制和密钥旋转,并且C#确实没有任何高级加密框架。我一直在研究Google的Keyczar框架的C#实现。如果你愿意,你可以在github Keyczar-dotnet上关注它。它的功能非常齐全,并且有90%的测试覆盖率,但保守地说,我不建议在它被正式接受为项目的一部分之前使用它,然后将来可能会有更多的眼睛。