原文地址: http://weavesky.com/2008/01/05/java-3des/
最近一個合作商提出使用3DES交換數據,本來他們有現成的代碼,可惜只有.net版本,我們的服務器都是Linux,而且應用都是Java。於是對照他們提供的代碼改了一個Java的版本出來,主要是不熟悉3DES,折騰了一天,終於搞定。
所謂3DES,就是把DES做三次,當然不是簡單地DES DES DES就行了,中途有些特定的排列。這個我可不關心,呵呵,我的目的是使用它。
在網上搜索了一下3DES,找到很少資料。經過朋友介紹,找到GNU Crypto和Bouncy Castle兩個Java擴充包,里面應該有3DES的實現吧。
從GNU Crypto入手,找到一個TripleDES的實現類,發現原來3DES還有一個名字叫DESede,在網上搜索TripleDES和DESede,呵呵,終於發現更多的資料了。
Java的安全API始終那么難用,先創建一個cipher看看算法在不在吧
Cipher cipher = Cipher.getInstance("DESede");
如果沒有拋異常的話,就證明這個算法是有效的
突然想看看JDK有沒有內置DESede,於是撇開Crypto,直接測試,發現可以正確運行。在jce.jar里面找到相關的類,JDK內置了。
於是直接用DES的代碼來改&測試,最后代碼變成這樣
SecureRandom sr = new SecureRandom();
DESedeKeySpec dks = new DESedeKeySpec(PASSWORD_CRYPT_KEY.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey securekey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
return new String(Hex.encodeHex(cipher.doFinal(str.getBytes())));
需要留意的是,要使用DESede的Spec、Factory和Cipher才行
事情還沒完結,合作商給過來的除了密鑰之外,還有一個IV向量。搜索了一下,發現有一個IvParameterSpec類,於是代碼變成這樣
SecureRandom sr = new SecureRandom();
DESedeKeySpec dks = new DESedeKeySpec(PASSWORD_CRYPT_KEY.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey securekey = keyFactory.generateSecret(dks);
IvParameterSpec iv = new IvParameterSpec(PASSWORD_IV.getBytes());
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, securekey, iv, sr);
return new String(Hex.encodeHex(cipher.doFinal(str.getBytes())));
但是,運行報錯了
java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
ECB是什么呢?我的代碼完全沒有寫ECB什么的
又上網搜索,結果把DES的來龍去脈都搞清楚了
http://www.tropsoft.com/strongenc/des.htm
ECB是其中一種字串分割方式,除了DES以外,其他加密方式也會使用這種分割方式的,而Java默認產生的DES算法就是用ECB方法,ECB不需要向量,當然也就不支持向量了
除了ECB,DES還支持CBC、CFB、OFB,而3DES只支持ECB和CBC兩種
http://www.tropsoft.com/strongenc/des3.htm
CBC支持並且必須有向量,具體算法這里就不說了。合作商給的.net代碼沒有聲明CBC模式,似乎是.net默認的方式就是CBC的
於是把模式改成CBC
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
成功運行了
后話:
搜索的過程中,找到一個不錯的討論
http://www.lslnet.com/linux/dosc1/21/linux-197579.htm 在CBC(不光是DES算法)模式下,iv通過隨機數(或偽隨機)機制產生是一種比較常見的方法。iv的作用主要是用於產生密文的第一個block,以使最終生成的密文產生差異(明文相同的情況下),使密碼攻擊變得更為困難,除此之外iv並無其它用途。因此iv通過隨機方式產生是一種十分簡便、有效的途徑。此外,在IPsec中采用了DES-CBC作為缺省的加密方式,其使用的iv是通訊包的時間戳。從原理上來說,這與隨機數機制並無二致。
看來,向量的作用其實就是salt
最大的好處是,可以令到即使相同的明文,相同的密鑰,能產生不同的密文
例如,我們用DES方式在數據保存用戶密碼的時候,可以另外增加一列,把向量同時保存下來,並且每次用不同的向量。這樣的好處是,即使兩個用戶的密碼是一樣的,數據庫保存的密文,也會不一樣,就能降低猜測的可能性
另外一種用法,就是類似IPsec的做法,兩部主機互傳數據,保證兩部機的時鍾同步的前提下(可以取樣到分鍾或更高的單位避免偏差),用時鍾的變化值作為向量,就能增加被sniffer數據的解密難度
