I'm trying to code a crypto java testclass which encrypt and decrypt a String password with BouncyCastle. The main()
is very simple, I do encryptPass()
and then decryptPass()
, and I watch the console trace.
我正在尝试编写一个加密java测试类,它使用BouncyCastle加密和解密String密码。 main()非常简单,我做了encryptPass()然后解密了Pass(),我看着控制台跟踪。
The problem is when it tries to decrypt, I got a padding exception :
问题是当它试图解密时,我得到了一个填充异常:
javax.crypto.BadPaddingException: pad block corrupted
at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at com.kiengi.crypto.Crypto.decryptPass(Crypto.java:79)
My code is the following for the Crypto class :
我的代码是Crypto类的以下代码:
// password to be crypted
public String pass = "password_go_here";
// key for encrypt pass
public String passKey = generateRandomKey(); // generation clef 16 caractere [a-zA-Z0-9]
// Encrypted pass
public String cryptedPass;
public final Logger logger = Logger.getLogger(this.getClass());
private final static byte[] IV_BYTES = new byte[] { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
0x00, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
public Crypto() {
super();
}
public void encryptPass(){
Security.addProvider(new BouncyCastleProvider());
IvParameterSpec _ivSpec = new IvParameterSpec(IV_BYTES);
try{
KeyGenerator _keygen = KeyGenerator.getInstance("AES");
_keygen.init(new SecureRandom(passKey.getBytes()));
SecretKey _key = _keygen.generateKey();
logger.trace("Secret key generated");
Cipher _cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
_cipher.init(Cipher.ENCRYPT_MODE, _key, _ivSpec);
cryptedPass = asHex(_cipher.doFinal(pass.getBytes("UTF-8")));
logger.trace("Encrypted pass : "+cryptedPass);
}catch (Exception e) {
logger.warn("encrypt failed");
e.printStackTrace();
}
}
public void decryptPass() {
byte[] _passKey = passKey.getBytes();
byte[] _cryptedPass = hexFromString(cryptedPass);
Security.addProvider(new BouncyCastleProvider());
IvParameterSpec _ivSpec = new IvParameterSpec(IV_BYTES);
try {
KeyGenerator _keygen = KeyGenerator.getInstance("AES");
_keygen.init(new SecureRandom(_passKey));
SecretKey _key = _keygen.generateKey();
logger.trace("Secret key generated");
Cipher _cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
_cipher.init(Cipher.DECRYPT_MODE, _key, _ivSpec);
String _pass = new String(_cipher.doFinal(_cryptedPass), "UTF-8");
logger.trace("Decrypted pass : "+_pass);
} catch (Exception e) {
logger.warn("decrypt failed");
e.printStackTrace();
}
}
private int fromDigit(char ch) {
if ((ch >= '0') && (ch <= '9')) {
return ch - '0';
} else if ((ch >= 'A') && (ch <= 'F')) {
return ch + 10 - 'A';
} else if ((ch >= 'a') && (ch <= 'f')) {
return ch + 10 - 'a';
} else {
throw new IllegalArgumentException(String.format(
"Invalid hex character 0x%04x", 0xff & ch));
}
}
private byte[] hexFromString(String hex) {
final byte[] buf = new byte[hex.length() / 2];
for (int i = 0, j = 0; i < hex.length(); i += 2) {
buf[j++] = (byte) (fromDigit(hex.charAt(i)) << 4 | fromDigit(hex
.charAt(i + 1)));
}
return buf;
}
private static String asHex(byte buf[]) {
final Formatter formatter = new Formatter(new StringBuffer());
for (int i = 0; i < buf.length; i++) {
formatter.format("%02x", 0xff & buf[i]);
}
return formatter.toString();
}
private String generateRandomKey() {
String _chars = "abcdefABCDEF1234567890";
StringBuffer _pass = new StringBuffer();
for (int x = 0; x < 32; x++) {
int i = (int) Math.floor(Math.random() * (_chars.length() - 1));
_pass.append(_chars.charAt(i));
}
return _pass.toString();
}
Does anyone knows what this exception means?
有谁知道这个例外意味着什么?
2 个解决方案
#1
0
This code has a bug. It assumes that new SecureRandom(passKey.getBytes())
will initialize the SecureRandom instance with only the bytes supplied in the constructor. This is wrong. The data in the constructor will supplement whatever entropy sources SecureRandom uses, not replace them.
这段代码有一个bug。它假设新的SecureRandom(passKey.getBytes())将仅使用构造函数中提供的字节初始化SecureRandom实例。这是错的。构造函数中的数据将补充SecureRandom使用的任何熵源,而不是替换它们。
You need to use a proper password-based encryption (PBE) scheme.
您需要使用正确的基于密码的加密(PBE)方案。
#2
0
This exception means that padding block is corrupted. You use PKCS#7 padding with 16B blocks. In this sample your output is 16B too. So it always should be added block with 16 bytes of value 0x10.
The padding is corrupted because the decryption is corrupted. Your SecureRandom implementation adds its own entropy and generates wrong decryption key. This SecureRandom constructor uses the first PRNG algorithm of the first provider that has registered a SecureRandom implementation.
此异常表示填充块已损坏。您使用带有16B块的PKCS#7填充。在此示例中,您的输出也是16B。所以总是应该添加16字节值0x10的块。填充已损坏,因为解密已损坏。您的SecureRandom实现会添加自己的熵并生成错误的解密密钥。此SecureRandom构造函数使用已注册SecureRandom实现的第一个提供程序的第一个PRNG算法。
#1
0
This code has a bug. It assumes that new SecureRandom(passKey.getBytes())
will initialize the SecureRandom instance with only the bytes supplied in the constructor. This is wrong. The data in the constructor will supplement whatever entropy sources SecureRandom uses, not replace them.
这段代码有一个bug。它假设新的SecureRandom(passKey.getBytes())将仅使用构造函数中提供的字节初始化SecureRandom实例。这是错的。构造函数中的数据将补充SecureRandom使用的任何熵源,而不是替换它们。
You need to use a proper password-based encryption (PBE) scheme.
您需要使用正确的基于密码的加密(PBE)方案。
#2
0
This exception means that padding block is corrupted. You use PKCS#7 padding with 16B blocks. In this sample your output is 16B too. So it always should be added block with 16 bytes of value 0x10.
The padding is corrupted because the decryption is corrupted. Your SecureRandom implementation adds its own entropy and generates wrong decryption key. This SecureRandom constructor uses the first PRNG algorithm of the first provider that has registered a SecureRandom implementation.
此异常表示填充块已损坏。您使用带有16B块的PKCS#7填充。在此示例中,您的输出也是16B。所以总是应该添加16字节值0x10的块。填充已损坏,因为解密已损坏。您的SecureRandom实现会添加自己的熵并生成错误的解密密钥。此SecureRandom构造函数使用已注册SecureRandom实现的第一个提供程序的第一个PRNG算法。