我不建议使用DES进行加密/解密,因为它是旧代码,所以我无法使用AES,现在我的代码可以在具有生产db的本地环境(即mac)上正常工作,也可以正常工作在基于SUSE的Linux发行版的UAT上运行,但是解密在基于Redhat的生产环境下无法正常工作。生产时会抛出“输入长度(带填充)不是8个字节的倍数”的非法块大小异常
@Service
public class EncryptionUtil {
private static final Logger log = LogManager.getLogger(EncryptionUtil.class);
@Autowired
GpsCacheManager gpsCacheManager;
private Cipher ecipher;
private Cipher dcipher;
@Autowired
private StringUtils stringUtils;
public EncryptionUtil() throws Exception {
ecipher = Cipher.getInstance("DES");
dcipher = Cipher.getInstance("DES");
initCipher();
}
private void initCipher() {
try {
String response = “[-3232, -34, -98, 111, -222, 33, -22, 55]”;
String[] byteValues = response.substring(1, response.length() - 1).split(",");
byte[] bytes = new byte[byteValues.length];
for (int i = 0, len = bytes.length; i < len; i++) {
bytes[i] = Byte.parseByte(byteValues[i].trim());
}
SecretKey key = new SecretKeySpec(bytes, "DES");
ecipher.init(Cipher.ENCRYPT_MODE, key);
dcipher.init(Cipher.DECRYPT_MODE, key);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
public String encryptUTF8(String str) throws Exception {
// Encode the string into bytes using utf-8
byte[] utf8 = str.getBytes("UTF8");
// Encrypt
byte[] enc = ecipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return new String(Base64.encodeBase64(enc));
}
public String decryptUTF8(String str) throws Exception {
if (stringUtils == null) {
stringUtils = new StringUtils();
}
//do not decrypt if a valid email.
if (stringUtils.isValidEmail(str)) {
return str;
}
// Decode base64 to get bytes
byte[] dec = Base64.decodeBase64(str.getBytes());
byte[] utf8 = null;
try {
utf8 = dcipher.doFinal(dec);
} catch (IllegalBlockSizeException e) {
return str;
}
// Decode using utf-8
return new String(utf8, "UTF8");
}
}
答案 0 :(得分:1)
String.getBytes()
和new String(byte[])
存在问题,它们与平台有关,因此不应在此处使用。同时,我用标准Java的Base64替换了Base64类,该类旨在替代十年前的几种Base64实现。
public String encryptUTF8(String str) throws Exception {
// Encode the string into bytes using utf-8
byte[] utf8 = str.getBytes(StandardCharsets.UTF_8);
// Encrypt
byte[] enc = ecipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return Base64.getEncoder().encodeToString(enc));
//Old class: return new String(Base64.encodeBase64(enc), StandardCharsets.US_ASCII);
}
public String decryptUTF8(String str) throws Exception {
if (stringUtils == null) {
stringUtils = new StringUtils();
}
//do not decrypt if a valid email.
if (stringUtils.isValidEmail(str)) {
return str;
}
// Decode base64 to get bytes
//byte[] dec = Base64.getDecoder().decode(str.getBytes(StandardCharsets.US_ASCII));
byte[] dec = Base64.getDecoder().decode(str);
try {
byte[] utf8 = dcipher.doFinal(dec);
// Decode using utf-8
return new String(utf8, StandardCharsets.UTF_8);
} catch (IllegalBlockSizeException e) {
return str;
}
}
有一个问题:String
用于Unicode文本,带有两个字节的char
(UTF-16)。
这意味着任何byte[]
值都必须是某种编码的文本,并且该编码必须转换为字符串。任何任意byte[]
值都不是有效的字符串。尤其是在具有卓越的UTF-8编码的Linux上,它将破坏数据。
问题可能出在decryptUTF8
。如果在原始代码中默认编码为单字节编码,则所有内容均被原样吞下。对于Linux,UTF-8可能会遇到错误的UTF-8多字节序列。 或者编码是7位ASCII。
通常将String
和byte[]
分开;将byte[]
用于非文本二进制数据。