我正在尝试更改现有项目的加密算法。但是我有点困惑。当我使用“ PBEWithHmacSHA512AndAES_256”作为参数时,它会产生不同的结果,但是当我使用“ PBEWithMD5AndDES”作为参数时,它会产生相同的结果。我的功能是:
public static synchronized String encrypt1(final String textToEncrypt, final String pathPublicKey) throws Exception {
final KeySpec pbeKeySpec = new PBEKeySpec(DbKeyHandler.getDbKey(pathPublicKey).toCharArray());
final SecretKey pbeKey = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(pbeKeySpec);
// Prepare the parameter to the ciphers
final AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
final Cipher cipher = Cipher.getInstance(pbeKey.getAlgorithm());
// Create the ciphers
cipher.init(Cipher.ENCRYPT_MODE, pbeKey, paramSpec);
// Encode the string into bytes using utf-8
final byte[] utf8 = textToEncrypt.getBytes("UTF8");
// Encrypt
final byte[] enc = cipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return new sun.misc.BASE64Encoder().encode(enc);
}
public static synchronized String encrypt2 (final String textToEncrypt, final String pathPublicKey) throws Exception {
final KeySpec pbeKeySpec = new PBEKeySpec(DbKeyHandler.getDbKey(pathPublicKey).toCharArray());
final SecretKey pbeKey = SecretKeyFactory.getInstance("PBEWithHmacSHA512AndAES_256").generateSecret(pbeKeySpec);
// Prepare the parameter to the ciphers
final AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
final Cipher cipher = Cipher.getInstance(pbeKey.getAlgorithm());
// Create the ciphers
cipher.init(Cipher.ENCRYPT_MODE, pbeKey, paramSpec);
// Encode the string into bytes using utf-8
final byte[] utf8 = textToEncrypt.getBytes("UTF8");
// Encrypt
final byte[] enc = cipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return new sun.misc.BASE64Encoder().encode(enc);
}
任何建议,想法将帮助我弄清楚这里发生了什么。
这也会产生不同的结果:
KeyStore keyStore = KeyStore.getInstance("JCEKS");
keyStore.load(new FileInputStream((pathOfJKSfile)), password.toCharArray());
Key key = keyStore.getKey(keyName, keyPass.toCharArray());
byte[] raw = key.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "PBEWithHmacSHA512AndAES_256");
final AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATIONS);
final Cipher cipherEncrypt = Cipher.getInstance(ALGORITHM);
cipherEncrypt.init(Cipher.ENCRYPT_MODE, secretKeySpec, paramSpec);
final byte[] enc = cipherEncrypt.doFinal(messageBytes);
System.out.println( new sun.misc.BASE64Encoder().encode(enc));
我知道cipher.init()使用“ JceSecurity.RANDOM”实现了不同的结果。
答案 0 :(得分:2)
PBEWithHmacSHA512AndAES_256
和PBEWithMD5AndDES
这两种算法首先通过处理密码,盐和迭代计数(使用HmacSHA512
和MD5
来生成加密密钥。 ,然后使用此密钥和CBC
-mode加密纯文本(分别使用AES-256
和DES
)。初始化Cipher
实例后,将生成CBC
-模式所需的伪随机initialization vector(IV)。
在PBEWithHmacSHA512AndAES_256
的上下文中,至少使用{{3},使用最高安装优先级的提供程序的SecureRandom
实现来生成IV。 }}-方法在代码中使用(请注意,Cipher#init()
-方法有多个重载,并且SecureRandom
-实例也可以显式传递)。即每次Cipher
初始化时,都会生成 new (随机)IV,因此,即使对于相同的纯文本,加密的文本也始终是不同的。因此,示例中的加密文本会在这种情况下发生变化。
在PBEWithMD5AndDES
的上下文中,IV仅由密码,盐,迭代次数(当然还有MD5
散列)确定。 -算法本身)。因此,IV和加密文本在重复的情况下不会更改(前提是密码,密码,迭代次数等相同)。因此,示例中的加密文本在这种情况下不会更改。
在密码初始化期间生成新的随机IV对于IV的以下要求是有意义的:出于安全原因,CBC
模式的IV(顺便说一句也适用) (其他模式)Cipher#init()
。此外,IV必须是不可预测的。
PBEWithMD5AndDES
是may only be used once under the same key。
编辑:
如今,出于安全考虑,IV的使用是标准的。在互联网上可以找到有关此主题的很多信息,例如deprecated。在下文中,我只会描述一些基本的东西。
用于加密的IV必须以某种方式存储,因为它是解密所必需的。 IV不必保密,因此通常将其与加密数据连接起来(例如,在加密数据之前),并与它们一起存储。在解密期间,因为IV的长度是已知的(AES为16字节),所以可以将两个部分分开。例如,对于加密方法中的级联,使用类似以下的内容(分别使iv
和enc
分别是具有IV和加密数据的字节数组):
byte[] result = new byte[enc.length + iv.length];
System.arraycopy(iv, 0, result, 0, iv.length);
System.arraycopy(enc, 0, result, iv.length, enc.length);
以及解密方法中的对应方法(请注意,AES中IV的长度为16字节)。
在加密方法中,可以使用Cipher#getIV()
确定IV(当然这必须在调用Cipher#init()
之后发生)。
在解密方法中,您必须将IV传递给PBEParameterSpec
-ctor(例如,让iv
是具有IV的字节数组):
IvParameterSpec ivSpec = new IvParameterSpec(iv);
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount, ivSpec);
IV的生成也可以在Cipher
类之外进行,请参见例如here。然后,您必须以与上述解密方法相同的方式在加密方法中传递该IV。
注意,关于IV,必须考虑一些要点,例如使用没有IV的模式(例如ECB),使用仅由0
值组成的IV,使用可预测的IV或在同一密钥下多次使用IV等,通常会大大降低安全性,例如,请参见Generating random IV for AES in Java!