有几天我一直试图将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;
}
}
答案 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向服务器验证客户端。