通常在開發過程當中,咱們爲了保證敏感數據的安全性,纔會對操做傳輸的數據進行加密,從而提升整個系統的安全性。html
好比,客戶端和服務端的數據交互傳輸,服務端將從數據庫查詢出來的數據經過加密的方式傳遞給客戶端,客戶端也將用戶提交的數據加密後提交給服務端,兩邊都經過對應的解密規則進行解密,這樣在數據傳輸的過程當中,一些別有用心的人試圖經過Fiddler這樣的工具進行數據抓包而試圖得到一些隱私數據將變得極其艱難,這也就達到了咱們對數據安全性提高目的。java
週一的時候,我接到了一個需求,某領導想要經過系統A免密跳轉到系統B,由於領導以爲再去系統B輸入一次用戶名、密碼、驗證碼實在是太繁瑣了,尤爲是在他有大量的審批工做要作的狀況下。算法
若是兩個系通通一作的CAS單點登陸的前期框架性工做,這件事能夠說根本不叫事,可是這個系統A和系統B都是近十年的老系統,確定是沒有這樣的條件的,因而如何將免密登陸的安全性提升就成了這個需求的重中之重了。數據庫
先拋開加密自己,我先說一下我對這個需求的總體考慮:apache
具體步驟是:安全
總體的架構思路大體就是如此,這樣就算別有用心的人使用抓包工具對這兩次API請求都進行截獲,也很難獲取到真實的數據信息了。網絡
用什麼算法?架構
衆所周知,加密方式有兩個經常使用的大方向,一個是對稱加密,一個是非對稱加密。框架
對稱加密:用相同的密鑰對原文進行加密和解密,通訊雙方共用一個密鑰。ide
- 加密過程:原文 + 密鑰 => 密文
- 解密過程:密文 - 密鑰 => 原文
非對稱加密:有兩個密鑰,即公鑰(Public Key)和私鑰(Private Key),對數據進行加密和解密使用不一樣的密鑰。使用公鑰進行加密,使用私鑰進行解密。
- 加密過程:原文 + 公鑰 => 密文
- 解密過程:密文 - 私鑰 => 原文
對稱加密的缺點:
對稱加密算法的缺點:沒法確保密鑰被安全傳遞。若是密鑰被截獲,則整個加密密文都是不安全的。
對稱加密的特色:
採用非對稱加密算法即便第三方在網絡上截獲到密文,但其沒法得到接收方的私鑰,也就沒法對密文進行解密,做爲接收方務必保證本身私鑰的安全,因此非對稱加密技術解決了密鑰傳輸過程的安全性問題。
好了,看到這裏,大方向確定定下來了,非對稱加密跑不了了,而後咱們看看非對稱加密有哪些加密算法呢?
RSA、Elgamal、揹包算法、Rabin、Diffie-Hellman、ECC(橢圓曲線加密算法)。 使用最普遍的是RSA算法,Elgamal是另外一種經常使用的非對稱加密算法,考慮到成本和學習曲線的問題,我此次選擇了ElGamal加密算法,由於兩點:
ElGamal算法不是雙向加解密的,RSA是雙向加解密的。
雙向加解密:公鑰、私鑰均可以進行加密和解密(公鑰加密須要私鑰解密、私鑰加密須要公鑰解密)
ElGamal我在線查了半天也沒找到解密工具,而RSA我查到了(固然,不肯定其是否可用)......
正所謂樹大招風,與其使用RSA這種最多見的非對稱加密,我仍是決定選擇一些相對沒那麼熱門的加密方式,這樣一些常見的在線破解網站也不會提供簡單的破解渠道,從而進一步增長數據的安全性,可是冷門,也帶來了一些冷門固有的問題,這個後面再說。
當你找到一些ElGamal或者RSA的既有算法的DEMO後,興高采烈的Run起它的main方法後,你有很大機率會遇到這個問題,一臉懵逼的你不用慌張,這是因爲美帝的出口限制致使的加密算法Key長度的限制,具體緣由:
每一個國家,尤爲是美國,對涉及密碼的軟件產品控制很是嚴格,在美國國內,不少密碼算法長度都做了限制,並且某些算法在某些國家沒有申請專利,能夠"濫"用,而在某些國家卻作了明確限制,不許使用,如此前提下,Sun必須按照慣例行事。
套用中國一句老話:上有政策,下有對策。Oracle也單獨的放出了關於解決這個問題的無政策限制文件(local_policy.jar和US_export_policy.jar),咱們只要下載對應JDK版本的文件並覆蓋到指定路徑(%JDK_Home%\jre\lib\security)下便可。
這就是冷門帶來的問題了,你並不能直接在JDK中使用ElGamal的算法支持,因此必需要引入兩個jar包:
bouncycastle 下載地址:
commons-codec 下載地址:
這兩個Jar包一個是對ElGamal算法自己提供支持的,另外一個是對Base64提供支持的,都須要引入到項目中去。
在實際使用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);
}
複製代碼
這個問題就不是每一個人都會遇到了,因爲我是給服務端的同事寫方法讓他們各自調用本身那端須要的加密方法,因此我考慮了將他們須要的類封裝成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算法時遇到的一些問題,但願你們在使用的過程當中儘可能避開這些問題,也爲本身作個記錄。