加密算法,是現在每個軟件項目裏必須用到的內容。廣泛應用在包括了用戶登入、數字簽名、數據傳輸等多個場合。那大家都知道那些呢?今天我把常見的加密算法全部整理在這裏,供大家學習參考。
首先,大家要知道加密算法能幹什麼,利用加密算法來對數據通信的過程進行加密傳輸是一種最常見的安全手段。利用該手段能夠達到一下三個目的:
1、數據保密性,防止用戶數據被竊取或泄露;
2、數據完整性,防止用戶傳輸的數據被篡改;
3、通信雙方身份確認,確保數據來源合法;
常見的加密算法
目前常見的加密算法分類如下:
1,單向散列加密算法
常見算法包括:MD5、sha1、sha256等
2,對稱加密算法
常見的算法有:DES、3DES、AES
3,非對稱加密算法
常見算法包括:RSA、ECC
各種加密算法對比如下:
1,單向散列加密算法:
名稱 | 運行速度 | 安全性 |
---|---|---|
MD5 | 快 | 中 |
SHA-1 | 慢 | 高 |
SHA-256 | 更慢 | 更高 |
2,對稱加密算法:
名稱 | 密鑰 | 運行速度 | 安全性 | 資源消耗 |
---|---|---|---|---|
DES | 56位 | 較快 | 低 | 中 |
3DES | 112位或168位 | 慢 | 中 | 高 |
AES | 128、192、256位 | 快 | 高 | 低 |
3,非對稱加密算法:
名稱 | 成熟度 | 安全性 | 運算速度 | 資源消耗 |
---|---|---|---|---|
RSA | 高 | 高 | 中 | 中 |
ECC | 高 | 高 | 慢 | 高 |
加密算法詳解
一,單向散列加密
單向散列加密算法常用於提取數據,驗證數據的完整性。發送者將明文通過單向加密算法加密生成定長的密文串,然後將明文和密文串傳遞給接收方。接收方在收到報文後,將解明文使用相同的單向加密算法進行加密,得出加密後的密文串。隨後與發送者發送過來的密文串進行對比,若發送前和發送後的密文串相一致,則說明傳輸過程中數據沒有損壞;若不一致,說明傳輸過程中數據丟失了。其次也用於密碼加密傳遞存儲。單向加密算法只能用於對數據的加密,無法被解密,其特點爲定長輸出、雪崩效應。
1.1,MD5加密算法
MD5加密算法用的是哈希函數,一般應用於對信息產生信息摘要,防止信息被篡改。最常見的使用是對密碼加密、生成數字簽名。從嚴格意義上來說,MD5是摘要算法,並非加密算法。MD5 生成密文時,無論要加密的字符串有多長,它都會輸出長度爲 128bits 的一個密文串,通常16 進制時爲 32 個字符。
public static final byte[] computeMD5(byte[] content) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
return md5.digest(content);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
1.2,SHA1加密算法
SHA1加密算法,與MD5一樣,也是目前較流行的摘要算法。但SHA1 比 MD5 的 安全性更高。對長度小於 2 ^ 64 位的消息,SHA1會產生一個 160 位的 消息摘要。基於 MD5、SHA1 的信息摘要特性以及不可逆,可以被應用在檢查文件完整性, 數字簽名等場景。
public static byte[] computeSHA1(byte[] content) {
try {
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
return sha1.digest(content);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
1.3,SHA256加密算法
SHA256是SHA2算法中的一種,如SHA2加密算法中有:SHA244、SHA256、SHA512等。SHA2屬於SHA1的升級,SHA1是160位的哈希值,而SHA2是組合值,有不同的位數,其中最受歡迎的是256位(SHA256算法)。
SSL行業選擇SHA作爲數字簽名的散列算法,從2011到2015,一直以SHA-1位主導算法。但隨着互聯網技術的提升,SHA-1的缺點越來越突顯。從去年起,SHA-2成爲了新的標準,所以現在簽發的SSL證書,必須使用該算法簽名。
public static byte[] getSHA256(String str) {
MessageDigest messageDigest;
String encodestr = "";
try {
messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(str.getBytes("UTF-8"));
return messageDigest.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
二,對稱加密算法
對稱加密算法採用單密鑰加密,在數據傳輸過程中,發送方將原始數據分割成固定大小的塊,經過密鑰和加密算法逐個加密後,發送給接收方;接收方收到加密後的報文後,結合密鑰和解密算法解密組合後得出原始數據。由於加解密算法是公開的,因此在這過程中,密鑰的安全傳遞就成爲了至關重要的事了。而密鑰通常來說是通過雙方協商,以物理的方式傳遞給對方,或者利用第三方平臺傳遞給對方,一旦這過程出現了密鑰泄露,不懷好意的人就能結合相應的算法攔截解密出其加密傳輸的內容。
AES、DES、3DES 都是對稱的塊加密算法,加解密的過程是可逆的。
2.1,DES算法
DES算法爲密碼體制中的對稱密碼體制,又被稱爲美國數據加密標準,是1972年美國IBM公司研製的對稱密碼體制加密算法。明文按64位進行分組,密鑰長64位,密鑰事實上是56位參與DES運算(第8、16、24、32、40、48、56、64位是校驗位, 使得每個密鑰都有奇數個1)分組後的明文組和56位的密鑰按位替代或交換的方法形成密文組的加密方法。
DES 加密算法是對密鑰進行保密,公開加密和解密算。只有知道發送方相同密鑰的人才能解讀獲取的密文數據。想破譯 DES 加密算法,就要搜索密鑰的編碼。對於56位長度的密鑰來說,用窮舉法,其運算次數爲 2 ^ 56 次。
2.2,3DES算法
3DES又稱Triple DES,是DES加密算法的一種模式,它使用2條不同的56位的密鑰對數據進行三次加密。DES使用56位密鑰和密碼塊的方法,而在密碼塊的方法中,文本被分成64位大小的文本塊然後再進行加密。比起最初的DES,3DES更爲安全。
public class Des3 {
private static final String Algorithm = "DESede";
/**
* 加密
* @param keybyte
* @param src
* @return
*/
public static byte[] encryptMode(byte[] keybyte, byte[] src) {
try {
// 生成密鑰
SecretKey deskey = new SecretKeySpec(keybyte, Algorithm);
// 加密
Cipher c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.ENCRYPT_MODE, deskey);
return c1.doFinal(src);
} catch (java.security.NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (javax.crypto.NoSuchPaddingException e2) {
e2.printStackTrace();
} catch (java.lang.Exception e3) {
e3.printStackTrace();
}
return null;
}
/**
* 解密
* @param keybyte 爲加密密鑰,長度爲24字節
* @param src 爲加密後的緩衝區
* @return
*/
public static byte[] decryptMode(byte[] keybyte, byte[] src) {
try {
// 生成密鑰
SecretKey deskey = new SecretKeySpec(keybyte, Algorithm);
// 解密
Cipher c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.DECRYPT_MODE, deskey);
return c1.doFinal(src);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 轉換成十六進制字符串
public static String byte2hex(byte[] b) {
String hs = "";
String stmp = "";
for (int n = 0; n < b.length; n++) {
stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length() == 1) {
hs = hs + "0" + stmp;
} else {
hs = hs + stmp;
}
if (n < b.length - 1) {
hs = hs + ":";
}
}
return hs.toUpperCase();
}
}
2.3,AES算法
AES算法是密碼學中的高級加密標準,同時也是美國聯邦政府採用的區塊加密標準。這個標準用來替代原先的DES,已經被多方分析且廣爲全世界所使用。算法採用對稱分組密碼體制,密鑰長度的最少支持爲 128 位、 192 位、256 位,分組長度 128 位,算法應易於各種硬件和軟件實現。AES本身就是爲了取代DES的,AES具有更好的安全性、效率和靈活性。
public class AESUtils {
/**
* 加密
*
* @param content
* @param strKey
* @return
* @throws Exception
*/
public static byte[] encrypt(String content, String strKey) throws Exception {
SecretKeySpec skeySpec = getKey(strKey);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
return cipher.doFinal(content.getBytes());
}
/**
* 解密
*
* @param strKey
* @param content
* @return
* @throws Exception
*/
public static String decrypt(byte[] content, String strKey) throws Exception {
SecretKeySpec skeySpec = getKey(strKey);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(content);
String originalString = new String(original);
return originalString;
}
private static SecretKeySpec getKey(String strKey) throws Exception {
byte[] arrBTmp = strKey.getBytes();
byte[] arrB = new byte[16];
for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
arrB[i] = arrBTmp[i];
}
SecretKeySpec skeySpec = new SecretKeySpec(arrB, "AES");
return skeySpec;
}
}
三,非對稱加密算法
非對稱加密算法採用公鑰(publickey)和私鑰(privatekey)兩種不同的密鑰來進行加解密。公鑰與私鑰是一對,如果用公鑰對數據進行加密,只有用對應的私鑰才能解密,反之亦然。因爲加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。
非對稱加密算法實現機密信息交換的基本過程是:甲方生成一對密鑰並將公鑰公開,需要向甲方發送信息的其他角色(乙方)使用該密鑰(甲方的公鑰)對機密信息進行加密後再發送給甲方;甲方再用自己私鑰對加密後的信息進行解密。甲方想要回復乙方時正好相反,使用乙方的公鑰對數據進行加密,同理,乙方使用自己的私鑰來進行解密。
3.1,RSA算法
RSA是目前最有影響力的公鑰加密算法,也是被普遍認爲是目前最優秀的公鑰方案之一。RSA算法是第一個能同時用於加密和數字簽名的算法,也易於理解和操作。RSA是被研究得最廣泛的公鑰算法,從提出到現今的三十多年裏,經歷了各種攻擊的考驗,逐漸爲人們接受,截止2017年被普遍認爲是最優秀的公鑰方案之一。也已被ISO推薦爲公鑰數據加密標準。
public class RSAUtils {
public static final String KEY_ALGORITHM = "RSA";
private static final String PUBLIC_KEY = "RSAPublicKey";
private static final String PRIVATE_KEY = "RSAPrivateKey";
/**
* 私鑰解密
*
* @param data 已加密數據
* @param privateKey 私鑰(BASE64編碼)
* @return
* @throws Exception
*/
public static String decryptByPrivateKey(String data, String privateKey) throws Exception {
byte[] keyBytes = Base64.decodeBase64(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateK);
byte[] buff = cipher.doFinal(Base64.decodeBase64(data));
return new String(buff);
}
/**
* 公鑰解密
*
* @param data 已加密數據
* @param publicKey 公鑰(BASE64編碼)
* @return
* @throws Exception
*/
public static String decryptByPublicKey(String data, String publicKey) throws Exception {
byte[] keyBytes = Base64.decodeBase64(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicK = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicK);
// 執行解密操作
byte[] buff = cipher.doFinal(Base64.decodeBase64(data));
return new String(buff);
}
/**
* 公鑰加密
*
* @param data 源數據
* @param publicKey 公鑰(BASE64編碼)
* @return
* @throws Exception
*/
public static String encryptByPublicKey(String data, String publicKey) throws Exception {
byte[] keyBytes = Base64.decodeBase64(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicK = keyFactory.generatePublic(x509KeySpec);
// 對數據加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicK);
byte[] buff = cipher.doFinal(data.getBytes());
return Base64.encodeBase64String(buff);
}
/**
* 私鑰加密
*
* @param data 源數據
* @param privateKey 私鑰(BASE64編碼)
* @return
* @throws Exception
*/
public static String encryptByPrivateKey(String data, String privateKey) throws Exception {
byte[] keyBytes = Base64.decodeBase64(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateK);
byte[] buff = cipher.doFinal(data.getBytes());
// 執行加密操作。加密後的結果通常都會用Base64編碼進行傳輸
return Base64.encodeBase64String(buff);
}
/**
* 獲取私鑰
*
* @param keyMap 密鑰對
* @return
* @throws Exception
*/
public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return Base64.encodeBase64String(key.getEncoded());
}
/**
* 獲取公鑰
*
* @param keyMap 密鑰對
* @return
* @throws Exception
*/
public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return Base64.encodeBase64String(key.getEncoded());
}
/**
* 生成密鑰對(公鑰和私鑰)
*
* @return
* @throws Exception
*/
public static Map<String, Object> initKey() throws Exception {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String, Object> keyMap = new HashMap<String, Object>(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
}
3.2,ECC算法
ECC(橢圓加密算法)是一種公鑰加密體制,主要優勢是在某些情況下它比其他的方法使用更小的密鑰——比如RSA加密算法——提供相當的或更高等級的安全。不過一個缺點是加密和解密操作的實現比其他機制時間長。它相比RSA算法,對 CPU 消耗嚴重。
public abstract class ECCCoder extends Coder {
public static final String ALGORITHM = "EC";
private static final String PUBLIC_KEY = "ECCPublicKey";
private static final String PRIVATE_KEY = "ECCPrivateKey";
/**
* 用私鑰解密
* @param data
* @param key
* @return
* @throws Exception
*/
public static byte[] decrypt(byte[] data, String key) throws Exception {
// 對密鑰解密
byte[] keyBytes = decryptBASE64(key);
// 取得私鑰
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = ECKeyFactory.INSTANCE;
ECPrivateKey priKey = (ECPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(priKey.getS(),priKey.getParams());
// 對數據解密
Cipher cipher = new NullCipher();
cipher.init(Cipher.DECRYPT_MODE, priKey, ecPrivateKeySpec.getParams());
return cipher.doFinal(data);
}
/**
* 用公鑰加密
* @param data
* @param privateKey
* @return
* @throws Exception
*/
public static byte[] encrypt(byte[] data, String privateKey) throws Exception {
// 對公鑰解密
byte[] keyBytes = decryptBASE64(privateKey);
// 取得公鑰
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = ECKeyFactory.INSTANCE;
ECPublicKey pubKey = (ECPublicKey) keyFactory.generatePublic(x509KeySpec);
ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(pubKey.getW(), pubKey.getParams());
Cipher cipher = new NullCipher();
cipher.init(Cipher.ENCRYPT_MODE, pubKey, ecPublicKeySpec.getParams());
return cipher.doFinal(data);
}
/**
* 取得私鑰
* @param keyMap
* @return
* @throws Exception
*/
public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return encryptBASE64(key.getEncoded());
}
/**
* 取得公鑰
* @param keyMap
* @return
* @throws Exception
*/
public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return encryptBASE64(key.getEncoded());
}
}
推薦閱讀:
爲什麼程序員都不喜歡使用switch,而是大量if…else?
掃碼關注公衆號,發送關鍵詞獲取相關資料:
-
發“Springboot”領取電商項目實戰源碼;
-
發“SpringCloud”領取學習實戰資料;