如何为 AES/CTR/NoPadding 选择合适的 IV(初始化向量)? [英] How to pick an appropriate IV (Initialization Vector) for AES/CTR/NoPadding?

查看:95
本文介绍了如何为 AES/CTR/NoPadding 选择合适的 IV(初始化向量)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想加密由 web 应用程序编写的 cookie,我想将 cookie 的大小保持在最小,因此我选择了 AES/CTR/NoPadding.

I would like to encrypt the cookies that are written by a webapp and I would like to keep the size of the cookies to minimum, hence the reason I picked AES/CTR/NoPadding.

您建议将什么用作足够随机且仍保持应用无状态的 IV.我知道我可以生成一个随机 IV 并将其附加到消息中,但这会增加 cookie 的大小.

What would you recommend to use as IV that's random enough and still keep the app stateless. I know that I can just generate a random IV and append it to the message, but that will increase the size of the cookie.

另外,对于 128 位 AES,推荐的 IV 大小是多少?

In addition, what's the recommended size of IV for 128-bit AES?

其他人都是怎么做的?是否存在任何久经考验"的方法?我不想重新发明轮子.

How else is everyone doing this? Do any "tried and true" ways exist? I don't want to reinvent the wheel.

推荐答案

CTR 安全要求您永远使用相同的密钥对两个消息加密重复使用一个 IV.实际上它更严格:CTR 模式通过对计数器的连续值进行加密来工作(IV 只是该计数器的初始值),并且只有在相同的计数器值不被使用两次时才能实现适当的安全性;这意味着用 IV 加密一个值实际上消耗"了一系列连续的 IV 值,这些值不能与另一个加密重用.

CTR security requires that you never reuse an IV for two message encryptions with the same key. Actually it is even stricter: CTR mode works by encrypting successive values of a counter (the IV is just the initial value for that counter) and proper security is achieved only if the same counter value is not used twice; this means that encrypting a value with an IV actually "consumes" a sequence of successive IV values which must not be reused with another encryption.

做到这一点的简单方法是使用密码安全随机数生成器,并为每条消息创建一个新的 16 字节随机 IV.我强调密码安全",因为这很重要;一个基本的随机数发生器是不够的.对于 Java,请使用 java.util.SecureRandom.使用 Win32,调用 CryptGenRandom().通过随机选择,可能的 128 位 IV 的空间足够大,几乎不可能发生冲突.实际上,这就是 AES 使用 128 位块(因此意味着 128 位 IV)的原因.

The easy way to do that is to use a cryptographically secure random number generator, and create a new 16-byte random IV for every message. I underline "cryptographically secure" because that's important; a basic random number generator is not enough. With Java, use java.util.SecureRandom. With Win32, call CryptGenRandom(). With a random selection, the space of possible 128-bit IV is large enough that collisions are extremely improbable. Actually, that's why AES uses 128-bit blocks (thus implying 128-bit IV).

解密消息的实体必须知道 IV,因此您必须将其与加密消息一起存储.这是额外的 16 个字节.我知道这种开销是您想要避免的,尽管 16 字节对于 cookie 来说并不多.cookie 的有效最大长度取决于 Web 浏览器,但 4000 个字符似乎无处不在".一个 16 字节的 IV,当以字符编码(例如使用 Base64)时,将使用大约 22 个字符,即远小于最大 cookie 大小的 1%:也许你能负担得起?

The entity which will decrypt the message must know the IV, so you have to store it along with the encrypted message. That's an extra 16 bytes. I understand that this overhead is what you want to avoid, although 16 bytes is not that much for a cookie. The effective maximum length of a cookie depends on the Web browser but 4000 characters appear to work "everywhere". A 16-byte IV, when encoded in characters (e.g. with Base64), will use about 22 characters, i.e. much less than 1% of your maximum cookie size: maybe you can afford that ?

现在我们可以变得时髦并尝试通过诡计来减少 IV 长度:

Now we can get funky and try to reduce the IV length through trickery:

  • 使用散列函数生成 IV: 在服务器端,使用计数器,该计数器从 0 开始并在每次需要新的 IV 时递增.要获得 IV,您可以使用合适的散列函数对计数器进行散列,例如SHA-256,您保留哈希值的前 16 个字节.散列函数的随机化特性"将足以使 IV 在 CTR 要求方面具有足够的随机性.这需要加密安全的哈希函数,因此需要 SHA-256(避免 MD5).然后您只需将计数器值存储在 cookie 中,计数器将小于 16 个字节(例如,如果您的客户不超过 40 亿,计数器将适合 4 个字节).但是,有一个隐藏的成本:服务器(我想服务器正在您的系统中执行加密)必须确保它永远不会重用计数器值,因此它必须以持续存在的方式将当前计数器"存储在某处服务器重新启动,并且如果您扩展到多个前端也不会失败.这似乎并不容易.

  • Generate the IV with a hash function: server-side, use a counter, which begins at 0 and is incremented every time a new IV is needed. To get the IV, you hash the counter with a suitable hash function, e.g. SHA-256, and you keep the first 16 bytes of the hash value. The "randomization properties" of the hash function will be enough to make the IV sufficiently random with regards to CTR requirements. This needs a cryptographically secure hash function, hence SHA-256 (avoid MD5). You then just have to store the counter value in the cookie, and the counter will be shorter than 16 bytes (e.g. if you have no more than 4 billions customers, the counter will fit in 4 bytes). However, there is a hidden cost: the server (I suppose the server is performing the encryption in your system) must make sure that it never reuses a counter value, so it must store the "current counter" somewhere in a way which persists over server reboots, and also does not fail if you scale up to several front-ends. That's not as easy at is seems.

使用外部唯一值:可能,cookie 可能是上下文的一部分,该上下文提供足够的数据来生成每个加密唯一的值.例如,如果请求还包含(以明文形式)用户 ID",您可以使用该用户 ID 作为 IV 源.设置类似于上面的设置:您获取所有数据,将其填充到 SHA-256 中,SHA-256 输出的前 16 个字节就是您需要的 IV.这仅适用于给定加密消息的数据不会更改的情况,并且它确实是唯一的.这是一种罕见的情况:例如,用户 ID"只有在永远不需要为同一用户重新加密新消息的情况下才有用,并且如果用户 ID 永远不可能被重用(例如一个老用户退出,一个新用户来选择现在免费的用户 ID).

Use an external unique value: possibly, the cookie could be part of an context which provides enough data to generate a value which will be unique to each encryption. For instance, if the request also contains (in the clear) a "user ID", you could use the user ID as an IV source. The setup is similar to the one above: you get all that data, stuff it into SHA-256, and the first 16 bytes of SHA-256 output is the IV you need. This works only if that data does not change for a given encrypted message, and if it is really unique. This is a rare occurrence: for instance, a "user ID" is good for that only if there is never a need to reencrypt a new message for the same user, and if there is never a possibility that a user ID is reused (e.g. an old user quits, a new user comes and selects the now free user ID).

使用由加密安全 PRNG 生成的随机 16 字节 IV 仍然是安全"的方式,也是我推荐的方式.如果您发现 cookie 空间紧张,那么这意味着您正在接近 4 kB 的限制,此时您可能想要使用压缩(对数据加密前;加密后,压缩非常不太可能工作).使用 zlib(在 Java 中,您可以通过 java.util.zip 访问 zlib).

Using a random 16-byte IV generated with a cryptographically secure PRNG is still the "safe" way, and the one I recommend. If you find space tight in the cookie, then this means that you are approaching the 4 kB limit, at which point you may want to use compression (on the data before encryption; after encryption, compression is very very unlikely to work). Use zlib (in Java, you can access zlib through java.util.zip).

警告:在上述所有内容中,我并不是说任何关于 cookie 加密是否有助于提供您试图实现的任何安全特征.通常,当需要加密时,您实际上需要加密和完整性,然后您应该使用组合加密和完整性模式.查找 GCMCCM.此外,cookie 加密主要用于一个目的,即避免在服务器端存储一些用户特定数据的成本.如果您想为其他内容加密 cookie,例如验证一个有效用户,那么你就错了:加密不是正确的工具.

Warning: in all of the above, I am not saying anything about whether cookie encryption does help in providing whatever security characteristics you are trying to achieve. Usually, when encryption is needed, you actually need both encryption and integrity, and then you should use a combined-encryption-and-integrity mode. Lookup GCM and CCM. Moreover, cookie encryption is mostly good for one purpose, which is to avoid the cost of storing server-side a bit of user-specific data. If you want to encrypt a cookie for something else, e.g. to authenticate a valid user, then you are doing it wrong: encryption is not the right tool for that.

这篇关于如何为 AES/CTR/NoPadding 选择合适的 IV(初始化向量)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆