我有一个发送给我的密码,该密码使用带有基于数字ID的MD5哈希的AES加密
从请求中,我可以使用其他属性获取数据库中的id 所以在服务器端,我需要获取id,根据该ID获取MD5哈希值,并使用AES算法和生成的MD5哈希值来解密密码。
我使用以下代码获取MD5哈希
try {
byte[] bytesOfMessage = id.getBytes("UTF-8");
log.error "bytesOfMessage length: " + bytesOfMessage.length
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(bytesOfMessage);
md5Value = new String(thedigest);
log.error "md5Value length: " + md5Value.length()
log.error "md5Value bytes length: " + md5Value.getBytes().length
} catch (UnsupportedEncodingException e) {
log.error "[getMD5EncryptionKey]UnsupportedEncodingException: " + e;
} catch (NoSuchAlgorithmException e) {
log.error "[getMD5EncryptionKey]NoSuchAlgorithmException: " + e;
}
基于id为1,md5Value长度为16但是当我从这个md5value获取字节时,有34个字节
当我使用此MD5哈希和javax.crypto.Cipher库解密密码时,我收到以下消息
java.security.InvalidKeyException:无效的AES密钥长度:34个字节
我在这里做错了什么想法?
我用来解密消息的代码如下
try {
byte [] encryptionKeyBytes = md5EncryptionKey.getBytes("UTF-8");
Key key = new SecretKeySpec(encryptionKeyBytes, "AES");
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.DECRYPT_MODE, key);
byte[] decodedValue = new Base64().decode(encryptedData);
byte[] decValue = c.doFinal(decodedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
} catch (InvalidKeyException e) {
log.error "[getDecryptedValue] InvalidKeyException: " + e
} catch (IllegalBlockSizeException e) {
log.error "[getDecryptedValue] InvalidKeyException: " + e
} catch (BadPaddingException e) {
log.error "[getDecryptedValue] InvalidKeyException: " + e
} catch (NoSuchAlgorithmException e) {
log.error "[getDecryptedValue] InvalidKeyException: " + e
} catch (NoSuchPaddingException e) {
log.error "[getDecryptedValue] InvalidKeyException: " + e
} catch (Exception e) {
log.error "[getDecryptedValue] InvalidKeyException: " + e
}
答案 0 :(得分:1)
您获得的字节数组是md5-hash,但具有十六进制值。
您不能只是将数组转换为字符串。您必须使用一个算法来转换它,该算法采用这些六进制值并为您提供正确的字符串。
下面你可以看到一个获取32位MD5Hash-String的算法,这可能会有所帮助:
public String createHashString(String s)
{
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytesOfMessage = s.getBytes("UTF-8");
byte[] thedigest = md.digest(bytesOfMessage);
String hexString = "";
for(byte bi : thedigest)
{
String hex = Integer.toHexString(0xFF & bi);
if (hex.length() == 1) {
hexString += "0";
}
hexString += (hex);
}
return hexString;
}
catch (Exception e) {
return "";
}
}
答案 1 :(得分:1)
这个md5Value = new String(thedigest)
是您的问题。 thedigest
是二进制的,并且String类无法弄清楚它的编码(因为它没有),这会导致二进制值在您尝试将其从String中取回时被破坏。这就是md5Value.getBytes().length
为34个字节的原因。直接从SecretKeySpec
创建thedigest
。
Key key = new SecretKeySpec(thedigest, "AES");
AES密钥需要是MD5哈希的实际16字节二进制值。
另请注意,new String(someBinaryByteArray).getBytes()
有时会返回您输入的相同字节,但这些都取决于输入。您的输入ID值说明了这一点。另一个例子:
String id = "test";
byte[] bytesOfMessage = id.getBytes("UTF-8");
System.out.println("bytesOfMessage length: " + bytesOfMessage.length);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(bytesOfMessage);
System.out.println("thedigest Hex: " + Hex.encodeHexString(thedigest));
String md5Value = new String(thedigest);
System.out.println("md5Value length: " + md5Value.length());
System.out.println("md5Value bytes length: " + md5Value.getBytes().length);
System.out.println("md5Value Hex: " + Hex.encodeHexString(md5Value.getBytes()));
Output:
bytesOfMessage length: 4
thedigest Hex: 098f6bcd4621d373cade4e832627b4f6
md5Value length: 16
md5Value bytes length: 16
md5Value Hex: 093f6bcd4621d373cade4e832627b4f6
098f6bcd4621d373cade4e832627b4f6
!= 093f6bcd4621d373cade4e832627b4f6
答案 2 :(得分:1)
问题是该字符串是十六进制的。我建议你使用apache commons-code包。你有一个哈希的实用程序类。
然后您可以使用以下代码:
String md5 = DigestUtils.md5Hex(id);
// or
byte[] md5 = DigestUtils.md5(id);