使用ELGmal演演算法為跨系統呼叫保駕護航
為什麼我們需要加密演演算法?
一般在開發過程中,我們為了保證敏感資料的安全性,才會對操作傳輸的資料進行加密,從而提高整個系統的安全性。
比如,客戶端和服務端的資料互動傳輸,服務端將從資料庫查詢出來的資料通過加密的方式傳遞給客戶端,客戶端也將使用者提交的資料加密後提交給服務端,兩邊都通過對應的解密規則進行解密,這樣在資料傳輸的過程中,一些別有用心的人試圖通過Fiddler這樣的工具進行資料抓包而試圖獲得一些隱私資料將變得極其艱難,這也就達到了我們對資料安全性提升目的。
週一的時候,我接到了一個需求,某領導想要通過系統A免密跳轉到系統B,因為領導覺得再去系統B輸入一次使用者名稱、密碼、驗證碼實在是太繁瑣了,尤其是在他有大量的審批工作要做的情況下。
如果兩個系統統一做的CAS單點登入的前期框架性工作,這件事可以說根本不叫事,但是這個系統A和系統B都是近十年的老系統,肯定是沒有這樣的條件的,於是如何將免密登入的安全性提高就成了這個需求的重中之重了。
整體思路
先拋開加密本身,我先說一下我對這個需求的整體考慮:
具體步驟是:
- 系統A發起免密登入的請求
- 系統B通過加密演演算法得到金鑰(公鑰和私鑰--非對稱加密)
- 系統B將加密後的公鑰返回給系統A
- 系統A解密公鑰後使用公鑰對資料進行加密並提交給系統B
- 系統B拿到密文後用私鑰進行解析
- 解析成功就執行免密登入,失敗就放棄該次操作。
整體的架構思路大致就是如此,這樣就算別有用心的人使用抓包工具對這兩次API請求都進行截獲,也很難獲取到真實的資料資訊了。
加密演演算法選型
用什麼演演算法?
眾所周知,加密方式有兩個常用的大方向,一個是對稱加密,一個是非對稱加密。
對稱加密:用相同的金鑰對原文進行加密和解密,通訊雙方共用一個金鑰。
- 加密過程:原文 + 金鑰 => 密文
- 解密過程:密文 - 金鑰 => 原文
非對稱加密:有兩個金鑰,即公鑰(Public Key)和私鑰(Private Key),對資料進行加密和解密使用不同的金鑰。使用公鑰進行加密,使用私鑰進行解密。
- 加密過程:原文 + 公鑰 => 密文
- 解密過程:密文 - 私鑰 => 原文
對稱加密的缺點:
對稱加密演演算法的缺點:無法確保金鑰被安全傳遞。如果金鑰被截獲,則整個加密密文都是不安全的。
對稱加密的特點:
採用非對稱加密演演算法即使第三方在網路上截獲到密文,但其無法獲得接收方的私鑰,也就無法對密文進行解密,作為接收方務必保證自己私鑰的安全,所以非對稱加密技術解決了金鑰傳輸過程的安全性問題。
好了,看到這裡,大方向肯定定下來了,非對稱加密跑不了了,然後我們看看非對稱加密有哪些加密演演算法呢?
非對稱加密演演算法型別:
RSA、Elgamal、揹包演演算法、Rabin、Diffie-Hellman、ECC(橢圓曲線加密演演算法)。 使用最廣泛的是RSA演演算法,Elgamal是另一種常用的非對稱加密演演算法,考慮到成本和學習曲線的問題,我這次選擇了ElGamal加密演演算法,因為兩點:
-
ElGamal演演算法不是雙向加解密的,RSA是雙向加解密的。
雙向加解密:公鑰、私鑰都可以進行加密和解密(公鑰加密需要私鑰解密、私鑰加密需要公鑰解密)
-
ElGamal我線上查了半天也沒找到解密工具,而RSA我查到了(當然,不確定其是否可用)......
正所謂樹大招風,與其使用RSA這種最常見的非對稱加密,我還是決定選擇一些相對沒那麼熱門的加密方式,這樣一些常見的線上破解網站也不會提供簡單的破解渠道,從而進一步增加資料的安全性,但是冷門,也帶來了一些冷門固有的問題,這個後面再說。
ElGamal演演算法在使用中的一些問題
1.Illegal key size or default parameters
當你找到一些ElGamal或者RSA的既有演演算法的DEMO後,興高采烈的Run起它的main方法後,你有很大概率會遇到這個問題,一臉懵逼的你不用慌張,這是由於美帝的出口限制導致的加密演演算法Key長度的限制,具體原因:
每個國家,尤其是美國,對涉及密碼的軟體產品控制非常嚴格,在美國國內,很多密碼演演算法長度都作了限制,而且某些演演算法在某些國家沒有申請專利,可以"濫"用,而在某些國家卻做了明確限制,不準使用,如此前提下,Sun必須按照慣例行事。
套用中國一句老話:上有政策,下有對策。Oracle也單獨的放出了關於解決這個問題的無政策限制檔案(local_policy.jar和US_export_policy.jar),我們只要下載對應JDK版本的檔案並覆蓋到指定路徑(%JDK_Home%\jre\lib\security)下即可。
2.JDK並不直接支援Elgamal演演算法
這就是冷門帶來的問題了,你並不能直接在JDK中使用ElGamal的演演算法支援,所以必須要引入兩個jar包:
-
bouncycastle 下載地址:
-
commons-codec 下載地址:
這兩個Jar包一個是對ElGamal演演算法本身提供支援的,另一個是對Base64提供支援的,都需要引入到專案中去。
3.ElGamal KeyFactory not available
在實際使用ElGamal演演算法的時候,我們不太可能只在一端使用公鑰和私鑰,這就面臨著我們需要在另一個平臺使用公鑰加密的演演算法,常見的公鑰加密演演算法是這樣寫的:
public static byte[] encryptByPublicKey(byte[] data,byte[] key) throws Exception{
//例項化金鑰工廠
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//初始化公鑰
//金鑰材料轉換
X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
//產生公鑰
PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
//資料加密
Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE,pubKey);
return cipher.doFinal(data);
}
複製程式碼
當你在同一個程式中這樣寫公鑰加密演演算法是沒有問題的,因為你在啟動main方法的時候,已經做好了initKey的相關工作了,但是你在另一個平臺直接呼叫該方法則會報出錯誤:
java.security.NoSuchAlgorithmException: ElGamal KeyFactory not available
複製程式碼
其實這也是冷門後遺症,因為JDK並沒有實現ElGamal演演算法,所以不做初始化就直接用KeyFactory呼叫對應演演算法的KeyFactory例項,是肯定會報錯的,解決方法就是自己做好初始化,走到天下都不怕:
public static byte[] encryptByPublicKey(byte[] data,byte[] key) throws Exception{
//加入對BouncyCastle支援
Security.addProvider(new BouncyCastleProvider());
AlgorithmParameterGenerator apg=AlgorithmParameterGenerator.getInstance(KEY_ALGORITHM);
//初始化引數生成器
apg.init(KEY_SIZE);
// 例項化金鑰生成器
KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM);
//例項化金鑰工廠
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//初始化公鑰
//金鑰材料轉換
X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
//產生公鑰
PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
//資料加密
Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE,pubKey);
return cipher.doFinal(data);
}
複製程式碼
4.Cannot find any provider supporting ElGamal
這個問題就不是每個人都會遇到了,由於我是給服務端的同事寫方法讓他們各自呼叫自己那端需要的加密方法,所以我考慮了將他們需要的類封裝成jar包的想法,於是我就將原始碼各自分離後,進行了基礎的封裝,然後通過Build FatJar將資料封裝成jar包呼叫,測試呼叫的專案也順利的引入了,一切就緒,執行main方法,然後就報錯了.....
java.security.NoSuchAlgorithmException: Cannot find any provider supporting ElGamal
複製程式碼
不支援Elgaml???明明已經加上了對應的初始化方法了啊,怎會不執行呢?
其實這裡,不是不執行初始化的方法,而是所需的第三方jar在jar包內部並沒有被正常載入導致的,我檢查了一下jar的MANIFEST.MF檔案發現合併打包時第三方丟失了Export-Package和Include-Resource對於第三方jar包的描述,解決方案可以檢視:
而我這個專案由於只需要兩個jar包,所以我的解決方案是單獨匯出我的jar包,然後在新專案中獨立引入我匯出的jar包和bouncycastle包以及codec包,這樣一切都可以正常執行了。
總結
以上就是我使用ElGamal演演算法時遇到的一些問題,希望大家在使用的過程中儘量避開這些問題,也為自己做個記錄。