客戶端與服務端數(shù)據(jù)加密傳輸方案

前言

從前一篇網(wǎng)絡安全基礎要點知識介紹中可以知道刽射,在網(wǎng)絡通信中,通信傳輸數(shù)據(jù)容易被截取或篡改幸乒,如果在傳輸用戶隱私數(shù)據(jù)過程中,被不法分子截取或篡改唇牧,就可能導致用戶受到傷害罕扎,比如被詐騙,所以對客戶端與服務端的傳輸數(shù)據(jù)加密丐重,是網(wǎng)絡通信中必不可少的腔召。

數(shù)據(jù)加密方案

首先,客戶端與服務端商量好數(shù)據(jù)加密協(xié)議扮惦,對傳輸數(shù)據(jù)做到安全保護臀蛛。

安全保護至少需要有下面兩點:

采用HTTPS協(xié)議

采用公鑰密碼體制RSA算法對數(shù)據(jù)加密

現(xiàn)在安全是保證了,但還要考慮到性能問題崖蜜,由于RSA算法對數(shù)據(jù)加密時運算速度慢浊仆,所以直接把所有傳輸數(shù)據(jù)都用RSA加密,會導致網(wǎng)絡通信慢豫领,這對用戶將是不好的體驗抡柿。由于對稱密鑰密碼體制中的AES運算速度快且安全性高,所以結合AES對傳輸數(shù)據(jù)加密是非常好的方案等恐。

下面是對客戶端與服務端通信數(shù)據(jù)加密比較通用的方案:

客戶端生成AES密鑰洲劣,并保存AES密鑰

客戶端用AES密鑰對請求傳輸數(shù)據(jù)進行加密

客戶端使用RSA公鑰對AES密鑰加密,然后把值放到自定義的一個請求頭中

客戶端向服務端發(fā)起請求

服務端拿到自定義的請求頭值课蔬,然后使用RSA私鑰解密囱稽,拿到AES密鑰

服務端使用AES密鑰對請求數(shù)據(jù)解密

服務端對響應數(shù)據(jù)使用AES密鑰加密

服務端向客戶端發(fā)出響應

客戶端拿到服務端加密數(shù)據(jù),并使用之前保存的AES密鑰解密

注意:傳輸數(shù)據(jù)使用AES密鑰加密二跋,RSA公鑰對AES密鑰加密粗悯。RSA公鑰和私鑰由服務端生成,公鑰放在客戶端同欠,私鑰放在服務端。公鑰私鑰要私密保護横缔,不能隨便給人铺遂。

具體流程圖如下:

上面網(wǎng)絡通信過程是安全的,可以保證通信數(shù)據(jù)即使被截取了茎刚,也無法獲得任何有效信息襟锐;即使被篡改了,也無法被客戶端和服務端驗證通過膛锭。

數(shù)據(jù)加密細節(jié)

AES加解密

生成AES密鑰和使用AES密鑰加密粮坞、解密蚊荣,有下面重要的幾點:

1.密鑰長度的選擇:AES能支持的密鑰長度可以為128,192,256位(也即16,24,32個字節(jié)),這里選擇128位莫杈。

2.算法/模式/填充的選擇:

算法/模式/填充 字節(jié)加密后數(shù)據(jù)長度 不滿16字節(jié)加密后長度

AES/CBC/NoPadding 16 不支持

AES/CBC/PKCS5Padding 32 16

AES/CBC/ISO10126Paddind 32 16

AES/CFB/NoPadding 16 原始數(shù)據(jù)長度

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ù)長度

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:增強算法強度。

4.編碼格式選擇:UTF-8筝闹。

下面為具體代碼實現(xiàn):

? ? private final int AES_KEY_LENGTH = 16;//密鑰長度16字節(jié)媳叨,128位

? ? private final String AES_ALGORITHM = "AES";//算法名字

? ? private final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding";//算法/模式/填充

? ? private final String AES_IV = "0112030445060709";//使用CBC模式,需要一個向量iv关顷,可增加加密算法的強度

? ? 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();

? ? }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

現(xiàn)在AES密鑰和AES加密糊秆、解密都有了,在通常情況下议双,還會對加密痘番、解密過程進行Base64 編碼、解碼平痰。

Base64編碼汞舱,選擇 URL_SAFE 標識,也就是 “-” 和 “_” 會被替換為 “+” 和 “/”觉增,:

? ? /**

? ? * 對數(shù)據(jù)進行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);

? ? }

1

2

3

4

5

6

7

8

9

10

Base64解碼说铃,和編碼對應:

? ? /**

? ? * 對數(shù)據(jù)進行Base64解碼,使用的是{@link android.util.Base64}嘹履,而且flags需要使用 {@link android.util.Base64#URL_SAFE,android.util.Base64#NO_WRAP}腻扇,主要是為了和Base64加密對應。

? ? *

? ? * @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);

? ? }

1

2

3

4

5

6

7

8

9

RSA公鑰加密

RSA公鑰是從服務端拿到的砾嫉,這個公鑰不能被泄漏幼苛,必須做到安全保護。

使用RSA公鑰加密焕刮,也有幾個重要點:

1.拿到的公鑰是Base64 編碼后的舶沿,所以首先需要對公鑰Base64解碼。

2.算法/模式/填充的選擇:RSA/ECB/PKCS1Padding

3.編碼格式選擇:UTF-8配并。

注意:使用RSA公鑰加密的流程對應的就是服務端使用RSA私鑰解密的流程括荡,所以需要和服務端溝通商量好。

具體代碼實現(xiàn):

? ? private final String RSA_PUB_KEY = "服務端給的公鑰";

? ? 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);

? ? }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

總結

1.為了保證網(wǎng)絡通信中的通信數(shù)據(jù)安全溉旋,首先采用HTTPS協(xié)議和公鑰密鑰體制中的RSA加密畸冲。

2.因為是RSA運算速度慢,所以采用運算速度快且安全性高的對稱密鑰密碼體制中的AES對所

有傳輸數(shù)據(jù)進行加密,然后再用RSA對AES密鑰加密邑闲,這樣既能保證安全又能保證性能算行。

3.RSA公鑰和私鑰由服務端生成,公鑰放在客戶端苫耸,私鑰放在服務端州邢。

4.數(shù)據(jù)加密后采用Base64編碼,數(shù)據(jù)解密前采用Base64解碼鲸阔。

5.編碼格式同一采用UTF-8

————————————————

版權聲明:本文為CSDN博主「麥田里的守望者-Jiang」的原創(chuàng)文章偷霉,遵循 CC 4.0 BY-SA 版權協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明褐筛。

原文鏈接:https://blog.csdn.net/wangjiang_qianmo/article/details/88073848

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末类少,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子渔扎,更是在濱河造成了極大的恐慌硫狞,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晃痴,死亡現(xiàn)場離奇詭異残吩,居然都是意外死亡,警方通過查閱死者的電腦和手機倘核,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門泣侮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人紧唱,你說我怎么就攤上這事活尊。” “怎么了漏益?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵蛹锰,是天一觀的道長。 經(jīng)常有香客問我绰疤,道長铜犬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任轻庆,我火速辦了婚禮癣猾,結果婚禮上,老公的妹妹穿的比我還像新娘余爆。我一直安慰自己煎谍,他們只是感情好,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布龙屉。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪转捕。 梳的紋絲不亂的頭發(fā)上作岖,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天,我揣著相機與錄音五芝,去河邊找鬼痘儡。 笑死,一個胖子當著我的面吹牛枢步,可吹牛的內(nèi)容都是我干的沉删。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼醉途,長吁一口氣:“原來是場噩夢啊……” “哼矾瑰!你這毒婦竟也來了?” 一聲冷哼從身側響起隘擎,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤殴穴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后货葬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體采幌,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年震桶,在試婚紗的時候發(fā)現(xiàn)自己被綠了休傍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蹲姐,死狀恐怖磨取,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情淤堵,我是刑警寧澤寝衫,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站拐邪,受9級特大地震影響慰毅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜扎阶,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一汹胃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧东臀,春花似錦着饥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呵哨。三九已至,卻和暖如春轨奄,著一層夾襖步出監(jiān)牢的瞬間孟害,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工挪拟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留挨务,地道東北人。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓玉组,卻偏偏與公主長得像谎柄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子惯雳,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

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

  • 1. ASCII 編碼 ASCII(American Standard Code for Information ...
    s酸菜閱讀 8,686評論 0 8
  • 概述 之前一直對加密相關的算法知之甚少朝巫,只知道類似DES、RSA等加密算法能對數(shù)據(jù)傳輸進行加密吨凑,且各種加密算法各有...
    Henryzhu閱讀 3,019評論 0 14
  • 上周在項目中需要對URL參數(shù)進行加密傳輸捍歪,實際過程中碰到了一些問題,在此對加密算法的Java實現(xiàn)及出現(xiàn)的編碼問題進...
    茶樹丶ccha閱讀 2,254評論 0 2
  • Base64.java public final class Base64 { static private ...
    BUG弄潮兒閱讀 795評論 0 0
  • 最近公司用到RSA數(shù)據(jù)加密傳輸鸵钝,本人也只會使用糙臼,并不知其原理,剛好今天在csdn看到一位大牛的博客寫得很到位恩商,遂搬...
    爸比好酷閱讀 1,418評論 0 1