對(duì)稱加密

介紹

加密和解密都使用同一把秘鑰掺出,這種加密方法稱為對(duì)稱加密载慈,也稱為單密鑰加密惭等。
簡單理解為:加密解密都是同一把鑰匙

Paste_Image.png

上一篇文章凱撒密碼就屬于對(duì)稱加密,他的字符偏移量即為秘鑰办铡。

對(duì)稱加密常用算法

AES辞做、DES珠十、3DES、TDEA凭豪、Blowfish焙蹭、RC2、RC4嫂伞、RC5孔厉、IDEA、SKIPJACK 等帖努。
DES:全稱為Data Encryption Standard撰豺,即數(shù)據(jù)加密標(biāo)準(zhǔn),是一種使用密鑰加密的塊算法拼余,1976 年被美國聯(lián)邦政府的國家標(biāo)準(zhǔn)局確定為聯(lián)邦資料處理標(biāo)準(zhǔn)(FIPS)污桦,隨后在國際上廣泛流傳開來。
3DES:也叫Triple DES匙监,是三重?cái)?shù)據(jù)加密算法(TDEA凡橱,Triple Data Encryption Algorithm)塊密碼的通稱。它相當(dāng)于是對(duì)每個(gè)數(shù)據(jù)塊應(yīng)用三次DES 加密算法亭姥。由于計(jì)算機(jī)運(yùn)算能力的增強(qiáng)稼钩,原版DES 密碼的密鑰長度變得容易被暴力破解;3DES 即是設(shè)計(jì)用來提供一種相對(duì)簡單的方法达罗,即通過增加DES 的密鑰長度來避免類似的攻擊坝撑,而不是設(shè)計(jì)一種全新的塊密碼算法。
AES: 高級(jí)加密標(biāo)準(zhǔn)(英語:Advanced Encryption Standard粮揉,縮寫:AES)巡李,在密碼學(xué)中又稱Rijndael 加密法,是美國聯(lián)邦政府采用的一種區(qū)塊加密標(biāo)準(zhǔn)扶认。這個(gè)標(biāo)準(zhǔn)用來替代原先的DES侨拦,已經(jīng)被多方分析且廣為全世界所使用。經(jīng)過五年的甄選流程蝠引,高級(jí)加密標(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 年螃概,高級(jí)加密標(biāo)準(zhǔn)已然成為對(duì)稱密鑰加密中最流行的算法之一矫夯。

DES 算法簡介

Bit 是計(jì)算機(jī)最小的傳輸單位。以0 或1 來表示比特位的值
例如數(shù)字3 對(duì)應(yīng)的二進(jìn)制數(shù)據(jù)為:00000011
代碼示例:

1. int i = 97;
2. String bit = Integer.toBinaryString(i);
3. //輸出:97 對(duì)應(yīng)的二進(jìn)制數(shù)據(jù)為: 1100001
4. System.out.println(i + "對(duì)應(yīng)的二進(jìn)制數(shù)據(jù)為: " + bit);

Byte 與Bit 區(qū)別

數(shù)據(jù)存儲(chǔ)是以“字節(jié)”(Byte)為單位吊洼,數(shù)據(jù)傳輸是以大多是以“位”(bit训貌,又名“比特”)為單位,一個(gè)位就代表一個(gè)0 或1(即二進(jìn)制),每8 個(gè)位(bit递沪,簡寫為b)組成一個(gè)字節(jié)(Byte豺鼻,簡寫為B),是最小一級(jí)的信息單位款慨。
Byte 的取值范圍:

1. //byte 的取值范圍:-128 到127
2. System.out.println(Byte.MIN_VALUE + "到" + Byte.MAX_VALUE);```
即10000000 到01111111 之間儒飒,一個(gè)字節(jié)占8 個(gè)比特位
二進(jìn)制轉(zhuǎn)十進(jìn)制圖示:

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/2540237-fbbc99044c9fad5e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
任何字符串都可以轉(zhuǎn)換為字節(jié)數(shù)組
  1. String data = "1234abcd";
  2. byte[] bytes = data.getBytes();//內(nèi)容為:49 50 51 52 97 98 99 100
上面數(shù)據(jù)49 50 51 52 97 98 99 100 對(duì)應(yīng)的二進(jìn)制數(shù)據(jù)(即比特位為):
00110001
00110010
00110011
00110100
01100001
01100010
01100011
01100100
將他們間距調(diào)大一點(diǎn),可看做一個(gè)矩陣:
0 0 1 1 0 0 0 1
0 0 1 1 0 0 1 0
0 0 1 1 0 0 1 1
0 0 1 1 0 1 0 0
0 1 1 0 0 0 0 1
0 1 1 0 0 0 1 0
0 1 1 0 0 0 1 1
0 1 1 0 0 1 0 0
之后可對(duì)他們進(jìn)行各種操作檩奠,例如交換位置桩了、分割、異或運(yùn)算等埠戳,常見的加密方式就是這樣操作比特位的井誉,
例如下圖的IP 置換以及S-Box 操作都是常見加密的一些方式:
IP 置換:

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/2540237-3c2d34edcd89a019.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
S-BOX 置換:

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/2540237-2be91a04eb9fa9ab.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
DES 加密過程圖解(流程很復(fù)雜,只需要知道內(nèi)部是操作比特位即可):

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/2540237-217d7a0520d495ae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##對(duì)稱加密應(yīng)用場景
1. 本地?cái)?shù)據(jù)加密(例如加密android 里SharedPreferences 里面的某些敏感數(shù)據(jù))
2. 網(wǎng)絡(luò)傳輸:登錄接口post 請(qǐng)求參數(shù)加密{username=lisi,pwd=oJYa4i9VASRoxVLh75wPCg==}
3. 加密用戶登錄結(jié)果信息并序列化到本地磁盤(將user 對(duì)象序列化到本地磁盤整胃,下次登錄時(shí)反序列化到
內(nèi)存里)
4. 網(wǎng)頁交互數(shù)據(jù)加密(即Https)

##DES 算法代碼實(shí)現(xiàn)
  1. //1,得到cipher 對(duì)象(可翻譯為密碼器或密碼系統(tǒng))
  2. Cipher cipher = Cipher.getInstance("DES");
  3. //2颗圣,創(chuàng)建秘鑰
  4. SecretKey key = KeyGenerator.getInstance("DES").generateKey();
  5. //3,設(shè)置操作模式(加密/解密)
  6. cipher.init(Cipher.ENCRYPT_MODE, key);
  7. //4屁使,執(zhí)行操作
  8. byte[] result = cipher.doFinal("哈哈".getBytes());
##AES 算法代碼實(shí)現(xiàn)
用法同上在岂,只需把”DES”參數(shù)換成”AES”即可。
##使用Base64 編碼加密后的結(jié)果
  1. byte[] result = cipher.doFinal("哈哈".getBytes());
  2. System.out.println(new String(result));
輸出:

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/2540237-a798bd00874c0f85.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

加密后的結(jié)果是字節(jié)數(shù)組屋灌,這些被加密后的字節(jié)在碼表(例如UTF-8 碼表)上找不到對(duì)應(yīng)字符洁段,會(huì)出現(xiàn)亂碼,當(dāng)亂碼字符串再次轉(zhuǎn)換為字節(jié)數(shù)組時(shí)共郭,長度會(huì)變化,導(dǎo)致解密失敗疾呻,所以轉(zhuǎn)換后的數(shù)據(jù)是不安全的除嘹。
使用Base64 對(duì)字節(jié)數(shù)組進(jìn)行編碼,任何字節(jié)都能映射成對(duì)應(yīng)的Base64 字符岸蜗,之后能恢復(fù)到字節(jié)數(shù)組尉咕,利于加密后數(shù)據(jù)的保存于傳輸,所以轉(zhuǎn)換是安全的璃岳。同樣年缎,字節(jié)數(shù)組轉(zhuǎn)換成16 進(jìn)制字符串也是安全的。

密文轉(zhuǎn)換成Base64 編碼后的輸出結(jié)果:

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/2540237-5191ff823152071c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

密文轉(zhuǎn)換成16 進(jìn)制編碼后的輸出結(jié)果:

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/2540237-3baa9ac41546c1f7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
Java 里沒有直接提供Base64 以及字節(jié)數(shù)組轉(zhuǎn)16 進(jìn)制的Api铃慷,開發(fā)中一般是自己手寫或直接使用第三方提供的成熟穩(wěn)定的工具類(例如apache 的commons-codec)单芜。
####Base64 字符映射表

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/2540237-cbafacc08d2ab8ec.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##對(duì)稱加密的具體應(yīng)用方式
1,生成秘鑰并保存到硬盤上犁柜,以后讀取該秘鑰進(jìn)行加密解密操作洲鸠,實(shí)際開發(fā)中用得比較少。
> 1. //生成隨機(jī)秘鑰
2. SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
3. //序列化秘鑰到磁盤上
4. FileOutputStream fos = new FileOutputStream(new File("haha.key"));
5. ObjectOutputStream oos = new ObjectOutputStream(fos);
6. oos.writeObject(secretKey); 
8. //從磁盤里讀取秘鑰
9. FileInputStream fis = new FileInputStream(new File("haha.key"));
10. ObjectInputStream ois = new ObjectInputStream(fis);
11. Key key = (Key) ois.readObject();

2,使用自定義秘鑰(秘鑰寫在代碼里)
> 1. //創(chuàng)建密鑰寫法1
2. KeySpec keySpec = new DESKeySpec(key.getBytes());
3. SecretKey secretKey = SecretKeyFactory.getInstance(ALGORITHM).
4. generateSecret(keySpec);
6. //創(chuàng)建密鑰寫法2
7. //SecretKey secretKey = new SecretKeySpec(key.getBytes(), KEY_ALGORITHM);
9. Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
10. cipher.init(Cipher.DECRYPT_MODE, secretKey);
11. //得到key 后扒腕,后續(xù)代碼就是Cipher 的寫法绢淀,此處省略...

把秘鑰寫在代碼里有一定風(fēng)險(xiǎn),當(dāng)別人反編譯代碼的時(shí)候瘾腰,可能會(huì)看到秘鑰皆的,android 開發(fā)里建議用`JNI `把秘鑰值寫到`C `代碼里,甚至拆分成幾份蹋盆,最后再組合成真正的秘鑰
##算法/工作模式/填充模式
初始化cipher 對(duì)象時(shí)祭务,參數(shù)可以直接傳算法名:例如:
Cipher c = Cipher.getInstance("DES");
也可以指定更詳細(xì)的參數(shù),格式:"algorithm/mode/padding" 怪嫌,即"算法/工作模式/填充模式"
Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
###密碼塊工作模式
塊密碼工作模式(Block cipher mode of operation)义锥,是對(duì)于按塊處理密碼的加密方式的一種擴(kuò)充,
不僅僅適用于AES岩灭,包括DES, RSA 等加密方法同樣適用拌倍。

|名稱|英文|全名|方法|優(yōu)點(diǎn)|缺點(diǎn)
|---|---|---|---|---|---
|ECB| Electroniccodebook|電子密碼本|每塊獨(dú)立加密|1.分塊可以并行處理|1.同樣的原文得到相同的密文,容易被攻擊
|CBC| Cipher-blockchaining|密碼分組鏈接|每塊加密依賴于前一塊的密文|1.同樣的原文得到不同的密文<br>2.原文微小改動(dòng)影響后面全部密文|1.加密需要串行處理 <br>2.誤差傳遞
|PCBC |Propagatingcipher-blockchaining|填充密碼塊鏈接|CBC 的擴(kuò)種噪径,較少使用|1.同樣的原文得到不同的密文<br>2.互換兩個(gè)鄰接的密文塊不會(huì)對(duì)后續(xù)塊的解密造成影響|1.加密需要串行處理
|CFB| Cipherfeedback|密文反饋||||
|OFB| Outputfeedback|輸出反饋模式|加密后密文與原文異或XOR||1.能夠?qū)γ芪倪M(jìn)行校驗(yàn)
|CTR |Counter mode |計(jì)數(shù)器模式|增加一個(gè)序列函數(shù)對(duì)所有密文快做XOR||||

填充
填充(Padding)柱恤,是對(duì)需要按塊處理的數(shù)據(jù),當(dāng)數(shù)據(jù)長度不符合塊處理需求時(shí)找爱,按照一定方法填充滿塊長的一種規(guī)則梗顺。

|名稱|方法|示例
|---|---|---
|Zero padding |最常見的方式,全填充0x00 |AA AA AA AA 00 00 00 00
|ANSI X.923| Zero 的改進(jìn)车摄,最后一個(gè)字節(jié)為填充字節(jié)個(gè)數(shù)|AA AA AA AA 00 00 00 04
|ISO 10126| 隨機(jī)填充|AA AA AA AA 81 A6 23 04
|PKCS7| ANSI X.923 的變體填充1 個(gè)字符就全0x01填充2 個(gè)字符就全0x02不需要填充就增加一個(gè)塊寺谤,填充塊長度,塊長為8 就填充0x08吮播,塊長為16 就填充0x10|AA AA AA AA AA AA AA01<br>AA AA AA AA 04 04 04 04<br>AA AA AA AA AA AA AA<br>AA 08 08 08 08 08 08 08 08
|ISO/IEC 7816-4 |以0x80 開始作為填充開始標(biāo)記变屁,后續(xù)全填充0x00|AA AA AA AA AA AA AA 80AA AA AA AA 80 00 00 00

具體代碼:
> 1 //秘鑰算法
2 private static final String KEY_ALGORITHM = "DES";
3 //加密算法:algorithm/mode/padding 算法/工作模式/填充模式
4 private static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";
5 //秘鑰
6 private static final String KEY = "12345678";//DES 秘鑰長度必須是8 位或以上
7 //private static final String KEY = "1234567890123456";//AES 秘鑰長度必須是16 位
9 //初始化秘鑰
10 SecretKey secretKey = new SecretKeySpec(KEY.getBytes(), KEY_ALGORITHM);
11 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
12 //加密
13 cipher.init(Cipher.ENCRYPT_MODE, secretKey);
14 byte[] result = cipher.doFinal(input.getBytes());

注意:AES、DES 在CBC 操作模式下需要`iv` 參數(shù)
> 15 //AES意狠、DES 在CBC 操作模式下需要iv 參數(shù)
16 IvParameterSpec iv = new IvParameterSpec(key.getBytes());
18 //加密
19 cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);

##總結(jié)
DES 安全度在現(xiàn)代已經(jīng)不夠高粟关,后來又出現(xiàn)的3DES 算法強(qiáng)度提高了很多,但是其執(zhí)行效率低下环戈,AES算法加密強(qiáng)度大闷板,執(zhí)行效率高,使用簡單院塞,**實(shí)際開發(fā)中建議選擇AES 算法**遮晚。
實(shí)際android 開發(fā)中可以用對(duì)稱加密(例如選擇AES 算法)來解決很多問題,例如:
1迫悠,做一個(gè)管理密碼的app鹏漆,我們?cè)诓煌木W(wǎng)站里使用不同賬號(hào)密碼,很難記住,想做個(gè)app 統(tǒng)一管理艺玲,但是賬號(hào)密碼保存在手機(jī)里括蝠,一旦丟失了容易造成安全隱患,所以需要一種加密算法饭聚,將賬號(hào)密碼信息加密起來保管忌警,這時(shí)候如果使用對(duì)稱加密算法,將數(shù)據(jù)進(jìn)行加密秒梳,秘鑰我們自己記載心里法绵,只需要記住一個(gè)密碼。需要的時(shí)候可以還原信息酪碘。
2朋譬,android 里需要把一些敏感數(shù)據(jù)保存到SharedPrefrence 里的時(shí)候,也可以使用對(duì)稱加密兴垦,這樣可以在需要的時(shí)候還原徙赢。
3,請(qǐng)求網(wǎng)絡(luò)接口的時(shí)候探越,我們需要上傳一些敏感數(shù)據(jù)狡赐,同樣也可以使用對(duì)稱加密,服務(wù)端使用同樣的算法就可以解密钦幔≌硖耄或者服務(wù)端需要給客戶端傳遞數(shù)據(jù),同樣也可以先加密鲤氢,然后客戶端使用同樣算法解密搀擂。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市铜异,隨后出現(xiàn)的幾起案子哥倔,更是在濱河造成了極大的恐慌,老刑警劉巖揍庄,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異东抹,居然都是意外死亡蚂子,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門缭黔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來食茎,“玉大人,你說我怎么就攤上這事馏谨”鹩妫” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長哎媚。 經(jīng)常有香客問我喇伯,道長,這世上最難降的妖魔是什么拨与? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任稻据,我火速辦了婚禮,結(jié)果婚禮上买喧,老公的妹妹穿的比我還像新娘捻悯。我一直安慰自己,他們只是感情好淤毛,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布今缚。 她就那樣靜靜地躺著,像睡著了一般低淡。 火紅的嫁衣襯著肌膚如雪姓言。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天查牌,我揣著相機(jī)與錄音事期,去河邊找鬼。 笑死纸颜,一個(gè)胖子當(dāng)著我的面吹牛兽泣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胁孙,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼唠倦,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了涮较?” 一聲冷哼從身側(cè)響起稠鼻,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎狂票,沒想到半個(gè)月后候齿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡闺属,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年慌盯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掂器。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡亚皂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出国瓮,到底是詐尸還是另有隱情灭必,我是刑警寧澤狞谱,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站禁漓,受9級(jí)特大地震影響跟衅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜璃饱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一与斤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧荚恶,春花似錦撩穿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至廓潜,卻和暖如春抵皱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辩蛋。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國打工呻畸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人悼院。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓伤为,卻偏偏與公主長得像,于是被迫代替她去往敵國和親据途。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绞愚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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