數(shù)據(jù)傳輸加密——非對稱加密算法RSA+對稱算法AES(適用于java,android和Web)

數(shù)據(jù)傳輸加密

在開發(fā)應(yīng)用過程中援制,客戶端與服務(wù)端經(jīng)常需要進(jìn)行數(shù)據(jù)傳輸晨仑,涉及到重要隱私信息時洪己,開發(fā)者自然會想到對其進(jìn)行加密答捕,即使傳輸過程中被“有心人”截取噪珊,也不會將信息泄露。對于加密算法磷箕,相信不少開發(fā)者也有所耳聞岳枷,比如MD5加密空繁,Base64加密朱庆,DES加密娱颊,AES加密箱硕,RSA加密等等剧罩。在這里我主要向大家介紹一下我在開發(fā)過程中使用到的加密算法,RSA加密算法+AES加密算法幕与。簡單地介紹一下這兩種算法吧纽门。

RSA

之所以叫RSA算法赏陵,是因為算法的三位發(fā)明者RSA是目前最有影響力的公鑰加密算法饼齿,它能夠抵抗到目前為止已知的絕大多數(shù)密碼攻擊,已被ISO推薦為公鑰數(shù)據(jù)加密標(biāo)準(zhǔn)蝙搔,主要的算法原理就不多加介紹缕溉,如果對此感興趣的話,建議去百度一下RSA算法吃型。需要了解的是RSA算法屬于非對稱加密算法证鸥,非對稱加密算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。公開密鑰與私有密鑰是一對勤晚,如果用公開密鑰對數(shù)據(jù)進(jìn)行加密,只有用對應(yīng)的私有密鑰才能解密赐写;如果用私有密鑰對數(shù)據(jù)進(jìn)行加密鸟蜡,那么只有用對應(yīng)的公開密鑰才能解密。因為加密和解密使用的是兩個不同的密鑰挺邀,所以這種算法叫作非對稱加密算法揉忘。簡單的說是“公鑰加密,私鑰解密端铛;私鑰加密泣矛,公鑰解密”。

AES

高級加密標(biāo)準(zhǔn)(英語:Advanced Encryption Standard禾蚕,縮寫:AES)您朽,在密碼學(xué)中又稱Rijndael加密法,是美國聯(lián)邦政府采用的一種區(qū)塊加密標(biāo)準(zhǔn)夕膀。這個標(biāo)準(zhǔn)用來替代原先的DES虚倒,已經(jīng)被多方分析且廣為全世界所使用。經(jīng)過五年的甄選流程产舞,高級加密標(biāo)準(zhǔn)由美國國家標(biāo)準(zhǔn)與技術(shù)研究院(NIST)于2001年11月26日發(fā)布于FIPS PUB 197,并在2002年5月26日成為有效的標(biāo)準(zhǔn)菠剩。2006年易猫,高級加密標(biāo)準(zhǔn)已然成為對稱密鑰加密中最流行的算法之一。

為什么要結(jié)合使用這兩種算法

如果不清楚非對稱算法和對稱算法具壮,也許你會問准颓,為什么要結(jié)合使用這兩種算法,單純使用一種算法不行嗎棺妓?這就要結(jié)合不同的場景和需求了攘已。

客戶端傳輸重要信息給服務(wù)端,服務(wù)端返回的信息不需加密的情況

客戶端傳輸重要信息給服務(wù)端怜跑,服務(wù)端返回的信息不需加密样勃,例如綁定銀行卡的時候吠勘,需要傳遞用戶的銀行卡號,手機(jī)號等重要信息峡眶,客戶端這邊就需要對這些重要信息進(jìn)行加密剧防,使用RSA公鑰加密,服務(wù)端使用RSA解密辫樱,然后返回一些普通信息峭拘,比如狀態(tài)碼code,提示信息msg,提示操作是成功還是失敗。這種場景下狮暑,僅僅使用RSA加密是可以的鸡挠。

客戶端傳輸重要信息給服務(wù)端,服務(wù)端返回的信息需加密的情況

客戶端傳輸重要信息給服務(wù)端搬男,服務(wù)端返回的信息需加密,例如客戶端登錄的時候宵凌,傳遞用戶名和密碼等資料,需要進(jìn)行加密止后,服務(wù)端驗證登錄信息后瞎惫,返回令牌token需要進(jìn)行加密,客戶端解密后保存译株。此時就需要結(jié)合這兩種算法了瓜喇。至于整個流程是怎樣的,在下面會慢慢通過例子向你介紹歉糜,因為如果一開始就這么多文字類的操作乘寒,可能會讓讀者感到一頭霧水。

使用RSA加密和解密

產(chǎn)生公鑰和私鑰

產(chǎn)生RSA公鑰和密鑰的方法有很多匪补,在這里我直接使用我封裝好的方法產(chǎn)生伞辛,都最后我會將兩個算法的工具類贈送給大家。

/**
 * 生成公鑰和私鑰
 * 
 * @throws Exception
 * 
 */
public static void getKeys() throws Exception {
    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
    keyPairGen.initialize(1024);
    KeyPair keyPair = keyPairGen.generateKeyPair();
    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
    RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

    String publicKeyStr = getPublicKeyStr(publicKey);
    String privateKeyStr = getPrivateKeyStr(privateKey);

    System.out.println("公鑰\r\n" + publicKeyStr);
    System.out.println("私鑰\r\n" + privateKeyStr);
}

public static String getPrivateKeyStr(PrivateKey privateKey)
        throws Exception {
    return new String(Base64Utils.encode(privateKey.getEncoded()));
}

public static String getPublicKeyStr(PublicKey publicKey) throws Exception {
    return new String(Base64Utils.encode(publicKey.getEncoded()));
}

公鑰

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCRQZ5O/AOAjeYAaSFf6Rjhqovws78I716I9oGF7WxCIPmcaUa1YuyLOncCCuPsaw69+RMWjdbOBp8hd4PPM/d4mKTOVEYUE0SfxhhDTZaM5CzQEUXUyXy7icQTGR5wBjrbjU1yHCKOf5PJJZZQWB06husSFZ40TdL7FdlBpZ1u1QIDAQAB

私鑰

MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJFBnk78A4CN5gBpIV/pGOGqi/CzvwjvXoj2gYXtbEIg+ZxpRrVi7Is6dwIK4+xrDr35ExaN1s4GnyF3g88z93iYpM5URhQTRJ/GGENNlozkLNARRdTJfLuJxBMZHnAGOtuNTXIcIo5/k8klllBYHTqG6xIVnjRN0vsV2UGlnW7VAgMBAAECgYBMoT9xD8aRNUrXgJ7YyFIWCzEUZN8tSYqn2tPt4ZkxMdA9UdS5sFx1/vv1meUwPjJiylnlliJyQlAFCdYBo7qzmib8+3Q8EU3MDP9bNlpxxC1go57/q/TbaymWyOk3pK2VXaX+8vQmllgRZMQRi2JFBHVoep1f1x7lSsf2TpipgQJBANJlO+UDmync9X/1YdrVaDOi4o7g3w9u1eVq9B01+WklAP3bvxIoBRI97HlDPKHx+CZXeODx1xj0xPOK3HUz5FECQQCwvdagPPtWHhHx0boPF/s4ZrTUIH04afuePUuwKTQQRijnl0eb2idBe0z2VAH1utPps/p4SpuT3HI3PJJ8MlVFAkAFypuXdj3zLQ3k89A5wd4Ybcdmv3HkbtyccBFALJgs+MPKOR5NVaSuF95GiD9HBe4awBWnu4B8Q2CYg54F6+PBAkBKNgvukGyARnQGc6eKOumTTxzSjSnHDElIsjgbqdFgm/UE+TJqMHmXNyyjqbaA9YeRc67R35HfzgpvQxHG8GN5AkEAxSKOlfACUCQ/CZJovETMmaUDas463hbrUznp71uRMk8RP7DY/lBnGGMeUeeZLIVK5X2Ngcp9nJQSKWCGtpnfLQ==

很明顯夯缺,公鑰字符串長度比較短蚤氏,私鑰的比較長。生成完密鑰后踊兜,公鑰可以存放在客戶端竿滨,即使被別人知道公鑰,也是沒有問題的捏境;私鑰則一定要保存在服務(wù)端于游。如果到時公司面臨人事變動,避免私鑰被離職人員泄露垫言,可以重新生成公鑰和密鑰贰剥。

使用公鑰加密,私鑰解密

這里在客戶端模擬加密的情況筷频,對字符串"Beyond黃家駒"使用RSA加密蚌成,調(diào)用RSAUtils的encryptByPublicKey()方法前痘,輸出結(jié)果為:

密文: BRFjf3tUqRqlwuP5JtzxZinf7lp+AHuHM9JSabM5BNFDxuUe9+uuO6RpCHVH5PibifqQHzGNsyZn1G9QcIENT9Tbm+PZwAbNUlMPZRDBU1FSnOtY8dBdeW/lJdnY9sJVwNvIBnOLQk66hxRh6R2149dwlgdsGUpWMOMBzcP3vsU=

在服務(wù)端,可以使用RSAUtils的decryptByPrivateKey()方法進(jìn)行解密笑陈,現(xiàn)在模擬服務(wù)端解密

在這里雖然沒有完全模擬數(shù)據(jù)傳輸過程际度,比如說客戶端發(fā)起一個網(wǎng)絡(luò)請求,傳遞參數(shù)給服務(wù)端涵妥,服務(wù)端接收參數(shù)并進(jìn)行處理乖菱,也是為了讓大家可以更加容易明白,所以這里只是進(jìn)行簡單的模擬蓬网≈纤可以看到android客戶端端和java服務(wù)端的RSA加密解密算法是可以互通的,原因是他們所使用到的base64加密類是一致的帆锋,所以才可以實現(xiàn)加密和解密的算法互通吵取。

使用到的jar包都是javabase64-1.3.1.jar,相信不少人都知道,java中有自帶的Base64算法類锯厢,但是安卓中卻沒有皮官,之前出現(xiàn)的情況是,使用的Base64類不統(tǒng)一实辑,比如在安卓客戶端開發(fā)使用的Base64算法是使用第三方提供的jar包捺氢,而java服務(wù)端中使用的是JDK自帶的Base64,導(dǎo)致從客戶端傳過來的密文,服務(wù)端解析出錯剪撬。

上面的例子展示了客戶端使用公鑰加密摄乒,服務(wù)端使用私鑰解密的過程。也許你會這么想残黑,既然可以如此馍佑,那服務(wù)端那邊信息也可以通過RSA加密后,傳遞加密信息過來梨水,客戶端進(jìn)行解密拭荤。但是,這樣做冰木,顯示是不安全的穷劈。原因是,由于客戶端并沒有保存私鑰踊沸,只有公鑰,只可以服務(wù)端進(jìn)行私鑰加密社证,客戶端進(jìn)行公鑰解密逼龟,但由于公鑰是公開,別人也可以獲取到公鑰追葡,如果信息被他們截取腺律,他們同樣可以通過公鑰進(jìn)行解密奕短,那么這樣子加密,就毫無意義了匀钧,所以這個時候翎碑,就要結(jié)合對稱算法,實現(xiàn)客戶端與服務(wù)端之前的安全通信了之斯。

使用AES加密解密
加密

模擬客戶端進(jìn)行AES加密日杈,我們通過調(diào)用AESUtils中的generateKey()方法,隨機(jī)產(chǎn)生一個密鑰佑刷,用于對數(shù)據(jù)進(jìn)行加密莉擒。輸出的結(jié)果為:

密鑰: 6446c69c0f914a57
密文: GECDQOsc22yV48hdJENTMg==
解密

模擬服務(wù)端進(jìn)行AES解密,由于AES屬于對稱算法瘫絮,加密和解密需要使用同一把密鑰涨冀,所以,服務(wù)端要解密傳遞過來的內(nèi)容麦萤,就需要密鑰 + 密文鹿鳖。這里模擬一下服務(wù)端解密。

到這里也許你會問壮莹,客戶端使用AES進(jìn)行加密翅帜,服務(wù)端要進(jìn)行解密的話,需要用到產(chǎn)生的密鑰垛孔,那密鑰必須從客戶端傳輸?shù)椒?wù)端藕甩,如果不對密鑰進(jìn)行加密,那加密就沒有意義了周荐。所以這里終于談到了重點狭莱,RSA算法+AES算法結(jié)合使用。

RSA算法+AES算法的使用

舉一個簡單的例子來說明一下吧,例如實名認(rèn)證功能徽职,需要傳遞用戶真實姓名和身份證號妒御,對于這種重要信息,需要進(jìn)行加密處理骤素。

客戶端使用RSA + AES對重要信息進(jìn)行加密

客戶端加密過程主要分為以下三個步驟:

1.客戶端隨機(jī)產(chǎn)生AES的密鑰;

2.對身份證信息(重要信息)進(jìn)行AES加密愚屁;

3.通過使用RSA對AES密鑰進(jìn)行公鑰加密济竹。

這樣在傳輸?shù)倪^程中,即時加密后的AES密鑰被別人截取霎槐,對其也無濟(jì)于事送浊,因為他并不知道RSA的私鑰,無法解密得到原本的AES密鑰丘跌,就無法解密用AES加密后的重要信息袭景。

服務(wù)端使用RSA + AES對重要信息進(jìn)行解密

服務(wù)端解密過程主要分為以下兩個步驟:

1.對加密后的AES密鑰進(jìn)行RSA私鑰解密唁桩,拿到密鑰原文;

2.對加密后的重要信息進(jìn)行AES解密耸棒,拿到原始內(nèi)容荒澡。

現(xiàn)實開發(fā)中,服務(wù)端有時也需要向客戶端傳遞重要信息与殃,比如登錄的時候单山,返回token給客戶端,作為令牌奈籽,這個令牌就需要進(jìn)行加密饥侵,原理也是差不多的,比上面多一個步驟而已衣屏,就是將解密后的AES密鑰躏升,對將要傳遞給客戶端的數(shù)據(jù)token進(jìn)行AES加密,返回給客戶端狼忱,由于客戶端和服務(wù)端都已經(jīng)拿到同一把AES鑰匙膨疏,所以客戶端可以解密服務(wù)端返回的加密后的數(shù)據(jù)。如果客戶端想要將令牌進(jìn)行保存钻弄,則需要使用自己定義的默認(rèn)的AES密鑰進(jìn)行加密后保存佃却,需要使用的時候傳入默認(rèn)密鑰和密文,解密后得到原token窘俺。

上面提及到客戶端加密饲帅,服務(wù)端返回數(shù)據(jù)不加密的情況,上面說到僅僅使用RSA是可以瘤泪,但是還是建議同時使用這兩種算法灶泵,即產(chǎn)生一個AES密鑰,使用RSA對該密鑰進(jìn)行公鑰加密对途,對重要信息進(jìn)行AES加密赦邻,服務(wù)端通過RSA私鑰解密拿到AES密鑰,再對加密后的重要信息進(jìn)行解密实檀。如果僅僅使用RSA惶洲,服務(wù)端只通過RSA解密,這樣會對于性能會有所影響膳犹,原因是RSA的解密耗時約等于AES解密數(shù)據(jù)的100倍恬吕,所以如果每個重要信息都只通過RSA加密和解密,則會影響服務(wù)端系統(tǒng)的性能须床,所以建議兩種算法一起使用币呵。

同時還有相應(yīng)的JS版RSA和AES算法,使用方式也差不多侨颈,在這里簡單演示一下:

下面是一個html頁面的代碼余赢,引入了rsa.js和aes.js

<!DOCTYPE html>
<html>
  <head>
    <title>RSA+AES.html</title>
    
    <meta name="keywords" content="keyword1,keyword2,keyword3">
    <meta name="description" content="this is my page">
    <meta name="content-type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="./js/rsa.js"></script>
    <script type="text/javascript" src="./js/aes.js"></script>
    <script type="text/javascript">
        var key = getKey();//隨機(jī)產(chǎn)生AES密鑰
        var encryptKey = RSA(key);//對AES密鑰進(jìn)行RSA加密
        console.log("encryptKey: " + encryptKey);
        
        //測試AES加密和解密
        var cipherText = AESEnc(key,"123456");
        var plainText = AESDec(key,cipherText);
        console.log("密文: " + cipherText);
        console.log("明文: " + plainText);
    </script>
  </head>
  
  <body>
    This is my HTML page. <br>
  </body>
</html>

打開頁面后,查看控制臺輸出:

同時哈垢,模擬服務(wù)端解密妻柒,運(yùn)行結(jié)果如下:

在這里將我自己封裝的RSAUtils、AESUtils以及使用第三方j(luò)ar包的Base64Utils還有JS版的RSAHE AES分享給大家耘分,希望可以幫助到大家,由于剛注冊博客不久举塔,沒有多少積分,下載一些資料的時候需要積分求泰,所以收取大家1積分央渣,謝謝了。

http://download.csdn.net/detail/chay_chan/9766486

需要注意的是:

1.RSAUtils中配置公鑰和密鑰渴频,可以使用getKeys()方法產(chǎn)生芽丹。如果是客戶端,則無須配置私鑰卜朗,把沒有私鑰的RSAUtils放到客戶端拔第,因為僅需要用到公鑰加密的方法。

2.AESUtils中配置偏移量IV_STRING场钉;

3.rsa.js中最底部配置公鑰蚊俺,須和上面RSAUtils配置的公鑰一致;

4.aes.js中的底部var iv = CryptoJS.enc.Utf8.parse("16-Bytes--String"); //加密向量中逛万,替換里面的字符串泳猬,加密向量須和
是上面的AESUtils中的偏移量一致。

為了完成這篇博客宇植,花費(fèi)了接近半天的時間得封,相當(dāng)于總結(jié)自己在數(shù)據(jù)傳輸這一方面的經(jīng)驗,希望可以幫助到更多的開發(fā)者当纱,一起交流學(xué)習(xí)呛每,互相提升和進(jìn)步。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坡氯,一起剝皮案震驚了整個濱河市晨横,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌箫柳,老刑警劉巖手形,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異悯恍,居然都是意外死亡库糠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瞬欧,“玉大人贷屎,你說我怎么就攤上這事∷一ⅲ” “怎么了唉侄?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長野建。 經(jīng)常有香客問我属划,道長,這世上最難降的妖魔是什么候生? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任同眯,我火速辦了婚禮,結(jié)果婚禮上唯鸭,老公的妹妹穿的比我還像新娘须蜗。我一直安慰自己,他們只是感情好肿孵,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布唠粥。 她就那樣靜靜地躺著,像睡著了一般停做。 火紅的嫁衣襯著肌膚如雪晤愧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天蛉腌,我揣著相機(jī)與錄音官份,去河邊找鬼。 笑死烙丛,一個胖子當(dāng)著我的面吹牛舅巷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播河咽,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼钠右,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了忘蟹?” 一聲冷哼從身側(cè)響起飒房,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎媚值,沒想到半個月后狠毯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡褥芒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年嚼松,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡献酗,死狀恐怖寝受,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情凌摄,我是刑警寧澤羡蛾,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站锨亏,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏忙干。R本人自食惡果不足惜器予,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捐迫。 院中可真熱鬧乾翔,春花似錦、人聲如沸施戴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赞哗。三九已至雷则,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間肪笋,已是汗流浹背月劈。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留藤乙,地道東北人猜揪。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像坛梁,于是被迫代替她去往敵國和親而姐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容