週末給女友講了遍加密演算法,沒想到...
大家好,我是小羽
哈哈哈,其實只是週末看了小舞而已啦,鐵鐵們沒追更的,趕快去補一下這集,特效炸裂。好了,不扯了,進入正題,最近做的專案,涉及到一些加密演算法的選擇,小羽在這裡順便也給大家做個總結,一起加深對加密的相關認識。
目前比較常用的加密演算法總結起來就是單向加密和雙向加密了,其實很簡單,理解也不難。但是小羽覺得還是很有必要對其原理進行清晰的認知的,這樣在我們的開發中才會得心應手。畢竟對於我們研發來說,資料安全是第一位,加密演算法對維護軟體的資料安全起著舉足輕重的作用。來跟著小羽看看這些演算法都用在了哪些方面,怎麼用的,程式碼具體如何實現的。慢慢讀完,你會對這些小密碼有更深入的瞭解。
前言
今天給大家帶來的的是關於加密演算法的來世今生。
其實早在古希臘時期,人類發明了置換密碼。到1881年世界上的第一個電話保密專利出現。二戰期間,德國軍方啟用“恩尼格瑪”密碼機,密碼學在戰爭中起著非常重要的作用。
在1997年,美國國家標準局公佈實施了“美國資料加密標準(DES)”,民間力量開始全面介入密碼學的研究和應用中,採用的加密演算法有 DES、RSA、SHA
等。隨著對加密強度需求的不斷提高,近期又出現了AES、ECC
等。
好了,歷史講完了,該進入正文了,先來看看使用加密演算法對我們有啥好處。
使用密碼學可以達到以下目的:
保密性:防止使用者的標識或資料被讀取。
資料完整性:防止資料被更改。
身份驗證:確保資料發自特定的一方。
單向加密
通俗來說,就是通過對資料進行摘要計算生成密文,密文不可逆推還原。演算法代表:MD5、SHA、HMAC等。
單向加密
MD5
MD5
-- message-digest algorithm 5 (資訊-摘要演算法)縮寫,廣泛用於加密和解密技術,常用於檔案校驗。不管檔案多大,經過MD5後都能生成唯一的 MD5
值。好比現在的 ISO 校驗,都是 MD5 校驗,把 ISO 經過 MD5 後產生 MD5 的值。一般下載 linux-ISO
的朋友都見過下載連結旁邊放著 MD5 的串。就是用來驗證檔案是否一致的。
加密工具類如下:
/** * MD5加密 * * @param data * @return * @throws Exception */ public static byte[] encryptMD5(byte[] data) throws Exception { MessageDigest md5 = MessageDigest.getInstance(KEY_MD5); md5.update(data); return md5.digest(); }
SHA
SHA
(Secure Hash Algorithm,安全雜湊演算法),數字簽名等密碼學應用中重要的工具,被廣泛地應用於電子商務等資訊保安領域。雖然, SHA 與 MD5 通過碰撞法都被破解了,但是 SHA 仍然是公認的安全加密演算法,較之MD5更為安全。
加密工具類如下:
/** * SHA加密 * * @param data * @return * @throws Exception */ public static byte[] encryptSHA(byte[] data) throws Exception { MessageDigest sha = MessageDigest.getInstance(KEY_SHA); sha.update(data); return sha.digest(); } }
HMAC
HMAC
(Hash Message Authentication Code ,雜湊訊息鑑別碼,基於金鑰的 Hash 演算法的認證協議。訊息鑑別碼實現鑑別的原理是,用公開函式和金鑰產生一個固定長度的值作為認證標識,用這個標識鑑別訊息的完整性。使用一個金鑰生成一個固定大小的小資料塊,即 MAC
,並將其加入到訊息中,然後傳輸。接收方利用與傳送方共享的金鑰進行鑑別認證等。
加密工具類如下:
/** * 初始化HMAC金鑰 * * @return * @throws Exception */ public static String initMacKey() throws Exception { KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC); SecretKey secretKey = keyGenerator.generateKey(); return encryptBASE64(secretKey.getEncoded()); } /** * HMAC加密 * * @param data * @param key * @return * @throws Exception */ public static byte[] encryptHMAC(byte[] data, String key) throws Exception { SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC); Mac mac = Mac.getInstance(secretKey.getAlgorithm()); mac.init(secretKey); return mac.doFinal(data); }
雙向加密
雙向加密又稱為可逆加密,即生成密文後,在需要的時候可以反解為明文,雙向加密分為對稱加密和非對稱加密。
對稱加密演算法
對稱加密演算法是應用較早的加密演算法,技術成熟。在對稱加密演算法中,資料發信方將明文(原始資料)和加密金鑰一起經過特殊加密演算法處理後,使其變成複雜的加密密文傳送出去。在對稱加密演算法中,使用的金鑰只有一個,發收信雙方都使用這個金鑰對資料進行加密和解密,這就要求解密方事先必須知道加密金鑰。對稱加密演算法的特點是8演算法公開、計算量小、加密速度快、加密效率高。不足之處是,交易雙方都使用同樣鑰匙,安全性得不到保證*。對稱加密演算法在分散式網路系統上使用較為困難,主要是因為金鑰管理困難,使用成本較高。
資料加密過程:在對稱加密演算法中,資料傳送方將明文(原始資料)和加密金鑰一起經過特殊加密處理,生成複雜的加密密文進行傳送。
資料解密過程:資料接收方收到密文後,若想讀取原資料,則需要使用加密使用的金鑰及相同演算法的逆演算法對加密的密文進行解密,才能使其恢復成可讀明文。
常用演算法:DES、3DES、AES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、Skipjack 等。下面主要介紹常用的 DES、3DES、AES
加密演算法。
DES加密演算法
DES 加密演算法是一種分組密碼,以 64
位為分組對資料加密,它的金鑰長度是 56
位,加密解密用同一演算法。DES 加密演算法是對金鑰進行保密,而公開演算法,包括加密和解密演算法。這樣,只有掌握了和傳送方相同金鑰的人才能解讀由DES加密演算法加密的密文資料。因此,破譯 DES 加密演算法實際上就是搜尋金鑰的編碼。對於 56 位長度的金鑰來說,如果用窮舉法來進行搜尋的話,其運算次數為 256
。
隨著計算機系統能力的不斷髮展, DES 的安全性比它剛出現時會弱得多,然而從非關鍵性質的實際出發,仍可以認為它是足夠的。不過, DES 現在僅用於舊系統的鑑定,而更多地選擇新的加密標準。
加密工具類如下:
/** * 加密 * * @param datasource 待加密資料 * @param key * @return byte陣列 */ public static byte[] enCrypto(byte[] datasource, String key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException { SecureRandom random = new SecureRandom(); DESKeySpec desKey = new DESKeySpec(key.getBytes()); // 建立一個密匙工廠,然後用它把DESKeySpec轉換成 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey securekey = keyFactory.generateSecret(desKey); // Cipher物件實際完成加密操作 Cipher cipher = Cipher.getInstance("DES"); // 用密匙初始化Cipher物件 cipher.init(Cipher.ENCRYPT_MODE, securekey, random); // 現在,獲取資料並加密 // 正式執行加密操作 return cipher.doFinal(datasource); }
3DES加密演算法
DES 是三重資料加密演算法塊密碼的通稱。它相當於是對每個資料塊應用三次 DES 加密演算法。由於計算機運算能力的增強,原版DES密碼的金鑰長度變得容易被暴力破解;3DES即是設計用來提供一種相對簡單的方法,即通過增加 DES
的金鑰長度來避免類似的攻擊,而不是設計一種全新的塊密碼演算法。
3DES 是 DES 向 AES 過渡的加密演算法,加密演算法,其具體實現如下:設 Ek()
和 Dk()
代表 DES 演算法的加密和解密過程, K
代表 DES 演算法使用的金鑰, M
代表明文, C
代表密文。加密過程為:C=Ek3(Dk2(Ek1(M)))
加密工具類如下:
/** * 方法描述:3DES加密 * * @param plainText 明文 * @param secretKey 金鑰 * @param iv 加密向量 * @return String 密文 * @throws Exception */ public static String encode(String plainText, String secretKey, String iv) throws Exception { Key deskey = null; DESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes()); SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede"); deskey = keyfactory.generateSecret(spec); Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding"); IvParameterSpec ips = new IvParameterSpec(iv.getBytes()); cipher.init(Cipher.ENCRYPT_MODE, deskey, ips); byte[] encryptData = cipher.doFinal(plainText.getBytes(encoding)); return Base64.encode(encryptData); }
AES加密演算法
AES 加密演算法是密碼學中的高階加密標準,該加密演算法採用對稱分組密碼體制,金鑰長度的最少支援為 128
、192
、 256
,分組長度 128
位,演算法應易於各種硬體和軟體實現。這種加密演算法是美國聯邦政府採用的區塊加密標準,這個標準用來替代原先的 DES
,已經被多方分析且廣為全世界所使用。
AES 加密演算法被設計為支援 128/192/256
位(/32=nb)資料塊大小(即分組長度);支援 128/192/256
位(/32=nk) 密碼長度,,在 10 進位制裡,對應 34×1038、62×1057、1.1×1077
個金鑰。
加密工具類如下:
/** * AES加密 * @param data 要加密的字串 * @param key 加密key * @param iv 密碼加密演算法中的IV * @return 加密後的字串 */ public static String encrypt(String data, String key, String iv) { try { Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); int blockSize = cipher.getBlockSize(); byte[] dataBytes = data.getBytes(); int plaintextLength = dataBytes.length; if (plaintextLength % blockSize != 0) { plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize)); } byte[] plaintext = new byte[plaintextLength]; System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length); SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), Constant.STRING_AES); IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes(Constant.STRING_UTF_8)); cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec); byte[] encrypted = cipher.doFinal(plaintext); String encrypt = Base64.getEncoder().encodeToString(encrypted); //BASE64加密 encrypt = encrypt.replaceAll(new String(Constant.STRING_CARRIAGE_RETURN), Constant.STRING_BLANK); encrypt = encrypt.replaceAll(new String(Constant.STRING_LINE_FEED), Constant.STRING_BLANK); return encrypt; } catch (Exception e) { e.printStackTrace(); return null; } }
對稱加密演算法比較
非對稱加密演算法
不對稱加密演算法使用兩把完全不同但又是完全匹配的一對鑰匙—公鑰和私鑰。在使用不對稱加密演算法加密檔案時,只有使用匹配的一對公鑰和私鑰,才能完成對明文的加密和解密過程。採用不對稱加密演算法,收發信雙方在通訊之前,收信方必須將自己早已隨機生成的公鑰送給發信方,而自己保留私鑰。由於不對稱演算法擁有兩個金鑰,因而特別適用於分散式系統中的資料加密。廣泛應用的不對稱加密演算法有 RSA
演算法和美國國家標準局提出的 DSA
。以不對稱加密演算法為基礎的加密技術應用非常廣泛。
工作流程:
1、乙方生成一對金鑰(公鑰和私鑰)並將公鑰向其它方公開。
2、得到該公鑰的甲方使用該金鑰對機密資訊進行加密後再發送給乙方。
3、乙方再用自己儲存的另一把專用金鑰(私鑰)對加密後的資訊進行解密。乙方只能用其專用金鑰(私鑰)解密由對應的公鑰加密後的資訊。
在傳輸過程中,即使攻擊者截獲了傳輸的密文,並得到了乙的公鑰,也無法破解密文,因為只有乙的私鑰才能解密密文。
同樣,如果乙要回復加密資訊給甲,那麼需要甲先公佈甲的公鑰給乙用於加密,甲自己儲存甲的私鑰用於解密。
RSA加密演算法
RSA 加密演算法是目前最有影響力的公鑰加密演算法,並且被普遍認為是目前最優秀的公鑰方案之一。RSA 是第一個能同時用於加密和數宇簽名的演算法,它能夠抵抗到目前為止已知的所有密碼攻擊,已被 ISO
推薦為公鑰資料加密標準。RSA 加密演算法基於一個十分簡單的數論事實:將兩個大素數相乘十分容易,但那時想要,但那時想要對其乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密金鑰。
加密工具類如下:
/** * RSA公鑰加密 * * @param str 加密字串 * @param publicKey 公鑰 * @return 密文 * @throws Exception 加密過程中的異常資訊 */ public static String encrypt( String str, String publicKey ) throws Exception{ //base64編碼的公鑰 byte[] decoded = Base64.decodeBase64(publicKey); RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded)); //RSA加密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, pubKey); String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8"))); return outStr; }
DSA加密演算法
DSA 是基於整數有限域離散對數難題的,其安全性與 RSA 相比差不多。DSA 的一個重要特點是兩個素數公開,這樣,當使用別人的 p 和 q 時,即使不知道私鑰,你也能確認它們是否是隨機產生的,還是作了手腳。RSA演算法卻做不到。DSA 只是一種演算法,和 RSA 不同之處在於它不能用作加密和解密,也不能進行金鑰交換,只用於簽名,它比RSA要快很多.
加密流程如下:
ECC加密演算法
橢圓加密演算法(ECC)是一種公鑰加密體制,最初由 Koblitz
和 Miller
兩人於 1985 年提出,其數學基礎是利用橢圓曲線上的有理點構成 Abel
加法群上橢圓離散對數的計算困難性。公鑰密碼體制根據其所依據的難題一般分為三類:大整數分解問題類、離散對數問題類、橢圓曲線類。有時也把橢圓曲線類歸為離散對數類。橢圓曲線密碼體制是目前已知的公鑰體制中,對每位元所提供加密強度最高的一種體制。解橢圓曲線上的離散對數問題的最好演算法是 Pollard rho
方法,其時間複雜度為,是完全指數階的。
加密工具類如下:
/** * 加密 * @param data * @param publicKey * @return * @throws Exception */ public static byte[] encrypt(byte[] data, String publicKey) throws Exception { byte[] keyBytes = BASE64Decoder.decodeBuffer(publicKey); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(ECCEnum.ALGORITHM.value()); ECPublicKey pubKey = (ECPublicKey) keyFactory .generatePublic(x509KeySpec); Cipher cipher = new NullCipher(); cipher.init(Cipher.ENCRYPT_MODE, pubKey); return cipher.doFinal(data); }
非對稱加密演算法比較
總結
對稱加密和非對稱加密比較
實際應用:
採用非對稱加密演算法管理對稱演算法的金鑰,用對稱加密演算法加密資料,即提高了加密速度,又實現瞭解密的安全
RSA 建議採用 1024
位的數字, ECC 建議採用160
位, AES 採用128
位即可
其它方面的比較:
在管理方面:公鑰密碼演算法只需要較少的資源就可以實現目的,在金鑰的分配上,兩者之間相差一個指數級別(一個是n一個是n2)。所以公鑰密碼演算法不適應廣域網的使用,而且更重要的一點是它不支援數字簽名。
在安全方面:由於公鑰密碼演算法基於未解決的數學難題,在破解上幾乎不可能。對於私鑰密碼演算法,到了AES雖說從理論來說是不可能破解的,但從計算機的發展角度來看。公鑰更具有優越性。