【发布时间】:2019-11-09 08:47:31
【问题描述】:
我不推荐使用 DES 进行加密/解密,但它是一个旧代码,所以我无法迁移到 AES,现在我的代码在本地环境(即 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");
}
}
【问题讨论】:
-
当分布完全不同时,UAT 怎么可能是一个精确的副本?这不是人们对“精确复制品”的意思
-
当你说它在 prod 中不起作用时,你是什么意思?
-
那么您的输入数据不同(使用错误的键您可能会遇到填充异常)。没有理由为什么这个 Java 代码在不同的环境中会有所不同(除了 Cipher 对象不是线程安全的)。您需要查找并提供更多信息。
-
这里有一些依赖默认值的加密反模式。下面@Joop Eggen 的答案突出显示了一个。另一个在这里:
Cipher.getInstance("DES");。始终将完整的 algorithm/mode/padding 字符串指定为Cipher.getInstance()。 -
另一个问题是您在
decryptUTF8中的异常处理。你抓住IllegalBlockSizeException并默默地返回base64 编码的密文。您至少应该记录异常,以便您可以意识到它并修复错误。您也没有提到结果如何“不同”。
标签: java linux encryption redhat des