最近在作項目中,遇到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