创建 AES 密钥比播种 SecureRandom 更好的方法
Posted
技术标签:
【中文标题】创建 AES 密钥比播种 SecureRandom 更好的方法【英文标题】:Better way to create AES keys than seeding SecureRandom 【发布时间】:2014-07-30 05:14:32 【问题描述】:我需要将加密数据从Java
客户端发送到C#
服务器。现在我正在学习如何使用AES
(要求)加密数据。按照这个公认的答案android encryption/decryption with AES 我正在做以下事情:
byte[] keyStart = "qweroiwejrwoejlsifeoisrn".getBytes(); // Random character string
byte[] toEncrypt = myMessageString.getBytes();
keyGen = KeyGenerator.getInstance("AES");
sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(keyStart);
keyGen.init(128, sr);
SecretKey secretKey = keyGen.generateKey();
byte[] secretKeyByte = secretKey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(secretKeyByte, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
cipher.doFinal(toEncrypt);
由于算法使用SecureRandom
使用keyStart
,我不确定这是否可以在C#
甚至另一个Java
程序中解码,而无需SecureRandom
。
这种加密/解密是否只知道keyStart
的值,或者因为我使用SecureRandom
我仍然需要传递其他东西才能解密?
另外,有没有更好的方法,或者这个就可以了?
【问题讨论】:
【参考方案1】:不,您应该使用 SecureRandom
从静态数据派生密钥的整个想法相当糟糕:
SecureRandom
的主要功能是生成随机值,不应该用作密钥流的生成器;
SecureRandom
,当用 "SHA1PRNG"
实例化时,没有实现定义明确的算法,而且实际上已知算法会发生变化,即使从一个 Sun JDK 到另一个;
Oracle 提供的"SHA1PRNG"
实现将初始种子仅用作种子,其他人可能只是将种子添加到随机池中。
已知使用"SHA1PRNG"
作为密钥派生函数会在多个 Android 版本上产生问题,并且可能会在任何其他 Java RE 上失败。
那么你应该怎么做呢?
-
使用
new SecureRandom()
甚至更好的KeyGenerator
来生成真正的随机密钥,如果您需要全新的随机密钥,则无需播种随机数生成器;
直接将已知密钥的byte[]
提供给SecretKeySpec
,或使用十六进制解码器将其解码为十六进制(注意String
实例很难从内存中删除,因此只有在没有其他方式);
如果您想从密码创建密钥,请使用 PBKDF2(但使用比链接中提供的迭代次数更高的迭代次数);
如果您想从一个密钥种子创建多个密钥,请使用真正的基于密钥的密钥派生机制,例如使用 HKDF(见下文)。
如果种子是由例如生成的,选项 4 将是首选。密钥协商算法,例如 Diffie-Hellman 或 ECDH。
请注意,对于选项 3,PBKDF2,您最好只使用 ASCII 密码。这是因为 Oracle 的 PBKDF2 实现不使用 UTF-8 编码。
至于选项 4,我已帮助将所有好的 KBKDF 添加到 Bouncy Castle libraries,因此如果您可以将 Bouncy Castle 添加到您的类路径和/或已安装安全性列表,则无需自己实现 KBKDF提供者。目前最好的 KBKDF 可能是 HKDF。如果您无法将 Bouncy Castle 添加到您的类路径中,那么您可能希望在派生数据上使用 SHA-256 输出的最左边字节作为“穷人的”KDF。
【讨论】:
以上是关于创建 AES 密钥比播种 SecureRandom 更好的方法的主要内容,如果未能解决你的问题,请参考以下文章
JOSEException:无法创建 AES/GCM/NoPadding 密码:非法密钥大小
关于 java中的SecureRandom在linux中每次生成不同结果
SecureRandom 提供程序“Crypto”在 Android N 中无法确定性地生成密钥