更好的方式来创建AES密钥,比种子SecureRandom [英] Better way to create AES keys than seeding SecureRandom
问题描述
我需要从 Java
客户端向 C#
服务器发送加密数据。现在我正在学习如何使用 AES
(需求)加密数据。遵循此接受答案使用AES加密/解密AES 我执行以下操作: / p>
I need to send encrypted data from a Java
client to a C#
server. Right now I'm learning how to encrypt data using AES
(requirement). Following this accepted answer android encryption/decryption with AES I'm doing the following:
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#
或甚至在另一个 / code>程序,没有
SecureRandom
。
Since the algorithm uses a SecureRandom
using the keyStart
I am not sure if this can be decoded in C#
or even in another Java
program, without the SecureRandom
.
这个加密/解密工作只需知道 keyStart
的价值,或者因为我使用 SecureRandom
我还需要传递别的东西为了解密?
Will this encryption/decryption work with just knowing the value of keyStart
or since I'm using SecureRandom
I still need to pass something else in order to decrypt?
此外,有没有更好的方法,或者这是一个很好吗?
Also, is there a better way to do it or is this one just fine?
推荐答案
不,你应该使用 SecureRandom
从静态数据的密钥导出的整个想法是不好的:
No, the whole idea that you should use a SecureRandom
for key derivation from static data is rather bad:
-
SecureRandom
的主要功能是生成随机值,不应该用作密钥流的生成器; c>SHA1PRNG未实现时, -
SecureRandom
即使从一个Sun JDK到另一个; - Oracle提供的实现
SHA1PRNG
使用初始种子作为种子,其他人可以将种子添加到随机池。
SecureRandom
's main function is to generate random values, it should not be used as a generator for a key stream;SecureRandom
, when instantiated with"SHA1PRNG"
does not implement a well defined algorithm, and the algorithm has actually be known to change, even from one Sun JDK to another;- The Oracle provided implementation of
"SHA1PRNG"
uses the initial seed as only seed, others may just add the seed to the random pool.
使用SHA1PRNG
作为密钥导出函数已知会在Android的多个版本上产生问题,并且可能在任何其他Java RE 。
Using "SHA1PRNG"
as key derivation function has been known to produce issues on several versions of Android, and may fail on any other Java RE.
那么你应该怎么办呢?
- 使用
new SecureRandom()
或更好,KeyGenerator
生成一个真正随机的密钥,而不需要随机数生成器一个全新的随机键; - 直接提供
SecretKeySpec 的已知键的
byte []
code>,或使用十六进制解码器从十六进制解码它(注意,String
实例很难从内存中删除,所以只有这样做,如果没有其他方式); - 如果要从密码创建密钥,请使用 PBKDF2 (使用比链接中提供的更高的迭代计数);
- 如果要从一个键种子创建多个键,请使用真正的基于键的键派生机制,例如使用HKDF(见下文)。
- Use
new SecureRandom()
or even better,KeyGenerator
to generate a truly random key, without seeding the random number generator if you need a brand new random key; - Directly provide a
byte[]
of a known key toSecretKeySpec
, or use a hexadecimal decoder to decode it from hexadecimals (note thatString
instances are hard to delete from memory, so only do this if there is no other way); - Use PBKDF2 if you want to create a key from a password (use a higher iteration count than the one provided in the link though);
- Use a true Key Based Key Derivation Mechanism if you want to create multiple keys from one key seed, e.g. use HKDF (see below).
如果种子是由密钥协议算法,如Diffie-Hellman或ECDH。
Option 4 would be preferred if the seed was generated by e.g. a key agreement algorithm such as Diffie-Hellman or ECDH.
请注意,对于选项3,PBKDF2,只保留ASCII密码。这是因为Oracle的PBKDF2实现不使用UTF-8编码。
Note that for option 3, PBKDF2, you would be wise to keep to ASCII passwords only. This is due to the fact that the PBKDF2 implementation by Oracle does not use UTF-8 encoding.
对于选项4 ,我已经帮助将所有好的KBKDF添加到 Bouncy城堡图书馆,所以没有如果您可以将Bouncy Castle添加到类路径和/或已安装的安全提供程序列表,则需要自行实施KBKDF。可能目前最好的KBKDF是HKDF。如果你不能添加Bouncy城堡到你的类路径,那么你可能想使用SHA-256输出的最左边的字节作为穷人的KDF的派生数据。
As for option 4, I've helped with adding all good KBKDF's to the Bouncy Castle libraries so there isn't a need to implement a KBKDF yourself if you can add Bouncy Castle to your classpath and/or list of installed security providers. Probably the best KBKDF at the moment is HKDF. If you cannot add Bouncy Castle to your classpath then you might want to use the leftmost bytes of SHA-256 output over the derivation data as a "poor man's" KDF.
这篇关于更好的方式来创建AES密钥,比种子SecureRandom的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!