在 Java 中为 AES 生成随机 IV

我正在为 android 中的 PBE 实现和 AES 加密引擎,我找到了两种方法来实现 IV 的创建,我想知道哪种方法更好更安全地获取 IvParameterSpec:

I'm implementing and AES encryption engine for PBE in android, and I've found two ways to implement the creation of the IV and I would like to know which one is better and more secure for getting IvParameterSpec:

方法#1:

SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
byte[] iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);

IvParameterSpec ivParams = new IvParameterSpec(iv);

方法#2:

AlgorithmParameters params = cipher.getParameters();
byte[] iv2 = params.getParameterSpec(IvParameterSpec.class).getIV();

ivParams = new IvParameterSpec(iv2);

推荐答案

我会使用方法#1,因为 Java API 为 Cipher.init() 只接受加密/解密模式和密钥的API:

I'd use method #1, because the Java API specifies the following for the Cipher.init() API that just takes the encryption/decryption mode and key:

如果此密码实例需要指定密钥无法提供的任何算法参数或随机值,则此密码的底层实现应该生成所需的参数(使用其提供者 或 随机值).

If this cipher instance needs any algorithm parameters or random values that the specified key can not provide, the underlying implementation of this cipher is supposed to generate the required parameters (using its provider or random values).

(强调我的).

所以不清楚选择方法2时不同的提供者会做什么.查看 Android 源代码,似乎至少某些版本(包括版本 21?)将不会创建随机 IV - 随机 IV 创建似乎已被注释掉.

So it is not clear what different providers will do when method 2 is chosen. Looking at the Android source code, it seems that at least some versions (including version 21?) will not create a random IV - the random IV creation seems commented out.

方法 1 也更透明,而且 - 在我看来 - 对眼睛更容易.

Method 1 is also more transparent and it is - in my opinion - easier on the eyes.

请注意,通常最好使用 new SecureRandom() 并让系统找出最好的 RNG.SHA1PRNG" 定义不明确,可能因实现而异,并且已知存在实现弱点,尤其是在 Android 上.

Note that it is generally better to use new SecureRandom() and let the system figure out which RNG is best. "SHA1PRNG" is not well defined, may differ across implementations and is known to have had implementation weaknesses, especially on Android.

所以最终结果应该是这样的:

So the end result should be something like:

SecureRandom randomSecureRandom = new SecureRandom();
byte[] iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);

<小时>

请注意,GCM 模式最适合 12 字节 IV 而不是 16 字节 IV - AES 的块大小.


Beware that GCM mode works best with a 12 byte IV instead of the 16 byte IV - the block size of AES.

相关文章