1 sha加密:
安全雜湊演算法(Secure Hash Algorithm)主要適用於數位簽章標準 (DSS)(Digital Signature Standard DSS)裡面定義的數位簽章演算法(Digital Signature Algorithm DSA)。對於長度小於2^64位的訊息,SHA1會產生一個160位的訊息摘要。該演算法經過加密專家多年來的發展和改進已日益完善,並被廣泛使用。該演算法的思想是接收一段明文,然後以一種無法復原的方式將它轉換成一段(通常更小)密文,也可以簡單的理解為取一串輸入碼(稱為預映射或資訊),並把它們轉化為長度較短、位元固定的輸出序列即散列值(也稱為資訊摘要或資訊認證代碼)的過程。散列函數值可以說是對明文的一種“指紋”或是“摘要”所以對散列值的數位簽章就可以視為對此明文的數位簽章。
安全散列演算法SHA (Secure Hash Algorithm,SHA) 是美國國家標準技術研究所發布的國家標準FIPS PUB 180,最新的標準已經於2008年更新到FIPS PUB 180-3。其中規定了SHA-1,SHA-224,SHA-256,SHA-384,和SHA-512這幾種 單向散列演算法。SHA-1,SHA-224和SHA-256適用於長度不超過2^64二進位位的訊息。SHA-384和SHA-512適用於長度不超過2^128二進位位的訊息。 散列演算法 散列是資訊的提煉,通常其長度要比資訊小得多,且為一個固定長度。加密性強的散列一定是無法復原的,這就意味著通過散列結果,無法推出任何部分的原始資訊。任何輸入資訊的變化,哪怕僅一位,都將導致散列結果的明顯變化,這稱之為雪崩效應。散列還應該是防衝突的,即找不出具有相同散列結果的兩條資訊。具有這些特性的散列結果就可以用於驗證資訊是否被修改。 單向散列函數一般用於產生 訊息摘要,祕密金鑰加密等,常見的有: l MD5(Message Digest Algorithm 5):是RSA資料安全公司開發的一種 單向散列演算法。 l SHA(Secure Hash Algorithm):可以對任意長度的資料運算產生一個160位的數值; SHA-1 在1993年,安全散列演算法(SHA)由美國國家標準和技術協會(NIST)提出,並作為聯邦資訊處理標準(FIPS PUB 180)公布;1995年又發布了一個修訂版FIPS PUB 180-1,通常稱之為SHA-1。SHA-1是基於MD4演算法的,並且它的設計在很大程度上是模仿MD4的。現在已成為公認的最安全的散列演算法之一,並被廣泛使用。 原理 SHA-1是一種 資料加密演算法,該演算法的思想是接收一段明文,然後以一種無法復原的方式將它轉換成一段(通常更小)密文,也可以簡單的理解為取一串輸入碼(稱為預映射或資訊),並把它們轉化為長度較短、位元固定的輸出序列即散列值(也稱為資訊摘要或資訊認證代碼)的過程。 單向散列函數的安全性在於其產生散列值的操作過程具有較強的單向性。如果在輸入序列中嵌入密碼,那麼任何人在不知道密碼的情況下都不能產生正確的散列值,從而保證了其安全性。SHA將輸入資料流按照每塊512位(64個位元組)進行分塊,併產生20個位元組的被稱為資訊認證代碼或資訊摘要的輸出。 該演算法輸入 報文的長度不限,產生的輸出是一個160位的 報文摘要。輸入是按512 位的分組進行處理的。SHA-1是無法復原的、防衝突,並具有良好的雪崩效應。 通過散列演算法可實現 數位簽章實現,數位簽章的原理是將要傳送的明文通過一種函數運算(Hash)轉換成報文摘要(不同的明文對應不同的報文摘要),報文摘要加密後與明文一起傳送給接受方,接受方將接受的明文產生新的報文摘要與發送方的發來報文摘要解密比較,比較結果一致表示明文未被改動,如果不一致表示明文已被篡改。 MAC (資訊認證代碼)就是一個散列結果,其中部分輸入資訊是密碼,只有知道這個密碼的參與者才能再次計算和驗證MAC碼的合法性。 SHA-1與MD5的比較 因為二者均由MD4匯出,SHA-1和MD5彼此很相似。相應的,他們的強度和其他特性也是相似,但還有以下幾點不同: l 對強行攻擊的安全性:最顯著和最重要的區別是SHA-1摘要比MD5摘要長32 位。使用強行技術,產生任何一個 報文使其摘要等於給定報摘要的難度對MD5是2^128數量級的操作,而對SHA-1則是2^160數量級的操作。這樣,SHA-1對強行攻擊有更大的強度。 l 對密碼分析的安全性:由於MD5的設計,易受密碼分析的攻擊,SHA-1顯得不易受這樣的攻擊。 l 速度:在相同的硬體上,SHA-1的運行速度比MD5慢。
JAVA 已經實現了 SHA-256 和 SHA-512 兩種 Hash 演算法
利用 java.security.MessageDigest 調用已經整合的 Hash 演算法
建立 Encrypt 對象,並調用 SHA256 或者 SHA512 並傳入要加密的文本資訊,分別得到 SHA-256 或 SHA-512 兩種被加密的 hash 串。
若要改為 MD5 演算法,修改傳入參數 strType 為 "MD5" 即可得到 MD5 加密功能。
/** * @file Encrypt.java * @date 2016年8月5日 * @version 3.4.1 * * Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved. */package encrypt; /** * * * @author chengjian.he * @version 3.4, 2016年8月5日 上午10:05:37 * @since */import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;public class Encrypt{ /** * 傳入常值內容,返回 SHA-256 串 * * @param strText * @return */ public String SHA256(final String strText) { return SHA(strText, "SHA-256"); } /** * 傳入常值內容,返回 SHA-512 串 * * @param strText * @return */ public String SHA512(final String strText) { return SHA(strText, "SHA-512"); } /** * 字串 SHA 加密 * * @param strSourceText * @return */ private String SHA(final String strText, final String strType) { // 傳回值 String strResult = null; // 是否是有效字串 if (strText != null && strText.length() > 0) { try { // SHA 加密開始 // 建立加密對象 並傳入加密類型 MessageDigest messageDigest = MessageDigest.getInstance(strType); // 傳入要加密的字串 messageDigest.update(strText.getBytes()); // 得到 byte 類型結果 byte byteBuffer[] = messageDigest.digest(); // 將 byte 轉換爲 string StringBuffer strHexString = new StringBuffer(); // 遍歷 byte buffer for (int i = 0; i < byteBuffer.length; i++) { String hex = Integer.toHexString(0xff & byteBuffer[i]); if (hex.length() == 1) { strHexString.append('0'); } strHexString.append(hex); } // 得到返回結果 strResult = strHexString.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } return strResult; } public static void main(String args[]){ Encrypt ey = new Encrypt(); System.out.println(ey.SHA("ILoveYou", "MD5"));//62accaf23ac9a73c0b28765b7dfaf75a }}
2 Base64
Base64是網路上最常見的用於傳輸8Bit位元組代碼的編碼方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的詳細規範。Base64編碼可用於在HTTP環境下傳遞較長的標識資訊。例如,在Java Persistence系統Hibernate中,就採用了Base64來將一個較長的唯一識別碼(一般為128-bit的UUID)編碼為一個字串,用作HTTP表單和HTTP GET URL中的參數。在其他應用程式中,也常常需要把位元據編碼為適合放在URL(包括隱藏表單域)中的形式。此時,採用Base64編碼具有不可讀性,即所編碼的資料不會被人用肉眼所直接看到。
然而,標準的Base64並不適合直接放在URL裡傳輸,因為URL編碼器會把標準Base64中的“/”和“+”字元變為形如“%XX”的形式,而這些“%”號在存入資料庫時還需要再進行轉換,因為ANSI SQL中已將“%”號用作萬用字元。 為解決此問題,可採用一種用於URL的改進Base64編碼,它不僅在末尾填充'='號,並將標準Base64中的“+”和“/”分別改成了“-”和“_”,這樣就免去了在URL編解碼和資料庫儲存時所要作的轉換,避免了編碼資訊長度在此過程中的增加,並統一了資料庫、表單等處對象 標識符的格式。 另有一種用於Regex的改進Base64變種,它將“+”和“/”改成了“!”和“-”,因為“+”,“*”以及前面在IRCu中用到的“[”和“]”在Regex中都可能具有特殊含義。 此外還有一些變種,它們將“+/”改為“_-”或“._”(用作程式設計語言中的標識符名稱)或“.-”(用於XML中的Nmtoken)甚至“_:”(用於XML中的Name)。 其他應用 Mozilla Thunderbird和Evolution用Base64來保密電子郵件密碼 Base64 也會經常用作一個簡單的“加密”來保護某些資料,而真正的加密通常都比較繁瑣。 垃圾訊息傳播者用Base64來避過反垃圾郵件工具,因為那些工具通常都不會翻譯Base64的訊息。 在LDIF檔案,Base64用作編碼字串。
/** * @file Base64.java * @date 2016年8月5日 * @version 3.4.1 * * Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved. */package encrypt;import java.io.UnsupportedEncodingException;import Decoder.BASE64Decoder;import Decoder.BASE64Encoder;/** * * * @author chengjian.he * @version 3.4, 2016年8月5日 上午10:32:23 * @since Yeexun 3.4 */public class Base64 {// 加密public String getBase64(String str) {byte[] b = null;String s = null;try {b = str.getBytes("utf-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}if (b != null) {s = new BASE64Encoder().encode(b);}return s;}// 解密public String getFromBase64(String s) {byte[] b = null;String result = null;if (s != null) {BASE64Decoder decoder = new BASE64Decoder();try {b = decoder.decodeBuffer(s);result = new String(b, "utf-8");} catch (Exception e) {e.printStackTrace();}}return result;}public static void main(String args[]){Base64 b6 = new Base64();System.out.println(b6.getBase64("ILoveYou"));System.out.println(b6.getFromBase64(b6.getBase64("ILoveYou")));}}
SUxvdmVZb3U=ILoveYou
3 Base64Encoder
一直以來Base64的加密解密都是使用sun.misc包下的BASE64Encoder及BASE64Decoder的sun.misc.BASE64Encoder/BASE64Decoder類。這人個類是sun公司的內部方法,並沒有在java api中公開過,不屬於JDK標準庫範疇,但在JDK中包含了該類,可以直接使用。
/** * @file Base64Encoder.java * @date 2016年8月5日 * @version 3.4.1 * * Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved. */package encrypt; /** * * * @author chengjian.he * @version 3.4, 2016年8月5日 上午10:44:22 * @since Yeexun 3.4 */public class Base64Encoder { public static String getBASE64(String s) { if (s == null) return null; return (new sun.misc.BASE64Encoder()).encode(s.getBytes()); } // 將 BASE64 編碼的字串 s 進行解碼 解密 public static String getFromBASE64(String s) { if (s == null) return null; sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder(); try { byte[] b = decoder.decodeBuffer(s); return new String(b); } catch (Exception e) { return null; } } public static String mTOa(Object ming){ return Base64Encoder.getBASE64(Base64Encoder.getBASE64(Base64Encoder.getBASE64((String)ming))); } public static String aTOm(String an){ return Base64Encoder.getFromBASE64(Base64Encoder.getFromBASE64(Base64Encoder.getFromBASE64(an))); } public static void main(String[] args) { String a = mTOa("100000.89".toString()); System.out.println(a);//加密 System.out.println(aTOm(a));//解密 }}
4 RSA
RSA 公開金鑰 密碼編譯演算法是1977年由 羅納德·李維斯特(Ron Rivest)、 阿迪·薩莫爾(Adi Shamir)和 倫納德·阿德曼(Leonard Adleman)一起提出的。1987年首次公布,當時他們三人都在麻省理工學院工作。RSA就是他們三人姓氏開頭字母拼在一起組成的。 RSA是目前最有影響力的公開金鑰加密演算法,它能夠抵抗到目前為止已知的絕大多數密碼攻擊,已被ISO推薦為公開金鑰 資料加密標準。 今天只有短的RSA鑰匙才可能被強力方式解破。到2008年為止,世界上還沒有任何可靠的攻擊RSA演算法的方式。只要其鑰匙的長度足夠長,用RSA加密的資訊實際上是不能被解破的。但在 分散式運算和 量子電腦理論日趨成熟的今天,RSA加密安全性受到了挑戰。 RSA演算法基於一個十分簡單的數論事實:將兩個大質數相乘十分容易,但是想要對其乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密金鑰。 缺點 編輯 1)產生密鑰很麻煩,受到素數產生技術的限制,因而難以做到一次一密。 2)安全性,RSA的安全性依賴於大數的因子分解,但並沒有從理論上證明破譯RSA的難度與大數分解難度等價,而且密碼學界多數人士傾向於因子分解不是NP問題。現今,人們已能分解140多個十進位位的大素數,這就要求使用更長的密鑰,速度更慢;另外,人們正在積極尋找攻擊RSA的方法,如選擇密文攻擊,一般攻擊者是將某一資訊作一下偽裝(Blind),讓擁有私密金鑰的實體簽署。然後,經過計算就可得到它所想要的資訊。實際上,攻擊利用的都是同一個弱點,即存在這樣一個事實:乘冪保留了輸入的乘法結構: (XM)d = Xd *Md mod n 前面已經提到,這個固有的問題來自於公開金鑰密碼系統的最有用的特徵--每個人都能使用公開金鑰。但從演算法上無法解決這一問題,主要措施有兩條:一條是採用好的公開金鑰協議,保證工作過程中實體不對其他實體任意產生的資訊解密,不對自己一無所知的資訊簽名;另一條是決不對陌生人送來的隨機文檔簽名,簽名時首先使用One-Way Hash Function對文檔作HASH處理,或同時使用不同的簽名演算法。除了利用公用模數,人們還嘗試一些利用解密指數或φ(n)等等攻擊. 3)速度太慢,由於RSA 的分組長度太大,為保證安全性,n 至少也要 600 bits以上,使運算代價很高,尤其是速度較慢,較對稱密碼演算法慢幾個數量級;且隨著大數分解技術的發展,這個長度還在增加,不利於資料格式的標準化。SET(Secure Electronic Transaction)協議中要求CA採用2048位元長的密鑰,其他實體使用1024位元的密鑰。為了速度問題,人們廣泛使用單, 公開金鑰密碼結合使用的方法,優缺點互補:單鑰密碼加密速度快,人們用它來加密較長的檔案,然後用RSA來給檔案祕密金鑰加密,極好的解決了單鑰密碼的密鑰分發問題。
/** * @file RSATool.java * @date 2016年8月5日 * @version 3.4.1 * * Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved. */package encrypt; /** * * * @author chengjian.he * @version 3.4, 2016年8月5日 上午10:51:35 * @since Yeexun 3.4 */import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.security.Key;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.NoSuchAlgorithmException;import java.security.interfaces.RSAPrivateKey;import java.security.interfaces.RSAPublicKey;import javax.crypto.Cipher;import javax.crypto.NoSuchPaddingException;public class RSATool {public static void makekeyfile(String pubkeyfile, String privatekeyfile)throws NoSuchAlgorithmException, FileNotFoundException, IOException {// KeyPairGenerator類用於產生公開金鑰和私密金鑰對,基於RSA演算法產生對象KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");// 初始化金鑰組產生器,密鑰大小為1024位keyPairGen.initialize(1024);// 產生一個金鑰組,儲存在keyPair中KeyPair keyPair = keyPairGen.generateKeyPair();// 得到私密金鑰RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();// 得到公開金鑰RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();// 產生私密金鑰ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(privatekeyfile));oos.writeObject(privateKey);oos.flush();oos.close();oos = new ObjectOutputStream(new FileOutputStream(pubkeyfile));oos.writeObject(publicKey);oos.flush();oos.close();System.out.println("make file ok!");}/** * * @param k * @param data * @param encrypt * 1 加密 0解密 * @return * @throws NoSuchPaddingException * @throws Exception */public static byte[] handleData(Key k, byte[] data, int encrypt)throws Exception {if (k != null) {Cipher cipher = Cipher.getInstance("RSA");if (encrypt == 1) {cipher.init(Cipher.ENCRYPT_MODE, k);byte[] resultBytes = cipher.doFinal(data);return resultBytes;} else if (encrypt == 0) {cipher.init(Cipher.DECRYPT_MODE, k);byte[] resultBytes = cipher.doFinal(data);return resultBytes;} else {System.out.println("參數必須為: 1 加密 0解密");}}return null;}public static void main(String[] args) throws Exception {String pubfile = "d:/temp/pub.key";String prifile = "d:/temp/pri.key"; makekeyfile(pubfile, prifile);ObjectInputStream ois = new ObjectInputStream(new FileInputStream(pubfile));RSAPublicKey pubkey = (RSAPublicKey) ois.readObject();ois.close();ois = new ObjectInputStream(new FileInputStream(prifile));RSAPrivateKey prikey = (RSAPrivateKey) ois.readObject();ois.close();// 使用公開金鑰加密String msg = "~O(∩_∩)O哈哈~";String enc = "UTF-8";// 使用公開金鑰加密私密金鑰解密System.out.println("原文: " + msg);byte[] result = handleData(pubkey, msg.getBytes(enc), 1);System.out.println("加密: " + new String(result, enc));byte[] deresult = handleData(prikey, result, 0);System.out.println("解密: " + new String(deresult, enc));msg = "謔謔";// 使用私密金鑰加密公開金鑰解密System.out.println("原文: " + msg);byte[] result2 = handleData(prikey, msg.getBytes(enc), 1);System.out.println("加密: " + new String(result2, enc));byte[] deresult2 = handleData(pubkey, result2, 0);System.out.println("解密: " + new String(deresult2, enc));}}
make file ok!原文: ~O(∩_∩)O哈哈~加密: �A N�ډB�����ym��r�C��ʇ�������U
5 AES對稱式加密
加密技術可以分為對稱與非對稱兩種.
對稱式加密,解密,即加密與解密用的是同一把秘鑰,常用的對稱式加密技術有DES,AES等
而非對稱技術,加密與解密用的是不同的秘鑰,常用的非對稱式加密技術有RSA等
為什麼要有非對稱式加密,解密技術呢
假設這樣一種情境A要發送一段訊息給B,但是又不想以明文發送,所以就需要對訊息進行加密.如果採用對稱式加密技術,那麼加密與解密用的是同一把秘鑰.除非B事先就知道A的秘鑰,並且儲存好.這樣才可以解密A發來的訊息.
由於對稱技術只有一把秘鑰,所以秘鑰的管理是一個很麻煩的問題.而非對稱技術的誕生就解決了這個問題.非對稱式加密與解密使用的是不同的秘鑰,並且秘鑰對是一一對應的,即用A的私密金鑰加密的密文只有用A的公開金鑰才能解密.
這樣的話,每個人都有兩把秘鑰,私密金鑰和公開金鑰,私密金鑰是只有自己才知道的,不能告訴別人,而公開金鑰是公開的,大家都可以知道