如何正确使用 "PBEWithHmacSHA512AndAES_256" 算法?
How do I properly use the "PBEWithHmacSHA512AndAES_256" algorithm?
我正在做一些 Java 加密,但无法找到正确使用 PBEWithHmacSHA512AndAES_256 算法的方法。
加密似乎工作正常,但我无法正确初始化解密密码。
下面是一个演示该问题的简短程序。
特别是,请参阅 "PROBLEM" 评论。
注意:我已经看到 this very helpful answer,我可以使用该方案使事情正常进行,但我很想知道我在这里做错了什么。
import java.nio.charset.StandardCharsets;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
public final class CryptQuestion {
private static final String ALGORITHM = "PBEWithHmacSHA512AndAES_256";
private static final int ITERATIONS = 1000; // Aside: not sure what is a good number, here.
public static void main(final String[] args) throws Exception {
final String message = "This is the secret message... BOO!";
System.out.println("Original : " + message);
final byte[] messageBytes = message.getBytes(StandardCharsets.US_ASCII);
final String password = "some password";
final byte[] salt = "would be random".getBytes(StandardCharsets.US_ASCII);
// Create the Key
final SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);
final PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS);
SecretKey key = factory.generateSecret(keySpec);
// Build the encryption cipher.
final Cipher cipherEncrypt = Cipher.getInstance(ALGORITHM);
cipherEncrypt.init(Cipher.ENCRYPT_MODE, key);
// Encrypt!
final byte[] ciphertext = cipherEncrypt.doFinal(messageBytes);
final byte[] iv = cipherEncrypt.getIV();
// Now for decryption... The receiving end will have as input:
// * ciphertext
// * IV
// * password
// * salt
// We just re-use 'key' from above, since it will be identical.
final PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, ITERATIONS);
final IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
// Build the decryption cipher.
final Cipher cipherDecrypt = Cipher.getInstance(ALGORITHM);
// PROBLEM: If I pass "ivParamSpec", I get "java.security.InvalidAlgorithmParameterException: Wrong parameter type: PBE expected"
// Whereas if I pass pbeParamSpec, I get "java.security.InvalidAlgorithmParameterException: Missing parameter type: IV expected"
// What to do?
cipherDecrypt.init(
Cipher.DECRYPT_MODE,
key,
ivParamSpec
//pbeParamSpec
);
final String decrypted = new String(
cipherDecrypt.doFinal(ciphertext),
StandardCharsets.US_ASCII);
System.out.println("Decrypted: " + decrypted);
}
}
// PROBLEM: If I pass "ivParamSpec", I get "java.security.InvalidAlgorithmParameterException: Wrong parameter type: PBE expected"
// Whereas if I pass pbeParamSpec, I get "java.security.InvalidAlgorithmParameterException: Missing parameter type: IV expected"
// What to do?
cipherDecrypt.init(
Cipher.DECRYPT_MODE,
key,
ivParamSpec
//pbeParamSpec
);
使用加密 Cipher
中的 AlgorithmParameters
:
cipherDecrypt.init(
Cipher.DECRYPT_MODE,
key,
cipherEncrypt.getParameters()
);
如果你想要一种不涉及cipherEncrypt
解密站点的更简洁的方法,将算法参数保存为一个字节并将它们与密钥数据一起传输:
byte[] algorithmParametersEncoded = cipherEncrypt.getParameters().getEncoded();
并在解密站点重建它们:
AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance(ALGORITHM);
algorithmParameters.init(algorithmParametersEncoded);
并使用 algorithmParameters
作为上面 Cipher.init()
的 parameters
参数。
我增强了 jasypt 的 StandardPBEByteEncryptor 以支持 "PBEWithHmacSHA512AndAES_256" 算法。见代码 here
在此处查看单元测试PBEEncryptorTest
致那些从google跳到这里的人。还有另一种方法可以为 java 中的 PBEwithHmacSHA512AndAES_256 密码指定 IV。 IvParameterSpec 可以像这样在构造函数中添加到 PBEParameterSpec 中:
byte[] iv = ...;
byte[] salt = ...;
int iterations = 200000;
IvParameterSpec ivSpec = new IvParameterSpec(iv);
PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iterations, ivSpec);
然后可以使用这样的pbeSpec来初始化密码:
cipher.init(
Cipher.DECRYPT_MODE,
key,
pbeSpec
);
无论如何,接受的答案提供了一个更简洁的解决方案——使用 cipherEncrypt.getParameters().getEncoded() 一次序列化所有密码参数。生成的字节数组一次包含 IV、salt 和迭代计数。至少对于 PBEwithHmacSHA512AndAES_256 算法
,将此数据传递到加密消息旁边是完全可以的
我正在做一些 Java 加密,但无法找到正确使用 PBEWithHmacSHA512AndAES_256 算法的方法。
加密似乎工作正常,但我无法正确初始化解密密码。
下面是一个演示该问题的简短程序。 特别是,请参阅 "PROBLEM" 评论。
注意:我已经看到 this very helpful answer,我可以使用该方案使事情正常进行,但我很想知道我在这里做错了什么。
import java.nio.charset.StandardCharsets;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
public final class CryptQuestion {
private static final String ALGORITHM = "PBEWithHmacSHA512AndAES_256";
private static final int ITERATIONS = 1000; // Aside: not sure what is a good number, here.
public static void main(final String[] args) throws Exception {
final String message = "This is the secret message... BOO!";
System.out.println("Original : " + message);
final byte[] messageBytes = message.getBytes(StandardCharsets.US_ASCII);
final String password = "some password";
final byte[] salt = "would be random".getBytes(StandardCharsets.US_ASCII);
// Create the Key
final SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);
final PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS);
SecretKey key = factory.generateSecret(keySpec);
// Build the encryption cipher.
final Cipher cipherEncrypt = Cipher.getInstance(ALGORITHM);
cipherEncrypt.init(Cipher.ENCRYPT_MODE, key);
// Encrypt!
final byte[] ciphertext = cipherEncrypt.doFinal(messageBytes);
final byte[] iv = cipherEncrypt.getIV();
// Now for decryption... The receiving end will have as input:
// * ciphertext
// * IV
// * password
// * salt
// We just re-use 'key' from above, since it will be identical.
final PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, ITERATIONS);
final IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
// Build the decryption cipher.
final Cipher cipherDecrypt = Cipher.getInstance(ALGORITHM);
// PROBLEM: If I pass "ivParamSpec", I get "java.security.InvalidAlgorithmParameterException: Wrong parameter type: PBE expected"
// Whereas if I pass pbeParamSpec, I get "java.security.InvalidAlgorithmParameterException: Missing parameter type: IV expected"
// What to do?
cipherDecrypt.init(
Cipher.DECRYPT_MODE,
key,
ivParamSpec
//pbeParamSpec
);
final String decrypted = new String(
cipherDecrypt.doFinal(ciphertext),
StandardCharsets.US_ASCII);
System.out.println("Decrypted: " + decrypted);
}
}
// PROBLEM: If I pass "ivParamSpec", I get "java.security.InvalidAlgorithmParameterException: Wrong parameter type: PBE expected"
// Whereas if I pass pbeParamSpec, I get "java.security.InvalidAlgorithmParameterException: Missing parameter type: IV expected"
// What to do?
cipherDecrypt.init(
Cipher.DECRYPT_MODE,
key,
ivParamSpec
//pbeParamSpec
);
使用加密 Cipher
中的 AlgorithmParameters
:
cipherDecrypt.init(
Cipher.DECRYPT_MODE,
key,
cipherEncrypt.getParameters()
);
如果你想要一种不涉及cipherEncrypt
解密站点的更简洁的方法,将算法参数保存为一个字节并将它们与密钥数据一起传输:
byte[] algorithmParametersEncoded = cipherEncrypt.getParameters().getEncoded();
并在解密站点重建它们:
AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance(ALGORITHM);
algorithmParameters.init(algorithmParametersEncoded);
并使用 algorithmParameters
作为上面 Cipher.init()
的 parameters
参数。
我增强了 jasypt 的 StandardPBEByteEncryptor 以支持 "PBEWithHmacSHA512AndAES_256" 算法。见代码 here
在此处查看单元测试PBEEncryptorTest
致那些从google跳到这里的人。还有另一种方法可以为 java 中的 PBEwithHmacSHA512AndAES_256 密码指定 IV。 IvParameterSpec 可以像这样在构造函数中添加到 PBEParameterSpec 中:
byte[] iv = ...;
byte[] salt = ...;
int iterations = 200000;
IvParameterSpec ivSpec = new IvParameterSpec(iv);
PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iterations, ivSpec);
然后可以使用这样的pbeSpec来初始化密码:
cipher.init(
Cipher.DECRYPT_MODE,
key,
pbeSpec
);
无论如何,接受的答案提供了一个更简洁的解决方案——使用 cipherEncrypt.getParameters().getEncoded() 一次序列化所有密码参数。生成的字节数组一次包含 IV、salt 和迭代计数。至少对于 PBEwithHmacSHA512AndAES_256 算法
,将此数据传递到加密消息旁边是完全可以的