浅谈常见的七种加密算法及实现(附代码)
1. 前言
數(shù)字簽名、信息加密?是前后端開發(fā)都經(jīng)常需要使用到的技術(shù),應用場景包括了用戶登入、交易、信息通訊、oauth?等等,不同的應用場景也會需要使用到不同的簽名加密算法,或者需要搭配不一樣的?簽名加密算法來達到業(yè)務(wù)目標。這里簡單的給大家介紹幾種常見的簽名加密算法和一些典型場景下的應用。
?
2. 正文
2.1 數(shù)字簽名
數(shù)字簽名,簡單來說就是通過提供?可鑒別?的?數(shù)字信息?驗證?自身身份?的一種方式。一套?數(shù)字簽名?通常定義兩種?互補?的運算,一個用于?簽名,另一個用于?驗證。分別由?發(fā)送者?持有能夠?代表自己身份?的?私鑰?(私鑰不可泄露),由?接受者?持有與私鑰對應的?公鑰?,能夠在?接受?到來自發(fā)送者信息時用于?驗證?其身份。
注意:圖中?加密過程?有別于?公鑰加密,更多?介紹戳這里。簽名?最根本的用途是要能夠唯一?證明發(fā)送方的身份,防止?中間人攻擊、CSRF?跨域身份偽造。基于這一點在諸如?設(shè)備認證、用戶認證、第三方認證等認證體系中都會使用到?簽名算法?(彼此的實現(xiàn)方式可能會有差異)。
2.2 加密和解密
2.2.1 加密
數(shù)據(jù)加密?的基本過程,就是對原來為?明文?的文件或數(shù)據(jù)按?某種算法?進行處理,使其成為?不可讀?的一段代碼,通常稱為?“密文”。通過這樣的途徑,來達到?保護數(shù)據(jù)?不被?非法人竊取、閱讀的目的。
2.2. 解密
加密?的?逆過程?為?解密,即將該?編碼信息?轉(zhuǎn)化為其?原來數(shù)據(jù)?的過程。
2.3 對稱加密和非對稱加密
加密算法分?對稱加密?和?非對稱加密,其中對稱加密算法的加密與解密?密鑰相同,非對稱加密算法的加密密鑰與解密?密鑰不同,此外,還有一類?不需要密鑰?的?散列算法。
常見的?對稱加密?算法主要有?DES、3DES、AES?等,常見的?非對稱算法?主要有?RSA、DSA?等,散列算法主要有?SHA-1、MD5?等。
2.3.1 對稱加密
對稱加密算法?是應用較早的加密算法,又稱為?共享密鑰加密算法。在?對稱加密算法?中,使用的密鑰只有一個,發(fā)送?和?接收?雙方都使用這個密鑰對數(shù)據(jù)進行?加密?和?解密。這就要求加密和解密方事先都必須知道加密的密鑰。
數(shù)據(jù)加密過程:在對稱加密算法中,數(shù)據(jù)發(fā)送方?將?明文?(原始數(shù)據(jù)) 和?加密密鑰?一起經(jīng)過特殊?加密處理,生成復雜的?加密密文?進行發(fā)送。
數(shù)據(jù)解密過程:數(shù)據(jù)接收方?收到密文后,若想讀取原數(shù)據(jù),則需要使用?加密使用的密鑰?及相同算法的?逆算法?對加密的密文進行解密,才能使其恢復成?可讀明文。
2.3.2 非對稱加密
非對稱加密算法,又稱為?公開密鑰加密算法。它需要兩個密鑰,一個稱為?公開密鑰?(public key),即?公鑰,另一個稱為?私有密鑰?(private key),即?私鑰。
因為?加密?和?解密?使用的是兩個不同的密鑰,所以這種算法稱為?非對稱加密算法。
如果使用?公鑰?對數(shù)據(jù)?進行加密,只有用對應的?私鑰?才能?進行解密。
如果使用?私鑰?對數(shù)據(jù)?進行加密,只有用對應的?公鑰?才能?進行解密。
例子:甲方生成?一對密鑰?并將其中的一把作為?公鑰?向其它人公開,得到該公鑰的?乙方?使用該密鑰對機密信息?進行加密?后再發(fā)送給甲方,甲方再使用自己保存的另一把?專用密鑰?(私鑰),對?加密?后的信息?進行解密。
2.4 常見的簽名加密算法
2.4.1 MD5算法
MD5?用的是?哈希函數(shù),它的典型應用是對一段信息產(chǎn)生?信息摘要,以?防止被篡改。嚴格來說,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);} }2.4.2 SHA1算法
SHA1?是和?MD5?一樣流行的?消息摘要算法,然而?SHA1?比?MD5?的?安全性更強。對于長度小于?2 ^ 64?位的消息,SHA1?會產(chǎn)生一個?160?位的?消息摘要。基于?MD5、SHA1?的信息摘要特性以及?不可逆?(一般而言),可以被應用在檢查?文件完整性?以及?數(shù)字簽名?等場景。
public?static?byte[]?computeSHA1(byte[]?content)?{try?{MessageDigest?sha1?=?MessageDigest.getInstance("SHA1");return?sha1.digest(content);}?catch?(NoSuchAlgorithmException?e)?{throw?new?RuntimeException(e);} }2.4.3 HMAC算法
HMAC?是密鑰相關(guān)的?哈希運算消息認證碼(Hash-based Message Authentication Code),HMAC?運算利用?哈希算法?(MD5、SHA1?等),以?一個密鑰?和?一個消息?為輸入,生成一個?消息摘要?作為?輸出。
HMAC?發(fā)送方?和?接收方?都有的?key?進行計算,而沒有這把?key?的第三方,則是?無法計算?出正確的?散列值的,這樣就可以?防止數(shù)據(jù)被篡改。
package?net.pocrd.util; import?net.pocrd.annotation.NotThreadSafe; import?net.pocrd.define.ConstField; import?org.slf4j.Logger; import?org.slf4j.LoggerFactory; import?javax.crypto.Mac; import?javax.crypto.SecretKey; import?javax.crypto.spec.SecretKeySpec; import?java.util.Arrays;@NotThreadSafe public?class?HMacHelper?{private?static?final?Logger?logger?=?LoggerFactory.getLogger(HMacHelper.class);private?Mac?mac;/***?MAC算法可選以下多種算法*?HmacMD5/HmacSHA1/HmacSHA256/HmacSHA384/HmacSHA512*/private?static?final?String?KEY_MAC?=?"HmacMD5";public?HMacHelper(String?key)?{try?{SecretKey?secretKey?=?new?SecretKeySpec(key.getBytes(ConstField.UTF8),?KEY_MAC);mac?=?Mac.getInstance(secretKey.getAlgorithm());mac.init(secretKey);}?catch?(Exception?e)?{logger.error("create?hmac?helper?failed.",?e);}}public?byte[]?sign(byte[]?content)?{return?mac.doFinal(content);}public?boolean?verify(byte[]?signature,?byte[]?content)?{try?{byte[]?result?=?mac.doFinal(content);return?Arrays.equals(signature,?result);}?catch?(Exception?e)?{logger.error("verify?sig?failed.",?e);}return?false;} }測試結(jié)論:HMAC?算法實例在?多線程環(huán)境?下是?不安全的。但是需要在?多線程訪問?時,進行同步的輔助類,使用?ThreadLocal?為?每個線程緩存?一個實例可以避免進行鎖操作。
2.4.4 AES/DES/3DES算法
AES、DES、3DES?都是?對稱?的?塊加密算法,加解密?的過程是?可逆的。常用的有?AES128、AES192、AES256?(默認安裝的?JDK?尚不支持?AES256,需要安裝對應的?jce?補丁進行升級?jce1.7,jce1.8)。
2.4.4.1 DES算法
DES?加密算法是一種?分組密碼,以?64?位為?分組對數(shù)據(jù)?加密,它的?密鑰長度?是?56?位,加密解密?用?同一算法。
DES?加密算法是對?密鑰?進行保密,而?公開算法,包括加密和解密算法。這樣,只有掌握了和發(fā)送方?相同密鑰?的人才能解讀由?DES加密算法加密的密文數(shù)據(jù)。因此,破譯?DES?加密算法實際上就是?搜索密鑰的編碼。對于?56?位長度的?密鑰?來說,如果用?窮舉法?來進行搜索的話,其運算次數(shù)為?2 ^ 56?次。
2.4.4.2 3DES算法
是基于?DES?的?對稱算法,對?一塊數(shù)據(jù)?用?三個不同的密鑰?進行?三次加密,強度更高。
2.4.4.3 AES算法
AES?加密算法是密碼學中的?高級加密標準,該加密算法采用?對稱分組密碼體制,密鑰長度的最少支持為?128?位、?192?位、256?位,分組長度?128?位,算法應易于各種硬件和軟件實現(xiàn)。這種加密算法是美國聯(lián)邦政府采用的?區(qū)塊加密標準。
AES?本身就是為了取代?DES?的,AES?具有更好的?安全性、效率?和?靈活性。
import?net.pocrd.annotation.NotThreadSafe; import?javax.crypto.Cipher; import?javax.crypto.KeyGenerator; import?javax.crypto.spec.IvParameterSpec; import?javax.crypto.spec.SecretKeySpec; import?java.security.SecureRandom;@NotThreadSafe public?class?AesHelper?{private?SecretKeySpec?keySpec;private?IvParameterSpec?iv;public?AesHelper(byte[]?aesKey,?byte[]?iv)?{if?(aesKey?==?null?||?aesKey.length?<?16?||?(iv?!=?null?&&?iv.length?<?16))?{throw?new?RuntimeException("錯誤的初始密鑰");}if?(iv?==?null)?{iv?=?Md5Util.compute(aesKey);}keySpec?=?new?SecretKeySpec(aesKey,?"AES");this.iv?=?new?IvParameterSpec(iv);}public?AesHelper(byte[]?aesKey)?{if?(aesKey?==?null?||?aesKey.length?<?16)?{throw?new?RuntimeException("錯誤的初始密鑰");}keySpec?=?new?SecretKeySpec(aesKey,?"AES");this.iv?=?new?IvParameterSpec(Md5Util.compute(aesKey));}public?byte[]?encrypt(byte[]?data)?{byte[]?result?=?null;Cipher?cipher?=?null;try?{cipher?=?Cipher.getInstance("AES/CFB/NoPadding");cipher.init(Cipher.ENCRYPT_MODE,?keySpec,?iv);result?=?cipher.doFinal(data);}?catch?(Exception?e)?{throw?new?RuntimeException(e);}return?result;}public?byte[]?decrypt(byte[]?secret)?{byte[]?result?=?null;Cipher?cipher?=?null;try?{cipher?=?Cipher.getInstance("AES/CFB/NoPadding");cipher.init(Cipher.DECRYPT_MODE,?keySpec,?iv);result?=?cipher.doFinal(secret);}?catch?(Exception?e)?{throw?new?RuntimeException(e);}return?result;}public?static?byte[]?randomKey(int?size)?{byte[]?result?=?null;try?{KeyGenerator?gen?=?KeyGenerator.getInstance("AES");gen.init(size,?new?SecureRandom());result?=?gen.generateKey().getEncoded();}?catch?(Exception?e)?{throw?new?RuntimeException(e);}return?result;} }2.4.5 RSA算法
RSA?加密算法是目前最有影響力的?公鑰加密算法,并且被普遍認為是目前?最優(yōu)秀的公鑰方案?之一。RSA?是第一個能同時用于?加密?和?數(shù)字簽名?的算法,它能夠?抵抗?到目前為止已知的?所有密碼攻擊,已被?ISO?推薦為公鑰數(shù)據(jù)加密標準。
RSA?加密算法?基于一個十分簡單的數(shù)論事實:將兩個大?素數(shù)?相乘十分容易,但想要對其乘積進行?因式分解?卻極其困難,因此可以將?乘積?公開作為?加密密鑰。
import?net.pocrd.annotation.NotThreadSafe; import?org.bouncycastle.jce.provider.BouncyCastleProvider; import?org.slf4j.Logger; import?org.slf4j.LoggerFactory; import?javax.crypto.Cipher; import?java.io.ByteArrayOutputStream; import?java.security.KeyFactory; import?java.security.Security; import?java.security.Signature; import?java.security.interfaces.RSAPrivateCrtKey; import?java.security.interfaces.RSAPublicKey; import?java.security.spec.PKCS8EncodedKeySpec; import?java.security.spec.X509EncodedKeySpec;@NotThreadSafe public?class?RsaHelper?{private?static?final?Logger?logger?=?LoggerFactory.getLogger(RsaHelper.class);private?RSAPublicKey?publicKey;private?RSAPrivateCrtKey?privateKey;static?{Security.addProvider(new?BouncyCastleProvider());?//使用bouncycastle作為加密算法實現(xiàn)}public?RsaHelper(String?publicKey,?String?privateKey)?{this(Base64Util.decode(publicKey),?Base64Util.decode(privateKey));}public?RsaHelper(byte[]?publicKey,?byte[]?privateKey)?{try?{KeyFactory?keyFactory?=?KeyFactory.getInstance("RSA");if?(publicKey?!=?null?&&?publicKey.length?>?0)?{this.publicKey?=?(RSAPublicKey)keyFactory.generatePublic(new?X509EncodedKeySpec(publicKey));}if?(privateKey?!=?null?&&?privateKey.length?>?0)?{this.privateKey?=?(RSAPrivateCrtKey)keyFactory.generatePrivate(new?PKCS8EncodedKeySpec(privateKey));}}?catch?(Exception?e)?{throw?new?RuntimeException(e);}}public?RsaHelper(String?publicKey)?{this(Base64Util.decode(publicKey));}public?RsaHelper(byte[]?publicKey)?{try?{KeyFactory?keyFactory?=?KeyFactory.getInstance("RSA");if?(publicKey?!=?null?&&?publicKey.length?>?0)?{this.publicKey?=?(RSAPublicKey)keyFactory.generatePublic(new?X509EncodedKeySpec(publicKey));}}?catch?(Exception?e)?{throw?new?RuntimeException(e);}}public?byte[]?encrypt(byte[]?content)?{if?(publicKey?==?null)?{throw?new?RuntimeException("public?key?is?null.");}if?(content?==?null)?{return?null;}try?{Cipher?cipher?=?Cipher.getInstance("RSA/ECB/PKCS1Padding");cipher.init(Cipher.ENCRYPT_MODE,?publicKey);int?size?=?publicKey.getModulus().bitLength()?/?8?-?11;ByteArrayOutputStream?baos?=?new?ByteArrayOutputStream((content.length?+?size?-?1)?/?size?*?(size?+?11));int?left?=?0;for?(int?i?=?0;?i?<?content.length;?)?{left?=?content.length?-?i;if?(left?>?size)?{cipher.update(content,?i,?size);i?+=?size;}?else?{cipher.update(content,?i,?left);i?+=?left;}baos.write(cipher.doFinal());}return?baos.toByteArray();}?catch?(Exception?e)?{throw?new?RuntimeException(e);}}public?byte[]?decrypt(byte[]?secret)?{if?(privateKey?==?null)?{throw?new?RuntimeException("private?key?is?null.");}if?(secret?==?null)?{return?null;}try?{Cipher?cipher?=?Cipher.getInstance("RSA/ECB/PKCS1Padding");cipher.init(Cipher.DECRYPT_MODE,?privateKey);int?size?=?privateKey.getModulus().bitLength()?/?8;ByteArrayOutputStream?baos?=?new?ByteArrayOutputStream((secret.length?+?size?-?12)?/?(size?-?11)?*?size);int?left?=?0;for?(int?i?=?0;?i?<?secret.length;?)?{left?=?secret.length?-?i;if?(left?>?size)?{cipher.update(secret,?i,?size);i?+=?size;}?else?{cipher.update(secret,?i,?left);i?+=?left;}baos.write(cipher.doFinal());}return?baos.toByteArray();}?catch?(Exception?e)?{logger.error("rsa?decrypt?failed.",?e);}return?null;}public?byte[]?sign(byte[]?content)?{if?(privateKey?==?null)?{throw?new?RuntimeException("private?key?is?null.");}if?(content?==?null)?{return?null;}try?{Signature?signature?=?Signature.getInstance("SHA1WithRSA");signature.initSign(privateKey);signature.update(content);return?signature.sign();}?catch?(Exception?e)?{throw?new?RuntimeException(e);}}public?boolean?verify(byte[]?sign,?byte[]?content)?{if?(publicKey?==?null)?{throw?new?RuntimeException("public?key?is?null.");}if?(sign?==?null?||?content?==?null)?{return?false;}try?{Signature?signature?=?Signature.getInstance("SHA1WithRSA");signature.initVerify(publicKey);signature.update(content);return?signature.verify(sign);}?catch?(Exception?e)?{logger.error("rsa?verify?failed.",?e);}return?false;} }2.4.6 ECC算法
ECC?也是一種?非對稱加密算法,主要優(yōu)勢是在某些情況下,它比其他的方法使用?更小的密鑰,比如?RSA?加密算法,提供?相當?shù)幕蚋叩燃?/strong>?的安全級別。不過一個缺點是?加密和解密操作?的實現(xiàn)比其他機制?時間長(相比?RSA?算法,該算法對?CPU?消耗嚴重)。
import?net.pocrd.annotation.NotThreadSafe; import?org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; import?org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import?org.bouncycastle.jce.provider.BouncyCastleProvider; import?org.slf4j.Logger; import?org.slf4j.LoggerFactory; import?javax.crypto.Cipher; import?java.io.ByteArrayOutputStream; import?java.security.KeyFactory; import?java.security.Security; import?java.security.Signature; import?java.security.spec.PKCS8EncodedKeySpec; import?java.security.spec.X509EncodedKeySpec;@NotThreadSafe public?class?EccHelper?{private?static?final?Logger?logger?=?LoggerFactory.getLogger(EccHelper.class);private?static?final?int?SIZE?=?4096;private?BCECPublicKey??publicKey;private?BCECPrivateKey?privateKey;static?{Security.addProvider(new?BouncyCastleProvider());}public?EccHelper(String?publicKey,?String?privateKey)?{this(Base64Util.decode(publicKey),?Base64Util.decode(privateKey));}public?EccHelper(byte[]?publicKey,?byte[]?privateKey)?{try?{KeyFactory?keyFactory?=?KeyFactory.getInstance("EC",?"BC");if?(publicKey?!=?null?&&?publicKey.length?>?0)?{this.publicKey?=?(BCECPublicKey)keyFactory.generatePublic(new?X509EncodedKeySpec(publicKey));}if?(privateKey?!=?null?&&?privateKey.length?>?0)?{this.privateKey?=?(BCECPrivateKey)keyFactory.generatePrivate(new?PKCS8EncodedKeySpec(privateKey));}}?catch?(ClassCastException?e)?{throw?new?RuntimeException("",?e);}?catch?(Exception?e)?{throw?new?RuntimeException(e);}}public?EccHelper(String?publicKey)?{this(Base64Util.decode(publicKey));}public?EccHelper(byte[]?publicKey)?{try?{KeyFactory?keyFactory?=?KeyFactory.getInstance("EC",?"BC");if?(publicKey?!=?null?&&?publicKey.length?>?0)?{this.publicKey?=?(BCECPublicKey)keyFactory.generatePublic(new?X509EncodedKeySpec(publicKey));}}?catch?(Exception?e)?{throw?new?RuntimeException(e);}}public?byte[]?encrypt(byte[]?content)?{if?(publicKey?==?null)?{throw?new?RuntimeException("public?key?is?null.");}try?{Cipher?cipher?=?Cipher.getInstance("ECIES",?"BC");cipher.init(Cipher.ENCRYPT_MODE,?publicKey);int?size?=?SIZE;ByteArrayOutputStream?baos?=?new?ByteArrayOutputStream((content.length?+?size?-?1)?/?size?*?(size?+?45));int?left?=?0;for?(int?i?=?0;?i?<?content.length;?)?{left?=?content.length?-?i;if?(left?>?size)?{cipher.update(content,?i,?size);i?+=?size;}?else?{cipher.update(content,?i,?left);i?+=?left;}baos.write(cipher.doFinal());}return?baos.toByteArray();}?catch?(Exception?e)?{throw?new?RuntimeException(e);}}public?byte[]?decrypt(byte[]?secret)?{if?(privateKey?==?null)?{throw?new?RuntimeException("private?key?is?null.");}try?{Cipher?cipher?=?Cipher.getInstance("ECIES",?"BC");cipher.init(Cipher.DECRYPT_MODE,?privateKey);int?size?=?SIZE?+?45;ByteArrayOutputStream?baos?=?new?ByteArrayOutputStream((secret.length?+?size?+?44)?/?(size?+?45)?*?size);int?left?=?0;for?(int?i?=?0;?i?<?secret.length;?)?{left?=?secret.length?-?i;if?(left?>?size)?{cipher.update(secret,?i,?size);i?+=?size;}?else?{cipher.update(secret,?i,?left);i?+=?left;}baos.write(cipher.doFinal());}return?baos.toByteArray();}?catch?(Exception?e)?{logger.error("ecc?decrypt?failed.",?e);}return?null;}public?byte[]?sign(byte[]?content)?{if?(privateKey?==?null)?{throw?new?RuntimeException("private?key?is?null.");}try?{Signature?signature?=?Signature.getInstance("SHA1withECDSA",?"BC");signature.initSign(privateKey);signature.update(content);return?signature.sign();}?catch?(Exception?e)?{throw?new?RuntimeException(e);}}public?boolean?verify(byte[]?sign,?byte[]?content)?{if?(publicKey?==?null)?{throw?new?RuntimeException("public?key?is?null.");}try?{Signature?signature?=?Signature.getInstance("SHA1withECDSA",?"BC");signature.initVerify(publicKey);signature.update(content);return?signature.verify(sign);}?catch?(Exception?e)?{logger.error("ecc?verify?failed.",?e);}return?false;} }2.5 各種加密算法對比
2.5.1 散列算法比較
| SHA-1 | 高 | 慢 |
| MD5 | 中 | 快 |
2.5.2 對稱加密算法比較
| DES | 56位 | 較快 | 低 | 中 |
| 3DES | 112位或168位 | 慢 | 中 | 高 |
| AES | 128、192、256位 | 快 | 高 | 低 |
2.5.3 非對稱加密算法比較
| RSA | 高 | 高 | 中 | 中 |
| ECC | 高 | 高 | 慢 | 高 |
2.5.4 對稱算法與非對稱加密算法
2.5.4.1 對稱算法
密鑰管理:比較難,不適合互聯(lián)網(wǎng),一般用于內(nèi)部系統(tǒng)
安全性:中
加密速度:快好?幾個數(shù)量級?(軟件加解密速度至少快?100?倍,每秒可以加解密數(shù)?M?比特?數(shù)據(jù)),適合大數(shù)據(jù)量的加解密處理
2.5.4.2 非對稱算法
密鑰管理:密鑰容易管理
安全性:高
加密速度:比較慢,適合?小數(shù)據(jù)量?加解密或數(shù)據(jù)簽名
?
3. 小結(jié)
本文介紹了?數(shù)字簽名,加密和解密,對稱加密和非對稱加密,然后詳細介紹了?MD5,SHA-1,HMAC,DES/AES,RSA?和?ECC?這幾種加密算法和代碼示例。
總結(jié)
以上是生活随笔為你收集整理的浅谈常见的七种加密算法及实现(附代码)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 8 开发的 4 大顶级技巧
- 下一篇: 详解 Java 中 4 种 I/O 模型