使用Rijndael_256(AES)从PHP mcrypt解密Java中的数据

时间:2014-05-08 10:42:06

标签: java php encryption aes mcrypt

有几天我一直试图将PHP服务中的加密数据发送到我的Android应用程序。我想使用Rijndael 256位加密。

在PHP中加密和解密字符串工作正常。 我所做的是我将数据从php发送到android中 以下结构=(初始化向量+哈希(md5)+加密数据)。

在Java中,我将收到的字符串拆分为3个隔间。

但是我在java中得到的是一条错误消息告诉:IV必须是16个字节长。 我检查了整个互联网,试图找到解决这个问题的方法。 有人建议不要在php中使用mcrypt,而有些人则建议使用128算法变体。在PHP中使用128位会破坏加密。

下面我有两个例子可能会进一步澄清问题。

感谢您的帮助。

PHP CODE加密/解密:

   function encrypt_data($data,$privk)
{
// Random number for feeding into AES encyption algorithm
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
// Check if decrypted properly
$hash = md5($data);
// Encrypt the data using the privk and the iv
$encrypted = trim(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $privk, trim($data), MCRYPT_MODE_CBC, $iv));
$encode = base64_encode($encrypted);

$base64_iv = base64_encode($iv);

return $base64_iv.$hash.'='.$encode;
}
function decrypt_data($data,$privk)
{
// Split data into 3 variables: iv,hash,encdata
$arr = explode('=',$data,3);    
$iv  = base64_decode($arr[0]);
$hash = $arr[1];
$encdata = base64_decode($arr[2]);
// Decrypt using the 3 variables
$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $privk, trim($encdata), MCRYPT_MODE_CBC, $iv));

// Check integrity of decrypted data
$hdec = md5($decrypted);

if ($hdec == $hash)
{
    return $decrypted;
}
else
{
    return false;
}
}

JAVA解密:

    public String decryptJson(String data)
{
    String[] split= data.trim().split("=");

    byte[] iv = Base64.decode(split[0],3);      
    String hash = split[1];
    byte[] encd = Base64.decode(split[2],0);

    String skey  = "secretkeyfromdatabase";
    byte[] skeyb = skey.getBytes();

            try
            {                   
            IvParameterSpec ivspec = new IvParameterSpec(iv);
            SecretKeySpec skeyspec = new SecretKeySpec(skeyb,"AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

            cipher.init(Cipher.DECRYPT_MODE,skeyspec,ivspec);

            byte[] original = cipher.doFinal(encd);

            return original.toString();

            }
            catch(Exception ex)
            {
                ex.printStackTrace();
                return "ERROR! | "+ex+"IV:"+iv;
            }
}

2 个答案:

答案 0 :(得分:0)

好吧,你的一个问题是JCE不支持AES 256位(如果你不能改变JCE策略文件,最多128位)。要么为PHP使用128位加密,要么......

正如您在doc&#34中所看到的;如果需要更强大的算法(例如,具有256位密钥的AES),则必须获取JCE无限强度管辖权策略文件并将其安装在JDK中/ JRE"

用户有责任根据当地法规验证此操作是否允许。

答案 1 :(得分:-1)

“我看到它的长度是32个字节。有没有办法可以接受32字节的IV?”

没有。根本问题是mcrypt中的“Rijndael_256”是一个Rijndael变体,它使用256位块大小而不是所有AES版本中使用的128位块大小。除了mcrypt库之外,您将很难找到“Rijndeal_256”的任何实现。 (见How can I do this same encrypt/decrypt PHP function on iOS with Objective-C?

修改:Bouncy Castle实际上通过RijndaelEngine支持Rijndeal_256:Encryption in Android equivalent to php's MCRYPT_RIJNDAEL_256

“有人建议不要在php中使用mcrypt,而其他人则说使用128算法变种。”

这两个建议都是正确的。 mcrypt是一个可怕的库,但如果你需要,你可以使用“Rijndael_128”运行,其中 与AES128相同。

对您的代码的一些评论:您对逐字数据md5($data)进行哈希处理,但会对修剪过的明文trim($data)进行加密。您使用mcrypt的默认零填充但在Java中指定PKCS5Padding,这不起作用。当您使用CBC但在加密之后和解密之前没有身份验证时,您很可能会填充oracle攻击

“是的,我很擅长使用加密技术。” - 替代方案:

鉴于您目前的加密专业知识水平,您应该避免实施任何加密。而是使用高级库和协议。哪一个使用很大程度上取决于您的用例。例如,如果PHP代码在受信任的服务器上运行,而客户端上的Java代码则可以通过SSL / TLS连接到服务器(很可能使用 https )。 TLS连接将向客户端验证服务器,您可以使用basic http authentcation向服务器验证客户端。