Android客戶端與服務(wù)端數(shù)據(jù)加密傳輸方案詳解
前言
在網(wǎng)絡(luò)通信中,通信傳輸數(shù)據(jù)容易被截取或篡改,如果在傳輸用戶隱私數(shù)據(jù)過程中,被不法分子截取或篡改,就可能導(dǎo)致用戶受到傷害,比如被詐 騙,所以對(duì)客戶端與服務(wù)端的傳輸數(shù)據(jù)加密,是網(wǎng)絡(luò)通信中必不可少的。
數(shù)據(jù)加密方案
首先,客戶端與服務(wù)端商量好數(shù)據(jù)加密協(xié)議,對(duì)傳輸數(shù)據(jù)做到安全保護(hù)。
安全保護(hù)至少需要有下面兩點(diǎn):
- 采用HTTPS協(xié)議
- 采用公鑰密碼體制RSA算法對(duì)數(shù)據(jù)加密
現(xiàn)在安全是保證了,但還要考慮到性能問題,由于RSA算法對(duì)數(shù)據(jù)加密時(shí)運(yùn)算速度慢,所以直接把所有傳輸數(shù)據(jù)都用RSA加密,會(huì)導(dǎo)致網(wǎng)絡(luò)通信慢,這對(duì)用戶將是不好的體驗(yàn)。由于對(duì)稱密鑰密碼體制中的AES運(yùn)算速度快且安全性高,所以結(jié)合AES對(duì)傳輸數(shù)據(jù)加密是非常好的方案。
下面是對(duì)客戶端與服務(wù)端通信數(shù)據(jù)加密比較通用的方案:
- 客戶端生成AES密鑰,并保存AES密鑰
- 客戶端用AES密鑰對(duì)請(qǐng)求傳輸數(shù)據(jù)進(jìn)行加密
- 客戶端使用RSA公鑰對(duì)AES密鑰加密,然后把值放到自定義的一個(gè)請(qǐng)求頭中
- 客戶端向服務(wù)端發(fā)起請(qǐng)求
- 服務(wù)端拿到自定義的請(qǐng)求頭值,然后使用RSA私鑰解密,拿到AES密鑰
- 服務(wù)端使用AES密鑰對(duì)請(qǐng)求數(shù)據(jù)解密
- 服務(wù)端對(duì)響應(yīng)數(shù)據(jù)使用AES密鑰加密
- 服務(wù)端向客戶端發(fā)出響應(yīng)
- 客戶端拿到服務(wù)端加密數(shù)據(jù),并使用之前保存的AES密鑰解密
注意:傳輸數(shù)據(jù)使用AES密鑰加密,RSA公鑰對(duì)AES密鑰加密。RSA公鑰和私鑰由服務(wù)端生成,公鑰放在客戶端,私鑰放在服務(wù)端。公鑰私鑰要私密保護(hù),不能隨便給人。
具體流程圖如下:
上面網(wǎng)絡(luò)通信過程是安全的,可以保證通信數(shù)據(jù)即使被截取了,也無法獲得任何有效信息;即使被篡改了,也無法被客戶端和服務(wù)端驗(yàn)證通過。
數(shù)據(jù)加密細(xì)節(jié)
AES加解密
生成AES密鑰和使用AES密鑰加密、解密,有下面重要的幾點(diǎn):
1.密鑰長(zhǎng)度的選擇:AES能支持的密鑰長(zhǎng)度可以為128,192,256位(也即16,24,32個(gè)字節(jié)),這里選擇128位。
2.算法/模式/填充的選擇:
算法/模式/填充 | 字節(jié)加密后數(shù)據(jù)長(zhǎng)度 | 不滿16字節(jié)加密后長(zhǎng)度 |
---|---|---|
AES/CBC/NoPadding | 16 | 不支持 |
AES/CBC/PKCS5Padding | 32 | 16 |
AES/CBC/ISO10126Paddind | 32 | 16 |
AES/CFB/NoPadding | 16 | 原始數(shù)據(jù)長(zhǎng)度 |
AES/CFB/PKCS5Padding | 32 | 16 |
AES/CFB/ISO10126Padding | 32 | 16 |
AES/ECB/NoPadding | 16 | 不支持 |
AES/ECB/PKCS5Padding | 32 | 16 |
AES/ECB/ISO10126Padding | 32 | 16 |
AES/ECB/ISO10126Padding | 32 | 16 |
AES/OFB/NoPadding | 16 | 原始數(shù)據(jù)長(zhǎng)度 |
AES/OFB/PKCS5Padding | 32 | 16 |
AES/OFB/ISO10126Padding | 32 | 16 |
AES/PCBC/NoPadding | 16 | 不支持 |
AES/PCBC/PKCS5Padding | 32 | 16 |
AES/PCBC/ISO10126Padding | 32 | 16 |
這里選擇AES/CBC/PKCS5Padding。
3.添加向量 IvParameterSpec:增強(qiáng)算法強(qiáng)度。 4.編碼格式選擇:UTF-8。
下面為具體代碼實(shí)現(xiàn):
private final int AES_KEY_LENGTH = 16;//密鑰長(zhǎng)度16字節(jié),128位 private final String AES_ALGORITHM = "AES";//算法名字 private final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding";//算法/模式/填充 private final String AES_IV = "0112030445060709";//使用CBC模式,需要一個(gè)向量iv,可增加加密算法的強(qiáng)度 private final String AES_STRING = "abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLOP"; private final Charset UTF_8 = Charset.forName("UTF-8");//編碼格式 /** * 使用AES加密 * * @param aesKey AES Key * @param data 被加密的數(shù)據(jù) * @return AES加密后的數(shù)據(jù) */ private byte[] encodeAES(byte[] aesKey, String data) { if (aesKey == null || aesKey.length != AES_KEY_LENGTH) { return null; } SecretKeySpec keySpec = new SecretKeySpec(aesKey, AES_ALGORITHM); try { Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION); IvParameterSpec iv = new IvParameterSpec(AES_IV.getBytes(UTF_8)); cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv); return cipher.doFinal(data.getBytes(UTF_8)); } catch (Exception e) { Log.d(TAG, e.getMessage(), e); } return null; } /** * 使用AES解密 * * @param aesKey AES Key * @param data 被解密的數(shù)據(jù) * @return AES解密后的數(shù)據(jù) */ private String decodeAES(byte[] aesKey, byte[] data) { if (aesKey == null || aesKey.length != AES_KEY_LENGTH) { return null; } SecretKeySpec keySpec = new SecretKeySpec(aesKey, AES_ALGORITHM); try { Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION); IvParameterSpec iv = new IvParameterSpec(AES_IV.getBytes(UTF_8)); cipher.init(Cipher.DECRYPT_MODE, keySpec, iv); return new String(cipher.doFinal(data), UTF_8); } catch (Exception e) { Log.d(TAG, e.getMessage(), e); } return null; } private int getRandom(int count) { return (int) Math.round(Math.random() * (count)); } /** * 生成AES key * * @return AES key */ private String initAESKey() { StringBuilder sb = new StringBuilder(); int len = AES_STRING.length(); for (int i = 0; i < AES_KEY_LENGTH; i++) { sb.append(AES_STRING.charAt(getRandom(len - 1))); } return sb.toString(); }
現(xiàn)在AES密鑰和AES加密、解密都有了,在通常情況下,還會(huì)對(duì)加密、解密過程進(jìn)行Base64 編碼、解碼。
Base64編碼,選擇 URL_SAFE 標(biāo)識(shí),也就是 "-" 和 “_” 會(huì)被替換為 "+" 和 "/",:
/** * 對(duì)數(shù)據(jù)進(jìn)行Base64編碼,使用的是{@link android.util.Base64},而且flags需要使用 {@link android.util.Base64#URL_SAFE,android.util#Base64.NO_PADDING,android.util.Base64#NO_WRAP}。 * * @param input 來源數(shù)據(jù) * @return Base64編碼的數(shù)據(jù) */ private String encodeBase64(byte[] input) { return new String(Base64.encode(input, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP), UTF_8); }
Base64解碼,和編碼對(duì)應(yīng):
/** * 對(duì)數(shù)據(jù)進(jìn)行Base64解碼,使用的是{@link android.util.Base64},而且flags需要使用 {@link android.util.Base64#URL_SAFE,android.util.Base64#NO_WRAP},主要是為了和Base64加密對(duì)應(yīng)。 * * @param str 需要解碼的數(shù)據(jù) * @return Base64解碼后的數(shù)據(jù) */ private byte[] decodeBase64(String str) { return Base64.decode(str.getBytes(UTF_8), Base64.URL_SAFE | Base64.DEFAULT); }
RSA公鑰加密
RSA公鑰是從服務(wù)端拿到的,這個(gè)公鑰不能被泄漏,必須做到安全保護(hù)。
使用RSA公鑰加密,也有幾個(gè)重要點(diǎn):
1.拿到的公鑰是Base64 編碼后的,所以首先需要對(duì)公鑰Base64解碼。
2.算法/模式/填充的選擇:RSA/ECB/PKCS1Padding
3.編碼格式選擇:UTF-8。
注意:使用RSA公鑰加密的流程對(duì)應(yīng)的就是服務(wù)端使用RSA私鑰解密的流程,所以需要和服務(wù)端溝通商量好。
具體代碼實(shí)現(xiàn):
private final String RSA_PUB_KEY = "服務(wù)端給的公鑰"; private final String RSA_TRANSFORMATION = "RSA/ECB/PKCS1Padding"; /** * 公鑰加密 * * @param data 要加密的數(shù)據(jù) * @param key 公鑰 * @param transformation 算法/模式/填充 * @return 加密后的數(shù)據(jù) */ public byte[] encryptByPublicKey(byte[] data, String key, String transformation) throws GeneralSecurityException { byte[] keyBytes = Base64.decode(key.getBytes(UTF_8), Base64.NO_WRAP); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey pubKey = keyFactory.generatePublic(keySpec); Cipher cipher = Cipher.getInstance(transformation); cipher.init(Cipher.ENCRYPT_MODE, pubKey); return cipher.doFinal(data); }
總結(jié)
1.為了保證網(wǎng)絡(luò)通信中的通信數(shù)據(jù)安全,首先采用HTTPS協(xié)議和公鑰密鑰體制中的RSA加密。
2.因?yàn)槭荝SA運(yùn)算速度慢,所以采用運(yùn)算速度快且安全性高的對(duì)稱密鑰密碼體制中的AES對(duì)所 有傳輸數(shù)據(jù)進(jìn)行加密,然后再用RSA對(duì)AES密鑰加密,這樣既能保證安全又能保證性能。
3.RSA公鑰和私鑰由服務(wù)端生成,公鑰放在客戶端,私鑰放在服務(wù)端。
4.數(shù)據(jù)加密后采用Base64編碼,數(shù)據(jù)解密前采用Base64解碼。
5.編碼格式同一采用UTF-8。
以上就是Android客戶端與服務(wù)端數(shù)據(jù)加密傳輸方案詳解的詳細(xì)內(nèi)容,更多關(guān)于Android客戶端服務(wù)端數(shù)據(jù)加密傳輸?shù)馁Y料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android調(diào)用系統(tǒng)時(shí)間格式顯示時(shí)間信息
這篇文章主要介紹了Android調(diào)用系統(tǒng)時(shí)間格式顯示時(shí)間信息的使用方法,代碼很簡(jiǎn)單2014-01-01Android 滾動(dòng)時(shí)間選擇的示例代碼
這篇文章主要介紹了Android 滾動(dòng)時(shí)間選擇的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12Android React Native原生模塊與JS模塊通信的方法總結(jié)
這篇文章主要介紹了Android React Native原生模塊與JS模塊通信的方法總結(jié)的相關(guān)資料,需要的朋友可以參考下2017-02-02ExpandableListView實(shí)現(xiàn)二級(jí)列表購物車
這篇文章主要為大家詳細(xì)介紹了ExpandableListView實(shí)現(xiàn)二級(jí)列表購物車,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11Android幀率監(jiān)測(cè)與優(yōu)化技巧
Android 應(yīng)用的性能優(yōu)化是開發(fā)過程中至關(guān)重要的一環(huán),而幀率(Frame Rate)是評(píng)估應(yīng)用性能的一個(gè)關(guān)鍵指標(biāo),在本文中,我們將深入探討如何監(jiān)測(cè) Android 應(yīng)用的幀率,以及如何通過代碼示例來優(yōu)化應(yīng)用的性能,需要的朋友可以參考下2023-10-10Android編程實(shí)現(xiàn)應(yīng)用強(qiáng)制安裝到手機(jī)內(nèi)存的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)應(yīng)用強(qiáng)制安裝到手機(jī)內(nèi)存的方法,涉及Android中屬性設(shè)置的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11Android MPAndroidChart開源庫圖表之折線圖的實(shí)例代碼
這篇文章主要介紹了Android MPAndroidChart開源庫圖表之折線圖的實(shí)例代碼,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05Android?MaterialAlertDialogBuilder修改按鈕屬性
這篇文章主要介紹了Android?MaterialAlertDialogBuilder修改按鈕屬性實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11Android 側(cè)滑抽屜菜單的實(shí)現(xiàn)代碼
這篇文章主要介紹了Android 側(cè)滑抽屜菜單的實(shí)現(xiàn)代碼,本文通過實(shí)例圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03