數據摘要算法是密碼學算法中非常重要的一個分支,它通過對所有數據提取指紋信息以實現數據簽名、數據完整性校驗等功能,由於其不可逆性,有時候會被用做敏感信息的加密。數據摘要算法也被稱為哈希(Hash)算法、散列算法。今天,我們就開始java中摘要算法的學習。
項目結構如下:
SHA算法
安全哈希算法(Secure Hash Algorithm)主要適用於數字簽名標准(Digital Signature Standard DSS)里面定義的數字簽名算法(Digital Signature Algorithm DSA)。對於長度小於2^64位的消息,SHA1會產生一個160位的消息摘要。該算法經過加密專家多年來的發展和改進已日益完善,並被廣泛使用。該算法的思想是接收一段明文,然后以一種不可逆的方式將它轉換成一段(通常更小)密文,也可以簡單的理解為取一串輸入碼(稱為預映射或信息),並把它們轉化為長度較短、位數固定的輸出序列即散列值(也稱為信息摘要或信息認證代碼)的過程。散列函數值可以說是對明文的一種“指紋”或是“摘要”所以對散列值的數字簽名就可以視為對此明文的數字簽名。
一、 HuhxSHA.java
package com.huhx.md; import java.security.MessageDigest; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA1Digest; import org.junit.Test; /** * wirter: huhx */ public class HuhxSHA { private static String src = "http://www.cnblogs.com/huhx"; // jdk版本的sha算法 @Test public void jdkSHA1() { try { MessageDigest messageDigest = MessageDigest.getInstance("SHA"); messageDigest.update(src.getBytes()); byte[] shaBytes = messageDigest.digest(); System.out.println("jdk SHA 1: " + Hex.encodeHexString(shaBytes)); } catch (Exception e) { e.printStackTrace(); } } // commons-codec的sha算法 @Test public void bcSHA1() { Digest digest = new SHA1Digest(); digest.update(src.getBytes(), 0, src.length()); byte[] shaBytes = new byte[digest.getDigestSize()]; digest.doFinal(shaBytes, 0); System.out.println("bc SHA 1: " + org.bouncycastle.util.encoders.Hex.toHexString(shaBytes)); } // bcprov的sha算法 @Test public void ccSHA1() { System.out.println("cc SHA 1: " + DigestUtils.sha1Hex(src.getBytes())); } }
二、 運行結果如下:
jdk SHA 1: 14ed5f04b940042df8dfcd5e60dc331dfddac16f bc SHA 1: 14ed5f04b940042df8dfcd5e60dc331dfddac16f cc SHA 1: 14ed5f04b940042df8dfcd5e60dc331dfddac16f
MD算法
MD2
Rivest在1989年開發出MD2算法。在這個算法中,首先對信息進行數據補位,使信息的字節長度是16的倍數。然后,以一個16位的檢驗和追加到信息末尾,並且根據這個新產生的信息計算出散列值。后來,Rogier和Chauvaud發現如果忽略了檢驗將和MD2產生沖突。MD2算法加密后結果是唯一的(即不同信息加密后的結果不同)。
MD4
為了加強算法的安全性,Rivest在1990年又開發出MD4算法。MD4算法同樣需要填補信息以確保信息的比特位長度減去448后能被512整除(信息比特位長度mod 512 = 448)。然后,一個以64位二進制表示的信息的最初長度被添加進來。信息被處理成512位damg?rd/merkle迭代結構的區塊,而且每個區塊要通過三個不同步驟的處理。Den boer和Bosselaers以及其他人很快的發現了攻擊MD4版本中第一步和第三步的漏洞。Dobbertin向大家演示了如何利用一部普通的個人電腦在幾分鍾內找到MD4完整版本中的沖突(這個沖突實際上是一種漏洞,它將導致對不同的內容進行加密卻可能得到相同的加密后結果)。毫無疑問,MD4就此被淘汰掉了。盡管MD4算法在安全上有個這么大的漏洞,但它對在其后才被開發出來的好幾種信息安全加密算法的出現卻有着不可忽視的引導作用。
MD5
1991年,Rivest開發出技術上更為趨近成熟的md5算法。它在MD4的基礎上增加了"安全-帶子"(safety-belts)的概念。雖然MD5比MD4復雜度大一些,但卻更為安全。這個算法很明顯的由四個和MD4設計有少許不同的步驟組成。在MD5算法中,信息-摘要的大小和填充的必要條件與MD4完全相同。Den boer和Bosselaers曾發現MD5算法中的假沖突(pseudo-collisions),但除此之外就沒有其他被發現的加密后結果了。
一、 HuhxMD.java
package com.huhx.md; import java.security.MessageDigest; import java.security.Security; import org.apache.commons.codec.digest.DigestUtils; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.encoders.Hex; import org.junit.Test; public class HuhxMD { private static String src = "http://www.cnblogs.com/huhx"; @Test public void jdkMD5() { try { MessageDigest messageDigest = MessageDigest.getInstance("MD5"); byte[] mdBytes = messageDigest.digest(src.getBytes()); System.out.println("md5 decode: " + Hex.toHexString(mdBytes)); } catch (Exception e) { e.printStackTrace(); } } @Test public void jdkMD2() { try { MessageDigest messageDigest = MessageDigest.getInstance("MD2"); byte[] mdBytes = messageDigest.digest(src.getBytes()); System.out.println("md2 decode: " + Hex.toHexString(mdBytes)); } catch (Exception e) { e.printStackTrace(); } } @Test public void bcmMD4() { // Digest digest = new MD4Digest(); // digest.update(src.getBytes(), 0, src.length()); // byte[] mdBytes = new byte[digest.getDigestSize()]; // digest.doFinal(mdBytes, 0); // System.out.println("md4 decode: " + Hex.toHexString(mdBytes)); Security.addProvider(new BouncyCastleProvider()); try { MessageDigest messageDigest = MessageDigest.getInstance("MD4"); byte[] mdBytes = messageDigest.digest(src.getBytes()); System.out.println("md4 decode: " + Hex.toHexString(mdBytes)); } catch (Exception e) { e.printStackTrace(); } } // @Test public void bcmMD5() { Digest digest = new MD5Digest(); digest.update(src.getBytes(), 0, src.length()); byte[] mdBytes = new byte[digest.getDigestSize()]; digest.doFinal(mdBytes, 0); System.out.println("md5 decode: " + Hex.toHexString(mdBytes)); } // @Test public void ccMD5() { String md5String = DigestUtils.md5Hex(src.getBytes()); System.out.println("common md5: " + md5String); } }
二、 運行結果如下:
md4 decode: b402321e9a067da3df0c36c8315f8e38
md5 decode: f121bf5f7491466ae75e056f686c4462
md2 decode: 42b6b066b1273470f9aad644cede7644
md5 decode: f121bf5f7491466ae75e056f686c4462
common md5: f121bf5f7491466ae75e056f686c4462
由於md5的算法被發現了某些微妙的規律性。所以建議最好使用ShA1的算法。
MAC算法
MAC算法 (Message Authentication Codes) 帶秘密密鑰的Hash函數:消息的散列值由只有通信雙方知道的秘密密鑰K來控制。此時Hash值稱作MAC。
MAC算法原理(以直聯銀聯pos和POS中心通訊為例)。
- 將欲發送給POS中心的消息中,從消息類型(MTI)到63域之間的部分構成MAC ELEMEMENT BLOCK (MAB)。
- 對MAB,按每8個字節做異或(不管信息中的字符格式),如果最后不滿8個字節,則添加“0X00”。
一、 HuhxMAC.java
package com.huhx.md; import javax.crypto.KeyGenerator; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.util.encoders.Hex; import org.junit.Test; public class HuhxMAC { private static String src = "http://www.cnblogs.com/huhx"; private static String decodeKey = "bbbbbbbbbb"; @Test public void jdkHmacMD5() { try { // 初始化KeyGenerator KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5"); // 產生密鑰 SecretKey secretKey = keyGenerator.generateKey(); // 獲得密鑰 // byte[] keyBytes = secretKey.getEncoded(); byte[] keyBytes = org.apache.commons.codec.binary.Hex.decodeHex(decodeKey.toCharArray()); // 還原密鑰 SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "HmacMD5"); // 實例化MAC Mac mac = Mac.getInstance(secretKeySpec.getAlgorithm()); // 初始化Mac mac.init(secretKeySpec); // 執行摘要 byte[] result = mac.doFinal(src.getBytes()); System.out.println("jdk mac: " + Hex.toHexString(result)); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Test public void bcHmacMD5() { HMac hMac = new HMac(new MD5Digest()); hMac.init(new KeyParameter(Hex.decode(decodeKey))); hMac.update(src.getBytes(), 0, src.length()); byte[] hMacBytes = new byte[hMac.getMacSize()]; hMac.doFinal(hMacBytes, 0); System.out.println("bc mac: " + Hex.toHexString(hMacBytes)); } }
二、 運行結果如下:
bc mac: 3bf59d550b1e0d6cee15e015870029f9
jdk mac: 3bf59d550b1e0d6cee15e015870029f9
友情鏈接