【发布时间】:2018-07-04 23:34:54
【问题描述】:
我正在尝试使用标准Cipher API 使用 Java 中的已知密钥解密 String。
加密的String 来自Web Service,使用标准CommonCrypto 库,其中responds 和一些statistics 定期作为加密字符串。
规格为AES/CBC/PKCS7Padding 与KeySize = 32 Bytes 和BlockSize = 16 Bytes,以及Encoding UTF-8 (raw) 和Base64。我打算编写一个 Java 客户端,它可以请求这些 statistics、decrypt 并存储它们以供以后分析。
问题 1. 如果密钥很短,CommonCrypto 会自动用额外的字符填充密钥吗?例如小于16 Bytes or 32 Bytes。
问题2.我应该采取什么编码措施来确保两端相同的encryption/decryption?
示例字符串和键
String message = "mQp9sp8ri1E0V1Xfso1d5g==Mrf3wtaqUjASlZmUO+BI8MrWsrZSC0MxxMocswfYnqSn/VKB9luv6E8887eCxpLNNAOMB0YXv6OS7rFDFdlvC53pCHo3cVZiLJFqgWN/eNiC9p4RMxyFCcOzWrwKzT5P8sy55DwE25DNJkvMthSaxK5zcP1OdLgBiZFOSxYRsX4rBk7VP7p5xr2uTGjRL+jmGgB9u3TmeCNCr8NxGLNt6g==";
String userKey = "123456789";
private static String decrypt (String message, String userKey) throws UnsupportedEncodingException,
NoSuchPaddingException,
NoSuchAlgorithmException,
InvalidKeyException,
ShortBufferException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, NoSuchProviderException {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
if (message.length() >= 48) {
ivFromEncryptedString = message.substring(0, Math.min(message.length(), 24));
messageFromEncryptedString = message.substring(24, message.length());
System.out.println(ivFromEncryptedString);
System.out.println(messageFromEncryptedString);
byte[] data = decodeBase64(messageFromEncryptedString);
byte[] ivData = decodeBase64(ivFromEncryptedString);
paddedKey = padShortKeys(userKey);
byte[] keyBytes = paddedKey.getBytes(CHARSET);
MessageDigest sha = MessageDigest.getInstance("SHA-256"); //key
keyBytes = sha.digest(keyBytes);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivData);
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
byte [] encrypted = new byte[cipher.getOutputSize(data.length)];
int ctLength = cipher.update(data, 0, data.length, encrypted, 0);
ctLength += cipher.doFinal(encrypted, ctLength);
} catch (Exception e) {
System.out.println(e);
} finally {
return encrypted;
}
}
return null;
}
private static String encodeBase64(byte [] in){
return Base64.getEncoder().encodeToString(in);
}
private static byte[] decodeBase64(String str) throws UnsupportedEncodingException {
return DatatypeConverter.parseBase64Binary(str);
}
此外,在当前代码状态下,我得到的是占位符字符,而不是所需的结果。
在此先感谢各位。 :)
【问题讨论】:
-
您将消息拆分为 IV 和加密数据。对于 IV,您采用 Base 64 编码字符串的 24 个字符,即 18 个原始字节。你的 IV 真的是 18 字节长吗?
-
1.为什么要在密钥传递到 MD5 时填充密钥,这没有任何意义。 2. MD5 产生一个 16 字节的输出,而您使用 AES 和 32 字节的密钥,这同样没有意义。 3. MD5不是安全密钥派生函数,PBKDF2是安全的。
-
@Codo 这 24 个字符是 Base64 编码并解码为 16 字节,最后两个字符“==”是 Base64 填充。见Base64 Output Padding。
-
除了 zaph 所说的一切之外,您还错误地使用了
Cipher.update()和Cipher.doFinal()。请仔细重新阅读这些方法的Javadocs。我怀疑你想要的只是一个电话doFinal(),即。byte [] out = cipher.doFinal(data). -
@Codo IV 应该是 16 字节。
标签: java encryption aes commoncrypto cbc-mode