AES算法返回数据字符串中间的垃圾字符



我取一个数据字符串="AkhilRanjanBiharbcdefghijklmnoMovedtoChennai18",先加密,然后解密。解密后返回的字符串是"AkhilRanjanBiharÙ†+™"这对于前16个和最后16个字符来说几乎没问题,但中间的16个字符都是垃圾。可能出了什么问题?

我的加密码:-

public String encrypt(String value) {
log.info("This method is not going to be used");
String key = "theabcd@heymaths";
initVector = "{{{{{{{{{{{{{{{{";
String encryptedStr="";
byte[] encrBytes =null;
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes());
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
encrBytes = cipher.doFinal(value.getBytes());
encryptedStr = new String(encrBytes);
} catch (Exception ex) {
ex.printStackTrace();
}
String strToBeEncoded = encryptedStr +"::"+initVector;
encrBytes = strToBeEncoded.getBytes();
//String encoded = Base64.encodeBase64String(encrBytes);
String encoded = Base64.getEncoder().encodeToString(encrBytes);
String urlEncoded = null;
try {
urlEncoded = java.net.URLEncoder.encode(encoded, CHARSET);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return urlEncoded;
}

解密代码:-

public String decrypt(String encrypted) {
String decryptedStr = null;
byte[] base64Bytes = null;
String urlDecoded = null;
String key = HmCommonProperty.getProperty("abcd_crypt_key");
if(key == null || key.isEmpty()) {
key = securityKey;
}
String encryptionMech = HmCommonProperty.getProperty("abcd_crypt_algo");
if(encryptionMech == null || encryptionMech.isEmpty()) {
encryptionMech = CRYPT_MECHANISM;
}
try {
//Url and Base64 decoding
urlDecoded = java.net.URLDecoder.decode(encrypted, CHARSET);
//base64Bytes = Base64.decodeBase64(urlDecoded);
base64Bytes = Base64.getDecoder().decode(urlDecoded);
//Generating IV
String str = new String(base64Bytes);
String[] bodyIVArr = str.split("::");
initVector = bodyIVArr[1];
String bodyStr = bodyIVArr[0];
//AES Decryption
Cipher cipher = Cipher.getInstance(encryptionMech);
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes());
System.out.println("initVector Length ->  "
+iv.getIV().length);
System.out.println("input length ->  "
+bodyStr.getBytes().length);
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] decryptedBytes = cipher.doFinal(bodyStr.getBytes());
decryptedStr =  new String(decryptedBytes);
} catch (Exception ex) {
ex.printStackTrace();
log.error("Error occurred while decryption abcd data",ex);
}
return decryptedStr;
}

您的加密数据是一个字节序列。如果需要将其编码为字符串,则应使用base64或类似的编码方法,用于对任意字节数组进行编码。假设任意字节数组是有效的字符串编码会给您带来麻烦,即使您使用ISO_8859_1也是如此。

更换

encryptedStr = new String(encrBytes)

带有

encryptedStr = Base64.getEncoder().encodeToString(encrBytes)

并替换

bodyStr.getBytes()

带有

Base64.getDecoder().decode(bodyStr)

另请参阅:如何正确一致地从字符串中获取字节进行AES加密?

您的错误就在这里:

encryptedStr = new String(encrBytes);
strToBeEncoded.getBytes();

这些方法使用平台默认字符集,当您从byte[]转换为String并返回到byte[]时,在一般情况下,该过程是有损耗的。唯一没有损耗的方法是平台默认字符集为"ISO_8859_1"

我把11个这样的电话都改成了:

encryptedStr = new String(encrBytes, StandardCharsets.ISO_8859_1);
strToBeEncoded.getBytes(StandardCharsets.ISO_8859_1);

(我没有更改CHARSET(。我现在得到的输出是:

initVector长度->16
输入长度->48
AkhilRanjanBiharbcdefghijklmnonopMovedtoChennai18

额外警告1:加密使用硬编码的"AES/CBC/NoPadding",但解密是动态的(当然也应该使用"AES/CBC/NoPadding"(。

奖金警告2:几率很低,但完全有可能"::"出现在encrBytes内部,搞砸了你的str.split("::");。一种解决方案是搜索"::"最后一次,并仅在此基础上拆分。

最新更新