使用ELGmal算法為跨系統(tǒng)調(diào)用保駕護航

為什么我們需要加密算法?

一般在開發(fā)過程中,我們?yōu)榱吮WC敏感數(shù)據(jù)的安全性,才會對操作傳輸?shù)臄?shù)據(jù)進行加密,從而提高整個系統(tǒng)的安全性。

比如,客戶端和服務端的數(shù)據(jù)交互傳輸,服務端將從數(shù)據(jù)庫查詢出來的數(shù)據(jù)通過加密的方式傳遞給客戶端,客戶端也將用戶提交的數(shù)據(jù)加密后提交給服務端,兩邊都通過對應的解密規(guī)則進行解密,這樣在數(shù)據(jù)傳輸?shù)倪^程中,一些別有用心的人試圖通過Fiddler這樣的工具進行數(shù)據(jù)抓包而試圖獲得一些隱私數(shù)據(jù)將變得極其艱難,這也就達到了我們對數(shù)據(jù)安全性提升目的。

周一的時候,我接到了一個需求,某領導想要通過系統(tǒng)A免密跳轉(zhuǎn)到系統(tǒng)B,因為領導覺得再去系統(tǒng)B輸入一次用戶名、密碼、驗證碼實在是太繁瑣了,尤其是在他有大量的審批工作要做的情況下。

如果兩個系統(tǒng)統(tǒng)一做的CAS單點登錄的前期框架性工作,這件事可以說根本不叫事,但是這個系統(tǒng)A和系統(tǒng)B都是近十年的老系統(tǒng),肯定是沒有這樣的條件的,于是如何將免密登錄的安全性提高就成了這個需求的重中之重了。

整體思路

先拋開加密本身,我先說一下我對這個需求的整體考慮:

1.jpg

具體步驟是:

  1. 系統(tǒng)A發(fā)起免密登錄的請求
  2. 系統(tǒng)B通過加密算法得到密鑰(公鑰和私鑰--非對稱加密)
  3. 系統(tǒng)B將加密后的公鑰返回給系統(tǒng)A
  4. 系統(tǒng)A解密公鑰后使用公鑰對數(shù)據(jù)進行加密并提交給系統(tǒng)B
  5. 系統(tǒng)B拿到密文后用私鑰進行解析
  6. 解析成功就執(zhí)行免密登錄,失敗就放棄該次操作。

整體的架構(gòu)思路大致就是如此,這樣就算別有用心的人使用抓包工具對這兩次API請求都進行截獲,也很難獲取到真實的數(shù)據(jù)信息了。

加密算法選型

用什么算法?

眾所周知,加密方式有兩個常用的大方向,一個是對稱加密,一個是非對稱加密。

對稱加密:用相同的密鑰對原文進行加密和解密,通信雙方共用一個密鑰。

  • 加密過程:原文 + 密鑰 => 密文
  • 解密過程:密文 - 密鑰 => 原文

非對稱加密:有兩個密鑰,即公鑰(Public Key)和私鑰(Private Key),對數(shù)據(jù)進行加密和解密使用不同的密鑰。使用公鑰進行加密,使用私鑰進行解密。

  • 加密過程:原文 + 公鑰 => 密文
  • 解密過程:密文 - 私鑰 => 原文

對稱加密的缺點:

? 對稱加密算法的缺點:無法確保密鑰被安全傳遞。如果密鑰被截獲,則整個加密密文都是不安全的。

對稱加密的特點:

? 采用非對稱加密算法即使第三方在網(wǎng)絡上截獲到密文,但其無法獲得接收方的私鑰,也就無法對密文進行解密,作為接收方務必保證自己私鑰的安全,所以非對稱加密技術(shù)解決了密鑰傳輸過程的安全性問題。

好了,看到這里,大方向肯定定下來了,非對稱加密跑不了了,然后我們看看非對稱加密有哪些加密算法呢?

非對稱加密算法類型:

RSA、Elgamal、背包算法、Rabin、Diffie-Hellman、ECC(橢圓曲線加密算法)。
使用最廣泛的是RSA算法,Elgamal是另一種常用的非對稱加密算法,考慮到成本和學習曲線的問題,我這次選擇了ElGamal加密算法,因為兩點:

  1. ElGamal算法不是雙向加解密的,RSA是雙向加解密的。

    雙向加解密:公鑰、私鑰都可以進行加密和解密(公鑰加密需要私鑰解密、私鑰加密需要公鑰解密)

  2. ElGamal我在線查了半天也沒找到解密工具,而RSA我查到了(當然,不確定其是否可用)......

正所謂樹大招風,與其使用RSA這種最常見的非對稱加密,我還是決定選擇一些相對沒那么熱門的加密方式,這樣一些常見的在線破解網(wǎng)站也不會提供簡單的破解渠道,從而進一步增加數(shù)據(jù)的安全性,但是冷門,也帶來了一些冷門固有的問題,這個后面再說。

ElGamal算法在使用中的一些問題

1.Illegal key size or default parameters

當你找到一些ElGamal或者RSA的既有算法的DEMO后,興高采烈的Run起它的main方法后,你有很大概率會遇到這個問題,一臉懵逼的你不用慌張,這是由于美帝的出口限制導致的加密算法Key長度的限制,具體原因:

每個國家,尤其是美國,對涉及密碼的軟件產(chǎn)品控制非常嚴格,在美國國內(nèi),很多密碼算法長度都作了限制,而且某些算法在某些國家沒有申請專利,可以"濫"用,而在某些國家卻做了明確限制,不準使用,如此前提下,Sun必須按照慣例行事。

套用中國一句老話:上有政策,下有對策。Oracle也單獨的放出了關于解決這個問題的無政策限制文件(local_policy.jar和US_export_policy.jar),我們只要下載對應JDK版本的文件并覆蓋到指定路徑(%JDK_Home%\jre\lib\security)下即可。

2.JDK并不直接支持Elgamal算法

這就是冷門帶來的問題了,你并不能直接在JDK中使用ElGamal的算法支持,所以必須要引入兩個jar包:

  1. bouncycastle 下載地址:

    http://www.bouncycastle.org/latest_releases.html

  2. commons-codec 下載地址:

    http://archive.apache.org/dist/commons/codec/binaries/

這兩個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);
        //初始化公鑰
        //密鑰材料轉(zhuǎn)換
        X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
        //產(chǎn)生公鑰
        PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
        
        //數(shù)據(jù)加密
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return cipher.doFinal(data);
    }

當你在同一個程序中這樣寫公鑰加密算法是沒有問題的,因為你在啟動main方法的時候,已經(jīng)做好了initKey的相關工作了,但是你在另一個平臺直接調(diào)用該方法則會報出錯誤:

java.security.NoSuchAlgorithmException: ElGamal KeyFactory not available

其實這也是冷門后遺癥,因為JDK并沒有實現(xiàn)ElGamal算法,所以不做初始化就直接用KeyFactory調(diào)用對應算法的KeyFactory實例,是肯定會報錯的,解決方法就是自己做好初始化,走到天下都不怕:

    public static byte[] encryptByPublicKey(byte[] data,byte[] key) throws Exception{
       //加入對BouncyCastle支持
        Security.addProvider(new BouncyCastleProvider());
        AlgorithmParameterGenerator apg=AlgorithmParameterGenerator.getInstance(KEY_ALGORITHM);
        //初始化參數(shù)生成器
        apg.init(KEY_SIZE);
        // 實例化密鑰生成器
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM);
       //實例化密鑰工廠
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
        //初始化公鑰
        //密鑰材料轉(zhuǎn)換
        X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
        //產(chǎn)生公鑰
        PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);    
        //數(shù)據(jù)加密
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return cipher.doFinal(data);
    }

4.Cannot find any provider supporting ElGamal

這個問題就不是每個人都會遇到了,由于我是給服務端的同事寫方法讓他們各自調(diào)用自己那端需要的加密方法,所以我考慮了將他們需要的類封裝成jar包的想法,于是我就將源碼各自分離后,進行了基礎的封裝,然后通過Build FatJar將數(shù)據(jù)封裝成jar包調(diào)用,測試調(diào)用的項目也順利的引入了,一切就緒,運行main方法,然后就報錯了.....

java.security.NoSuchAlgorithmException: Cannot find any provider supporting ElGamal

不支持Elgaml???明明已經(jīng)加上了對應的初始化方法了啊,怎會不執(zhí)行呢?

其實這里,不是不執(zhí)行初始化的方法,而是所需的第三方jar在jar包內(nèi)部并沒有被正常加載導致的,我檢查了一下jar的MANIFEST.MF文件發(fā)現(xiàn)合并打包時第三方丟失了Export-Package和Include-Resource對于第三方jar包的描述,解決方案可以查看:

https://www.cnblogs.com/skyme/articles/2316457.html

而我這個項目由于只需要兩個jar包,所以我的解決方案是單獨導出我的jar包,然后在新項目中獨立引入我導出的jar包和bouncycastle包以及codec包,這樣一切都可以正常執(zhí)行了。

總結(jié)

以上就是我使用ElGamal算法時遇到的一些問題,希望大家在使用的過程中盡量避開這些問題,也為自己做個記錄。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容