提及加密,個人第一印象就是電視劇各類密碼本破解解密的場景,這兩天在看加密相關的東西,作下筆記以便之後查看,也提供給你們個參考。java
本文是java加密的第一篇,主要講述下消息編碼Base64以及簡單的消息摘要算法MD5,SHA,MAC等,若是有不對的地方還望你們指正。
linux
消息編碼:Base64git
消息摘要:MD類,SHA類,MAC算法
對稱加密:DES,3DES,AESapache
非對稱加密:RSA,DH密鑰交換安全
數字簽名:RSA signature,DSA signatureide
明文-->加密算法--> 密文 --> 解密算法 --> 明文函數
一、jdk自身提供的加密類this
二、其餘提供加密的第三方jar包
Apache Commons Codec(簡稱CC),
Bouncy Castle(BC)編碼
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.57</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec --> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency>
消息摘要算法,可謂是非可逆加密,就是不可解密的加密方法也稱單向加密算法。固然如今網上也有大神將一些算法破解解密的例子,這只是特例。
爲何是使用base64編碼呢,由於嚴格地說,Base64屬於編碼格式,而非加密算法。我在網上有看到一個base64產生的背景,看完這個相信你們就會理解我說的這句話了。
Base64算法最先主要是解決電子郵件的傳輸問題,因爲當時的網關有個問題就是可能會使非ASCII碼字符的二進制位作調整,致使用戶收取的郵件變成亂碼,因此就出現了Base64算法。
什麼是base64算法?
按照RFC2045的定義,Base64被定義爲:Base64內容傳送編碼被設計用來把任意序列的8位字節描述爲一種不易被人直接識別的形式。
常見於郵件、http加密,截取http信息,你就會發現登陸操做的用戶名、密碼字段經過BASE64加密的。
算法流程:
明文-->Base64加密--> 密文 --> Base64解密 --> 明文
代碼實現:
base64目前主要是經過jdk自帶的類實現,也有BC和CC等第三方的解決方案,根據個人瞭解,BC是對jdk的補充,CC主要是對jdk操做的簡化,你們能夠在後面的代碼中看到的。
package checkcode; import org.apache.commons.codec.binary.Base64; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; /** * {@link http://www.cnblogs.com/allanzhang/} * @author 小賣鋪的老爺爺 * */ public class Base64Test { public static final String src = "laoyeye base64"; public static void main(String[] args) { jdkBase64(); commonsCodesBase64(); bouncyCastleBase64(); } // 用jdk實現 public static void jdkBase64() { try { BASE64Encoder encoder = new BASE64Encoder(); String encode = encoder.encode(src.getBytes()); System.out.println("encode:" + encode); BASE64Decoder decoder = new BASE64Decoder(); System.out.println("decode:" + new String(decoder.decodeBuffer(encode))); } catch (Exception e) { e.printStackTrace(); } } // 用Apache的common codes實現 public static void commonsCodesBase64() { byte[] encodeBytes = Base64.encodeBase64(src.getBytes()); System.out.println("common codes encode:" + new String(encodeBytes)); byte[] dencodeBytes = Base64.decodeBase64(encodeBytes); System.out.println("common codes decode:" + new String(dencodeBytes)); } // 用bouncy castle實現 public static void bouncyCastleBase64() { byte[] encodeBytes = org.bouncycastle.util.encoders.Base64.encode(src.getBytes()); System.out.println("bouncy castle encode:" + new String(encodeBytes)); byte[] dencodeBytes = org.bouncycastle.util.encoders.Base64.decode(encodeBytes); System.out.println("bouncy castle decode:" + new String(dencodeBytes)); } }
效果圖:
注:BASE加密後產生的字節位數是8的倍數,若是不夠位數以=符號填充。
MD算法目前使用最多的大概就是MD5了吧,MD5的全稱是Message-Digest Algorithm 5(信息-摘要算法),在90年代初由MIT Laboratory for Computer Science和RSA Data Security Inc的Ronald L. Rivest開發出來,經MD2和MD4等發展而來。目前jdk提供了MD2和MD5的實現,對於MD4咱們須要藉助BC來實現。如今MD普遍用於加密和解密技術,經常使用於文件校驗。無論文件多大,通過MD後都能生成惟一的MD值。比如如今的ISO校驗,都是MD校驗。怎麼用?固然是把ISO通過MD後產生MD的值。通常下載linux-ISO的朋友都見過下載連接旁邊放着MD的串。就是用來驗證文件是否一致的。
加密流程:
明文-->MD加密--> 密文--> 接收者
明文-->接收者--> MD加密--> 密文--> 比較驗證
代碼實現:
package checkcode; import java.security.MessageDigest; import java.security.Security; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; import org.bouncycastle.crypto.digests.MD4Digest; import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.jce.provider.BouncyCastleProvider; /** * {@link http://www.cnblogs.com/allanzhang/} * @author 小賣鋪的老爺爺 * */ public class MD5Test { public static final String src = "laoyeye md5"; public static void main(String[] args) { jdkMD5(); jdkMD2(); bcMD4(); bcMD5(); bc2jdkMD4(); ccMD5(); ccMD2(); } // 用jdk實現:MD5 public static void jdkMD5() { try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] md5Bytes = md.digest(src.getBytes()); System.out.println("JDK MD5:" + Hex.encodeHexString(md5Bytes)); } catch (Exception e) { e.printStackTrace(); } } // 用jdk實現:MD2 public static void jdkMD2() { try { MessageDigest md = MessageDigest.getInstance("MD2"); byte[] md2Bytes = md.digest(src.getBytes()); System.out.println("JDK MD2:" + Hex.encodeHexString(md2Bytes)); } catch (Exception e) { e.printStackTrace(); } } // 用bouncy castle實現:MD5 public static void bcMD5() { MD5Digest digest = new MD5Digest(); digest.update(src.getBytes(),0,src.getBytes().length); byte[] md5Bytes = new byte[digest.getDigestSize()]; digest.doFinal(md5Bytes, 0); System.out.println("bouncy castle MD5:" + Hex.encodeHexString(md5Bytes)); } // 用bouncy castle實現:MD4 public static void bcMD4() { MD4Digest digest = new MD4Digest(); digest.update(src.getBytes(),0,src.getBytes().length); byte[] md4Bytes = new byte[digest.getDigestSize()]; digest.doFinal(md4Bytes, 0); System.out.println("bouncy castle MD4:" + Hex.encodeHexString(md4Bytes)); } // 用bouncy castle與jdk結合實現:MD4 public static void bc2jdkMD4() { try { Security.addProvider(new BouncyCastleProvider()); MessageDigest md = MessageDigest.getInstance("MD4"); byte[] md4Bytes = md.digest(src.getBytes()); System.out.println("bc and JDK MD4:" + Hex.encodeHexString(md4Bytes)); } catch (Exception e) { e.printStackTrace(); } } // 用common codes實現實現:MD5 public static void ccMD5() { System.out.println("common codes MD5:" + DigestUtils.md5Hex(src.getBytes())); } // 用common codes實現實現:MD2 public static void ccMD2() { System.out.println("common codes MD2:" + DigestUtils.md2Hex(src.getBytes())); } }
SHA如今主要有SHA1和SHA2兩大類,SH2又分好多種,你們能夠網上看下。SHA,被普遍地應用於電子商務等信息安全領域。雖然,SHA與MD5經過碰撞法都被破解了, 可是SHA仍然是公認的安全加密算法,較之MD5更爲安全。
加密流程:
明文-->SHA加密--> 密文--> 接收者
明文-->接收者--> SHA加密--> 密文--> 比較驗證
代碼實現:
package checkcode; import java.math.BigInteger; import java.security.MessageDigest; import java.security.Security; 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.bouncycastle.crypto.digests.SHA224Digest; import org.bouncycastle.jce.provider.BouncyCastleProvider; /** * {@link http://www.cnblogs.com/allanzhang/} * @author 小賣鋪的老爺爺 * */ public class SHATest { public static final String src = "laoyeye sha"; public static void main(String[] args) { jdkSHA1(); bcSHA1(); bcSHA224(); bcSHA224b(); generateSha256(); ccSHA1(); } // 用jdk實現:SHA1 public static void jdkSHA1() { try { MessageDigest md = MessageDigest.getInstance("SHA"); md.update(src.getBytes()); System.out.println("jdk sha-1:" + Hex.encodeHexString(md.digest())); } catch (Exception e) { e.printStackTrace(); } } // 用bouncy castle實現:SHA1 public static void bcSHA1() { Digest digest = new SHA1Digest(); digest.update(src.getBytes(), 0, src.getBytes().length ); byte[] sha1Bytes = new byte[digest.getDigestSize()]; digest.doFinal(sha1Bytes, 0); System.out.println("bc sha-1:" + org.bouncycastle.util.encoders.Hex.toHexString(sha1Bytes)); } // 用bouncy castle實現:SHA224 public static void bcSHA224() { Digest digest = new SHA224Digest(); digest.update(src.getBytes(), 0, src.getBytes().length ); byte[] sha224Bytes = new byte[digest.getDigestSize()]; digest.doFinal(sha224Bytes, 0); System.out.println("bc sha-224:" + org.bouncycastle.util.encoders.Hex.toHexString(sha224Bytes)); } // 用bouncy castle與jdk結合實現:SHA224 public static void bcSHA224b() { try { Security.addProvider(new BouncyCastleProvider()); MessageDigest md = MessageDigest.getInstance("SHA224"); md.update(src.getBytes()); System.out.println("bc and JDK sha-224:" + Hex.encodeHexString(md.digest())); } catch (Exception e) { e.printStackTrace(); } } public static void generateSha256() { MessageDigest md = null; try { md = MessageDigest.getInstance("SHA-256"); md.update(src.getBytes("UTF-8")); // Change this to "UTF-16" if needed } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } byte[] digest = md.digest(); BigInteger bigInt = new BigInteger(1, digest); System.out.println("Sha256 hash: " + bigInt.toString(16)); } // 用common codes實現實現:SHA1 public static void ccSHA1() { System.out.println("common codes SHA1 - 1 :" + DigestUtils.sha1Hex(src.getBytes())); System.out.println("common codes SHA1 - 2 :" + DigestUtils.sha1Hex(src)); } }
效果圖:
SHA與MD的比較
由於兩者均由MD導出,SHA和MD彼此很類似。相應的,他們的強度和其餘特性也是類似,但還有如下幾點不一樣:
對強行攻擊的安全性:最顯著和最重要的區別是SHA-摘要比MD摘要長。使用強行技術,產生任何一個報文使其摘要等於給定報摘要的難度對MD是2^128數量級的操做,而對SHA則是2^160數量級的操做。這樣,SHA對強行攻擊有更大的強度。
對密碼分析的安全性:因爲MD的設計,易受密碼分析的攻擊,SHA顯得不易受這樣的攻擊。
速度:在相同的硬件上,SHA的運行速度比MD慢。
基於密鑰的Hash算法的認證協議。消息鑑別碼實現鑑別的原理是,用公開函數和密鑰產生一個固定長度的值做爲認證標識,用這個 標識鑑別消息的完整性。使用一個密鑰生成一個固定大小的小數據塊,即MAC,並將其加入到消息中,而後傳輸。接收方利用與發送方共享的密鑰進行鑑別認證等。
加密流程:
構建祕鑰-->發送祕鑰--> 接收者
明文-->HMAC算法+祕鑰加密--> 密文--> 接收者
明文-->接收者--> HMAC算法+祕鑰加密--> 密文--> 比較驗證
代碼實現:
package checkcode; import javax.crypto.KeyGenerator; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Hex; import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.params.KeyParameter; /** * {@link http://www.cnblogs.com/allanzhang/} * @author 小賣鋪的老爺爺 * */ public class HMACTest { public static final String src = "laoyeye hmac"; public static void main(String[] args) { jdkHmacMD5(); bcHmacMD5(); } // 用jdk實現: public static void jdkHmacMD5() { try { // 初始化KeyGenerator KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5"); // 產生密鑰 SecretKey secretKey = keyGenerator.generateKey(); //一、 獲取密鑰 // byte[] key = secretKey.getEncoded(); //二、使用固定祕鑰 byte[] key = Hex.decodeHex(new char[]{'1','2','3','4','5','6','7','8','9','a','b','c','d','e' }); // 還原密鑰 SecretKey restoreSecretKey = new SecretKeySpec(key, "HmacMD5"); // 實例化MAC Mac mac = Mac.getInstance(restoreSecretKey.getAlgorithm()); // 初始化MAC mac.init(restoreSecretKey); // 執行摘要 byte[] hmacMD5Bytes = mac.doFinal(src.getBytes()); System.out.println("jdk hmacMD5:" + Hex.encodeHexString(hmacMD5Bytes)); } catch (Exception e) { e.printStackTrace(); } } // 用bouncy castle實現: public static void bcHmacMD5() { HMac hmac = new HMac(new MD5Digest()); // 必須是16進制的字符,長度必須是2的倍數 hmac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex.decode("123456789abcde"))); hmac.update(src.getBytes(), 0, src.getBytes().length); // 執行摘要 byte[] hmacMD5Bytes = new byte[hmac.getMacSize()]; hmac.doFinal(hmacMD5Bytes, 0); System.out.println("bc hmacMD5:" + org.bouncycastle.util.encoders.Hex.toHexString(hmacMD5Bytes)); } }
注:還原祕鑰是將jdk初始化的密鑰轉換爲符合特定算法規則的密鑰,只要有密鑰的算法,在加密步驟以前都須要進行還原密鑰操做,來做爲加密與解密操做時的參數.
效果圖:
總結:
BASE64的加密解密是雙向的,能夠得出明文和密文。
MD五、SHA以及HMAC是單向加密,任何數據加密後只會產生惟一的一個加密串,一般用來校驗數據在傳輸過程當中是否被修改。其中HMAC算法有一個密鑰,加強了數據傳輸過程當中的安全性,強化了算法外的不可控因素。
單向加密的用途主要是爲了校驗數據在傳輸過程當中是否被修改。
源碼地址:https://git.oschina.net/allanzhang/checkcode.git