最近在作项目中,遇到des加密解密的问题。php
场景是安卓app端用des加密,php这边须要解密。以前没有接触过des这种加密解密算法,但想着确定会有demo。所以百度,搜了代码来用。网上代码也是鱼龙混杂,好不容易测试在php这边测试加密和解密成功了。为确保安卓app端提交过来的加密参数可以解密出来,给定安卓人员一个字符串,让他们把des加密后的字符串给我,在php这边解密。结果一看,加密出来的字符串跟我这边加密出来的结果不一致,天然是解密不出来。java
要来java的des算法代码,研究加密的过程,其中各类调试测试,外加各类百度,必应。发现可以正确解密的规则,其中很是重要的三点就是,加密解密过程,双方的key、加密模式(例如ECB、CBC等),以及iv(有些地方叫它偏移量,有些地方叫它向量,没有深刻研究)须要一致。须要着重说明的是这个iv,在ECB加密模式(java默认的加密模式)时,是不须要这个iv的,即便写了,也不会影响加密的结果;而当加密模式为CBC时,则须要iv这个参数,不然会随机生成该参数,这样每次加密的结果会变。而关键在于,java端定义了iv,那么php这边也须要跟java端保持一致,这样才可以正确解密出来。算法
后面就胶着在这个iv上面。查看java端代码,iv是一个byte[],即字节数组,想都没有想就去网上找php将字符串转化为byte[]类型的,也试过强制转换,解密失败。最后才想起来去看php的数据类型,呃呃呃,压根就没有type类型的。真是基础不牢,又想固然,以为java有该数据类型,php也会有。。。惯性思惟真的害人啊。这怎么办呢?既须要byte[]去解密,又没有该数据数据类型,已经感受无解了。数组
一般这个时候,须要休息,休息一下子。后面忽然念头闪过,php中有函数能够des解密,该函数确定不会用php没有的数据类型去解密,因此我试着将java加密中转换成byte[]类型前的字符串做为php的iv,测试,终于解密成功。app
附上java端加密代码,采用CBC模式:函数
import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import javax.crypto.spec.IvParameterSpec; public class DES { //加密数据入口 public static String encryptString(String message, String key) throws Exception { byte[] bytes = encrypt(message, key); return toHexString(bytes).toUpperCase(); } public static byte[] encrypt(String message, String key) throws Exception { Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8")); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey = keyFactory.generateSecret(desKeySpec); IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8")); cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); return cipher.doFinal(message.getBytes("UTF-8")); } }
附上对应的php端解密代码:测试
class DES { public static function decrypt($str, $key) { $midstr = hex2bin(strtolower($str)); //第二个参数$key就是三个重点中的$key,而最后一个参数$key是iv,只是java加密时采用了与第二个参数相同的字符串,根据具体状况来定就好 $str = mcrypt_decrypt(MCRYPT_DES, $key, $midstr, MCRYPT_MODE_CBC, $key);
$pad = ord($str[($len = strlen($str)) - 1]); return substr($str, 0, strlen($str) - $pad); } }
其中hex2bin是将十六进制转换成二进制,php自带该函数,不须要再另行定义(网上看到不少该函数的代码)。解密能够看做是加密的逆操做,因此java端将加密后字符串转成十六进制,并大写,解密时天然须要转换回来。加密
能够看看下面这个连接,写得不错:url