作者簡介? 原創(chuàng)微信公眾號郭霖 WeChat ID: guolin_blog
大家早上好,轉(zhuǎn)眼假期就結(jié)束了,又到了跟你們見面的時候啦沥阳!
本篇是Chay_Chan第二篇 投稿嗅绸,分享了如何在Android、Java以及Web端使用 RSA 與 AES 加密,希望對大家有所幫助。
Chay_Chan的博客地址:
http://blog.csdn.net/Chay_Chan
正文
數(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)生屡久,都最后我會將兩個算法的工具類贈送給大家忆首。
公鑰:
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:
打開頁面后,查看控制臺輸出:
同時斋攀,模擬服務(wù)端解密已卷,運行結(jié)果如下:
需要注意的是:
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中的偏移量一致泡仗。
在這里將我自己封裝的RSAUtils、AESUtils以及使用第三方j(luò)ar包的Base64Utils還有JS版的RSAHE AES分享給大家猜憎,希望可以幫助到大家娩怎。
http://download.csdn.net/detail/chay_chan/9766486
為了完成這篇博客,花費了接近半天的時間胰柑,相當(dāng)于總結(jié)自己在數(shù)據(jù)傳輸這一方面的經(jīng)驗截亦,希望可以幫助到更多的開發(fā)者,一起交流學(xué)習(xí)柬讨,互相提升和進(jìn)步崩瓤。
文章原創(chuàng)作者GuoLin 書籍推薦
郭林大神原創(chuàng)android 書籍:《第一行代碼 android》