我們和多部門之間聯調經常需要涉及報文加解密的場景, 梳理出一部分常用的加解密實用文檔供參考
加密算法(DES,AES,RSA,MD5,SHA1,Base64)比較和項目應用
加密技術通常分為兩大類:"對稱式"和"非對稱式"。
對稱性加密算法:對稱式加密就是加密和解密使用同一個密鑰。信息接收雙方都需事先知道密匙和加解密算法且其密匙是相同的,之后便是對數據進行加解密了。對稱加密算法用來對敏感數據等信息進行加密。
非對稱算法:非對稱式加密就是加密和解密所使用的不是同一個密鑰,通常有兩個密鑰,稱為"公鑰"和"私鑰",它們兩個必需配對使用,否則不能打開加密文件。發(fā)送雙方A,B事先均生成一堆密匙,然后A將自己的公有密匙發(fā)送給B,B將自己的公有密匙發(fā)送給A,如果A要給B發(fā)送消 息,則先需要用B的公有密匙進行消息加密,然后發(fā)送給B端,此時B端再用自己的私有密匙進行消息解密,B向A發(fā)送消息時為同樣的道理。
散列算法:散列算法,又稱哈希函數,是一種單向加密算法。在信息安全技術中,經常需要驗證消息的完整性,散列(Hash)函數提供了這一服務,它對不同長度的輸入消息,產生固定長度的輸出。這個固定長度的輸出稱為原輸入消息的"散列"或"消息摘要"(Message digest)。散列算法不算加密算法,因為其結果是不可逆的,既然是不可逆的,那么當然不是用來加密的,而是簽名。
對稱性加密算法有:AES、DES、3DES
用途:對稱加密算法用來對敏感數據等信息進行加密
DES(Data Encryption Standard):數據加密標準,速度較快,適用于加密大量數據的場合。
3DES(Triple DES):是基于DES,對一塊數據用三個不同的密鑰進行三次加密,強度更高。
AES(Advanced Encryption Standard):高級加密標準,是下一代的加密算法標準,速度快,安全級別高;AES是一個使用128為分組塊的分組加密算法,分組塊和128、192或256位的密鑰一起作為輸入,對4×4的字節(jié)數組上進行操作。眾所周之AES是種十分高效的算法,尤其在8位架構中,這源于它面向字節(jié)的設計。AES 適用于8位的小型單片機或者普通的32位微處理器,并且適合用專門的硬件實現,硬件實現能夠使其吞吐量(每秒可以到達的加密/解密bit數)達到十億量級。同樣,其也適用于RFID系統(tǒng)。
//AES-------------------------
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
/**
* 當我們把密鑰定為大于128時(即192或256)時,就會出現這個錯誤:Illegal key size or default parameters 這是因為Java默認不能處理這么長的key。
*
* 解決辦法:使用一個JCE就可以解決(Unlimited Strength Jurisdiction Policy)
*
* JCE的下載地址:https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_Developer-Site/en_US/-/USD/ViewProductDetail-Start?ProductRef=jce_policy-6-oth-
* JPR@CDS-CDS_Developer
*
* 下載后,解壓,把解壓后的local_policy.jar文件和US_export_policy.jar放到你的程序所使用的jre下的安全目錄下,如:%jre%/lib/security
public class AES {
public static void main(String[] args) throws Exception {
String content = "beginTime=-1&endTime=1462032000&partner_id=10&status=1,2,3,4,5,50";
String key = "d5e774de46f53ffeae8623ac47ca3334";
// System.out.println("加密密鑰和解密密鑰:" + key);
String encrypt = aesEncrypt(content, key);
encrypt = encrypt.replaceAll("\\s|\\r|\\n|\\t", "");
System.out.println("加密后:" + encrypt);
String decrypt = aesDecrypt(encrypt, key);
System.out.println("解密后:" + decrypt);
System.out.println(System.currentTimeMillis() / 1000);
}
/**
* 將byte[]轉為各種進制的字符串
*
* @param bytes
* byte[]
* @param radix
* 可以轉換進制的范圍,從Character.MIN_RADIX到Character.MAX_RADIX,超出范圍后變?yōu)?0進制
* @return 轉換后的字符串
*/
public static String binary(byte[] bytes, int radix) {
return new BigInteger(1, bytes).toString(radix);// 這里的1代表正數
}
/**
* base 64 encode
*
* @param bytes
* 待編碼的byte[]
* @return 編碼后的base 64 code
*/
public static String base64Encode(byte[] bytes) {
return Base64.encodeBase64String(bytes);
}
/**
* base 64 decode
*
* @param base64Code
* 待解碼的base 64 code
* @return 解碼后的byte[]
* @throws Exception
*/
public static byte[] base64Decode(String base64Code) throws Exception {
return StringUtils.isEmpty(base64Code) ? null : Base64.decodeBase64(base64Code);
}
/**
* 獲取byte[]的md5值
*
* @param bytes
* byte[]
* @return md5
* @throws Exception
*/
public static byte[] md5(byte[] bytes) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes);
return md.digest();
}
/**
* 獲取字符串md5值
*
* @param msg
* @return md5
* @throws Exception
*/
public static byte[] md5(String msg) throws Exception {
return StringUtils.isEmpty(msg) ? null : md5(msg.getBytes());
}
/**
* 結合base64實現md5加密
*
* @param msg
* 待加密字符串
* @return 獲取md5后轉為base64
* @throws Exception
*/
public static String md5Encrypt(String msg) throws Exception {
return StringUtils.isEmpty(msg) ? null : base64Encode(md5(msg));
}
/**
* AES加密
*
* @param content
* 待加密的內容
* @param encryptKey
* 加密密鑰
* @return 加密后的byte[]
* @throws Exception
*/
public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(encryptKey.getBytes()));
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));
// cipher.init(Cipher.ENCRYPT_MODE, new IvParameterSpec(encryptKey.getBytes("UTF-8")));
// KeyGenerator kgen = KeyGenerator.getInstance("AES");
// kgen.init(128, new SecureRandom(encryptKey.getBytes()));
// Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes("UTF-8"), "AES"));
return cipher.doFinal(content.getBytes("utf-8"));
}
/**
* AES加密為base 64 code
*
* @param content
* 待加密的內容
* @param encryptKey
* 加密密鑰
* @return 加密后的base 64 code
* @throws Exception
*/
public static String aesEncrypt(String content, String encryptKey) throws Exception {
return base64Encode(aesEncryptToBytes(content, encryptKey));
}
/**
* AES解密
*
* @param encryptBytes
* 待解密的byte[]
* @param decryptKey
* 解密密鑰
* @return 解密后的String
* @throws Exception
*/
public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(decryptKey.getBytes()));
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes("UTF-8"), "AES"));
byte[] decryptBytes = cipher.doFinal(encryptBytes);
return new String(decryptBytes);
}
/**
* 將base 64 code AES解密
*
* @param encryptStr
* 待解密的base 64 code
* @param decryptKey
* 解密密鑰
* @return 解密后的string
* @throws Exception
*/
public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
}
}
//AES-----------------------------
非對稱性算法有:RSA、DSA、ECC
RSA:由 RSA 公司發(fā)明,是一個支持變長密鑰的公共密鑰算法,需要加密的文件塊的長度也是可變的。RSA在國外早已進入實用階段,已研制出多種高速的RSA的專用芯片。
DSA(Digital Signature Algorithm):數字簽名算法,是一種標準的 DSS(數字簽名標準),嚴格來說不算加密算法。
ECC(Elliptic Curves Cryptography):橢圓曲線密碼編碼學。ECC和RSA相比,具有多方面的絕對優(yōu)勢,主要有:抗攻擊性強。相同的密鑰長度,其抗攻擊性要強很多倍。計算量小,處理速度快。ECC總的速度比RSA、DSA要快得多。存儲空間占用小。ECC的密鑰尺寸和系統(tǒng)參數與RSA、DSA相比要小得多,意味著它所占的存貯空間要小得多。這對于加密算法在IC卡上的應用具有特別重要的意義。帶寬要求低。當對長消息進行加解密時,三類密碼系統(tǒng)有相同的帶寬要求,但應用于短消息時ECC帶寬要求卻低得多。帶寬要求低使ECC在無線網絡領域具有廣泛的應用前景。
散列算法(簽名算法)有:MD5、SHA1、HMAC
用途:主要用于驗證,防止信息被修。具體用途如:文件校驗、數字簽名、鑒權協(xié)議
MD5:MD5是一種不可逆的加密算法,目前是最牢靠的加密算法之一,尚沒有能夠逆運算的程序被開發(fā)出來,它對應任何字符串都可以加密成一段唯一的固定長度的代碼。
SHA1:是由NISTNSA設計為同DSA一起使用的,它對長度小于264的輸入,產生長度為160bit的散列值,因此抗窮舉(brute-force)性更好。SHA-1設計時基于和MD4相同原理,并且模仿了該算法。SHA-1是由美國標準技術局(NIST)頒布的國家標準,是一種應用最為廣泛的Hash函數算法,也是目前最先進的加密技術,被政府部門和私營業(yè)主用來處理敏感的信息。而SHA-1基于MD5,MD5又基于MD4。
HMAC:是密鑰相關的哈希運算消息認證碼(Hash-based Message Authentication Code),HMAC運算利用哈希算法,以一個密鑰和一個消息為輸入,生成一個消息摘要作為輸出。也就是說HMAC是需要一個密鑰的。所以,HMAC_SHA1也是需要一個密鑰的,而SHA1不需要。
其他常用算法:
Base64:其實不是安全領域下的加密解密算法,只能算是一個編碼算法,通常用于把二進制數據編碼為可寫的字符形式的數據,對數據內容進行編碼來適合傳輸(可以對img圖像編碼用于傳輸)。這是一種可逆的編碼方式。編碼后的數據是一個字符串,其中包含的字符為:A-Z、a-z、0-9、+、/,共64個字符(26 + 26 + 10 + 1 + 1 = 64,其實是65個字符,“=”是填充字符。Base64要求把每三個8Bit的字節(jié)轉換為四個6Bit的字節(jié)(3*8 = 4*6 = 24),然后把6Bit再添兩位高位0,組成四個8Bit的字節(jié),也就是說,轉換后的字符串理論上將要比原來的長1/3。原文的字節(jié)最后不夠3個的地方用0來補足,轉換時Base64編碼用=號來代替。這就是為什么有些Base64編碼會以一個或兩個等號結束的原因,中間是不可能出現等號的,但等號最多只有兩個。其實不用"="也不耽誤解碼,之所以用"=",可能是考慮到多段編碼后的Base64字符串拼起來也不會引起混淆。)
Base64編碼是從二進制到字符的過程,像一些中文字符用不同的編碼轉為二進制時,產生的二進制是不一樣的,所以最終產生的Base64字符也不一樣。例如"上網"對應utf-8格式的Base64編碼是"5LiK572R", 對應GB2312格式的Base64編碼是"yc/N+A=="。
標準的Base64并不適合直接放在URL里傳輸,因為URL編碼器會把標準Base64中的“/”和“+”字符變?yōu)樾稳纭?XX”的形式,而這些“%”號在存入數據庫時還需要再進行轉換,因為ANSI SQL中已將“%”號用作通配符。
為解決此問題,可采用一種用于URL的改進Base64編碼,它不在末尾填充'='號,并將標準Base64中的“+”和“/”分別改成了“-”和“_”,這樣就免去了在URL編解碼和數據庫存儲時所要作的轉換,避免了編碼信息長度在此過程中的增加,并統(tǒng)一了數據庫、表單等處對象標識符的格式。
另有一種用于正則表達式的改進Base64變種,它將“+”和“/”改成了“!”和“-”,因為“+”,“*”以及前面在IRCu中用到的“[”和“]”在正則表達式中都可能具有特殊含義。
此外還有一些變種,它們將“+/”改為“_-”或“._”(用作編程語言中的標識符名稱)或“.-”(用于XML中的Nmtoken)甚至“_:”(用于XML中的Name)。
HTTPS(全稱:Hypertext Transfer Protocol over Secure Socket Layer),是以安全為目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL層,HTTPS的安全基礎是SSL(SSL使用40 位關鍵字作為RC4流加密算法,這對于商業(yè)信息的加密是合適的。),因此加密的詳細內容就需要SSL。https:URL表明它使用了HTTP,但HTTPS存在不同于HTTP的默認端口及一個加密/身份驗證層(在HTTP與TCP之間),提供了身份驗證與加密通訊方法,現在它被廣泛用于萬維網上安全敏感的通訊,例如交易支付方面。它的主要作用可以分為兩種:一種是建立一個信息安全通道,來保證數據傳輸的安全;另一種就是確認網站的真實性。
項目應用總結:
1. 加密算法是可逆的,用來對敏感數據進行保護。散列算法(簽名算法、哈希算法)是不可逆的,主要用于身份驗證。
2. 對稱加密算法使用同一個密匙加密和解密,速度快,適合給大量數據加密。對稱加密客戶端和服務端使用同一個密匙,存在被抓包破解的風險。
3. 非對稱加密算法使用公鑰加密,私鑰解密,私鑰簽名,公鑰驗簽。安全性比對稱加密高,但速度較慢。非對稱加密使用兩個密匙,服務端和客戶端密匙不一樣,私鑰放在服務端,黑客一般是拿不到的,安全性高。
4. Base64不是安全領域下的加解密算法,只是一個編碼算法,通常用于把二進制數據編碼為可寫的字符形式的數據,特別適合在http,mime協(xié)議下的網絡快速傳輸數據。UTF-8和GBK中文的Base64編碼結果是不同的。采用Base64編碼不僅比較簡短,同時也具有不可讀性,即所編碼的數據不會被人用肉眼所直接看到,但這種方式很初級,很簡單。Base64可以對圖片文件進行編碼傳輸。
5. https協(xié)議廣泛用于萬維網上安全敏感的通訊,例如交易支付方面。它的主要作用可以分為兩種:一種是建立一個信息安全通道,來保證數據傳輸的安全;另一種就是確認網站的真實性。
6. 大量數據加密建議采用對稱加密算法,提高加解密速度;小量的機密數據,可以采用非對稱加密算法。在實際的操作過程中,我們通常采用的方式是:采用非對稱加密算法管理對稱算法的密鑰,然后用對稱加密算法加密數據,這樣我們就集成了兩類加密算法的優(yōu)點,既實現了加密速度快的優(yōu)點,又實現了安全方便管理密鑰的優(yōu)點。
7. MD5標準密鑰長度128位(128位是指二進制位。二進制太長,所以一般都改寫成16進制,每一位16進制數可以代替4位二進制數,所以128位二進制數寫成16進制就變成了128/4=32位。16位加密就是從32位MD5散列中把中間16位提取出來);sha1標準密鑰長度160位(比MD5摘要長32位),Base64轉換后的字符串理論上將要比原來的長1/3。