我的问题是:我在Java中加密的东西我可以在Java中完美解密,但PHP mcrypt
无法解密。我使用mcrypt
加密的内容我可以用mcrypt
解密,但不能用Java解密。
我想从Java应用程序发送和接收加密数据到PHP页面,所以我需要它兼容。
这就是我所拥有的......
... JAVA
public static String crypt(String input, String key){
byte[] crypted = null;
try{
SecretKeySpec skey = new SecretKeySpec(Base64.decodeBase64(key), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skey);
crypted = cipher.doFinal(input.getBytes());
}catch(Exception e){
}
return Base64.encodeBase64String(crypted);
}
public static String decrypt(String input, String key){
byte[] output = null;
try{
SecretKeySpec skey = new SecretKeySpec(Base64.decodeBase64(key), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skey);
output = cipher.doFinal(Base64.decodeBase64(input));
}catch(Exception e){
}
return new String(output);
}
运行:
public static void main(String[] args) {
String key = "Zvzpv8/PXbezPCZpxzQKzL/FeoPw68jIb+NONX/LIi8=";
String data = "example";
System.out.println(Cpt.decrypt(Cpt.crypt(data, key), key));
}
输出:
example
... PHP
function getEncrypt($sStr, $sKey) {
return base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_256,
$sKey,
$sStr,
MCRYPT_MODE_ECB
)
);
}
function getDecrypt($sStr, $sKey) {
return mcrypt_decrypt(
MCRYPT_RIJNDAEL_256,
$sKey,
base64_decode($sStr),
MCRYPT_MODE_ECB
);
}
运行:
$crypt = getDecrypt(getEncrypt($str, $key), $key);
echo "<p>Crypt: $crypt</p>";
输出:
Crypt: example�������������������������
使用PHP密钥“示例”,密钥为“Zvzpv8 / PXbezPCZpxzQKzL / FeoPw68jIb + NONX / LIi8 =”我得到“YTYhgp4zC + w5IsViTR5PUkHMX4i7JzvA6NJT1FqhoGY =”。 使用Java用相同的密钥加密相同的东西,我得到“+ tdAZqTE7WAVPXhB3Tp5 + g ==”。
我正在以正确的顺序对base64进行编码和解码,我测试了base64编码和解码Java和PHP之间的兼容性,并且它正在工作。
答案 0 :(得分:14)
BUG#1
MCRYPT_RIJNDAEL_256
不是 AES。该常量中的256表示块大小,而不是密钥大小。使用MCRYPT_RIJNDAEL_128
获取与AES相同的算法。密钥大小仅由您提供的密钥参数中的字节数设置。因此,提供32个字节,然后使用256位密钥获得AES。
BUG#2
这两行在Java中永远不正确,表明对加密转换产生的任意二进制数据性质的基本误解:
output = cipher.doFinal(Base64.decodeBase64(input));
return new String(output);
直接传输和存储byte[]
没有任何问题,但如果您必须只使用可打印的字符串,那么您应该使用base64编码/解码来执行此操作。因为你已经广泛使用base64,这似乎是要走的路。我猜想正确的两行是:
output = cipher.doFinal(Base64.decodeBase64(input));
return new String(Base64.encodeBase64(output), "UTF-8");
编辑:
开玩笑吧#2。真的,我错了,我没注意到它是解密方向。当然,如果你知道解密的byte[]
是一个有效的字符串,那么完成代码所做的就完全正确了。
答案 1 :(得分:9)
我知道这是一个老话题,但我会添加我的工作解决方案。
你必须重写脚本的PHP端:
function getEncrypt($sStr, $sKey) {
return base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
base64_decode($sKey),
$sStr,
MCRYPT_MODE_ECB
)
);
}
function getDecrypt($sStr, $sKey) {
return mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
base64_decode($sKey),
base64_decode($sStr),
MCRYPT_MODE_ECB
);
}
你应该base64_decode($ sKey)因为你的密钥是base64编码的。
$key = "Zvzpv8/PXbezPCZpxzQKzL/FeoPw68jIb+NONX/LIi8=";
然后,你需要创建这个功能(功劳从http://www.php.net/manual/en/function.mcrypt-decrypt.php转到beltrachi):
function pkcs5_pad ($text, $blocksize) {
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
使用此代码执行编码/解码:
$decrypt = getDecrypt("6XremNEs1jv/Nnf/fRlQob6oG1jkge+5Ut3PL489oIo=", $key);
echo $decrypt;
echo "\n\n";
echo getEncrypt(pkcs5_pad("My very secret text:)", 16), $key);
我希望这对某人有用! :)
答案 2 :(得分:3)
请看这里:
您遇到的问题是填充问题。我不了解Java,但AES/ECB/PKCS5Padding
看起来你正在使用PKCS#5(与PKCS#7本质上相同)填充,而PHP本身只支持NULL
- 填充。这就是PKCS#5/7的作用:
使用填充字符串填充输入 在1到8个字节之间做 总长度是8的精确倍数 字节。每个字节的值 padding string设置为的数量 添加的字节数 - 即8个字节的值 0x08,7个字节的值0x07,...,2 0x02的字节,或一个字节的值 0×01。
所以用于填充权限的PHP代码是微不足道的:
$blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$padding = $blockSize - (strlen($data) % $blockSize);
$data .= str_repeat(chr($padding), $padding);
答案 3 :(得分:1)
请记住对字符串使用相同的编码。尝试将两种语言的字符串转换为UTF-8,例如转换为编码的二进制数据:
PHP(s。utf8_encode()函数):
$strAndBlob = utf8_encode("My string");
爪哇:
String str = "My string";
byte[] blob = str.getBytes("utf-8");
PHP,例如,默认情况下不得使用UTF-8。