密碼學(xué)系列 - 對稱加密
本文討論的對稱加密算法主要包括 DES、3DES、AES
DES
明文:64 bit 密文:64 bit 密鑰:56/64 bit(每 7 位插入一個(gè)校驗(yàn)位的時(shí)候?yàn)?64 bit) 其設(shè)計(jì)思想充分體現(xiàn)了香農(nóng)提出的混淆和擴(kuò)散原則

DES 使用的是 Feistel 結(jié)構(gòu)來加密的,一共需要 16 輪,加密過程如下:
- 將明文進(jìn)行初始置換(通過置換表)
- 將置換后的數(shù)據(jù)分為左右 L1 R1 各 32 bit
- 將 48 bit 的子密鑰與 R1 作為輪函數(shù)F的輸入
- 將 L1 與輪函數(shù)的輸出異或運(yùn)算,得到 L1密文
- 將 L1 密文與 R1 交換位置,分別作為下一輪的 R2,L2
- 將 2-5 再重復(fù) 15 次
- 將 L17 R17 交換位置,并拼接為 64bit 數(shù)據(jù)
- 將 64bit 數(shù)據(jù)進(jìn)行逆初始置換,得到最終密文
需要注意的是:
- 子密鑰在每一輪中都是不一樣的
- 每一輪之間會(huì)將左側(cè)和右側(cè)對調(diào)(右側(cè)沒有加密)
- 解密的過程就是將輸出用相同的子密鑰再走一遍,如果加密的子密鑰順序是key1 key2 key3,則解密的子密鑰為key3 key2 key1
- 輪函數(shù)可以設(shè)計(jì)為不可逆函數(shù)如hash,對解密沒有影響

golang 代碼實(shí)戰(zhàn):
func TestDesEncrypt(t *testing.T) {
key:=[]byte{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}
cipherBlock,err:=des.NewCipher(key)
if err!=nil{
t.Error(err)
}
src:=[]byte{0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}
encrptDst :=make([]byte,len(src))
cipherBlock.Encrypt(encrptDst,src)
t.Log(encrptDst)
plainDst:=make([]byte,len(encrptDst))
cipherBlock.Decrypt(plainDst, encrptDst)
t.Log(plainDst)
}
//out: [206 173 55 61 184 14 171 248]
//out: [1 2 3 4 5 6 7 8]
三重DES
明文:64 bit 密文:64 bit 密鑰:56/64 * 3 bit(加入校驗(yàn)位的時(shí)候?yàn)?4 bit)
為了增加 DES 的強(qiáng)度,明文經(jīng)過 3 次 DES 處理后變成最后的密文,因此密鑰長度為 56/64 * 3 bit。3 次 DES 處理并不是簡單的 3 次加密的過程,而是加密、解密、加密,解密的過程相應(yīng)的就是解密、解密、解密。這樣設(shè)計(jì)是因?yàn)樵?3 個(gè)密鑰相同時(shí),可以兼容 DES 算法

golang 代碼實(shí)戰(zhàn):
func TestTripleDesEncrypt(t *testing.T) {
key:=[]byte{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}
cipherBlock,err:=des.NewTripleDESCipher(key)
if err!=nil{
t.Error(err)
}
src:=[]byte{0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}
encrptDst :=make([]byte,len(src))
cipherBlock.Encrypt(encrptDst,src)
t.Log(encrptDst)
plainDst:=make([]byte,len(encrptDst))
cipherBlock.Decrypt(plainDst, encrptDst)
t.Log(plainDst)
}
//此處3個(gè)密鑰相同,兼容DES
//out: [206 173 55 61 184 14 171 248]
//out: [1 2 3 4 5 6 7 8]
AES
明文:128 bit 密文:128 bit 密鑰:128/192/256 bit (分別需要10/12/14輪)
AES 標(biāo)準(zhǔn)最后評選出的算法是 Rijindale 算法,該算法支持密鑰 128/192/256 bit ,分別需要 10/12/14 輪,本文討論的是 128 bit密鑰。它的加密過程并沒有使用 DES 的 feistel 結(jié)構(gòu),而是使用了一種新的 SPN 結(jié)構(gòu),需要 10-14 輪計(jì)算,如下圖:

其中每一輪計(jì)算過程如下:
- SubBytes(字節(jié)替換):以字節(jié)大小為索引,與s_box表中字節(jié)映射
- ShiftRows(行移位-擴(kuò)散):從上到下從左到右的順序組成 4 * 4 數(shù)組,從 0 行開始,第 n 行向左平移 n 個(gè)字節(jié)
- MixColums(列混肴-擴(kuò)散):對每一列進(jìn)行矩陣運(yùn)算,共四列
- AddRoundKey(輪密鑰加):與輪密鑰即子密鑰異或運(yùn)算
需要注意的是:
- 最后一輪沒有列混淆
- 加密時(shí):SubBytes -> ShiftRows -> MixColums -> AddRoundKey 解密時(shí):AddRoundkey -> InvMixColums -> InvShiftRows -> InvSubBytes (Inv代表逆運(yùn)算)
golang 代碼實(shí)戰(zhàn):
func TestAesEncrypt(t *testing.T){
key:=[]byte{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}
cipherBlock,err:=aes.NewCipher(key)
if err!=nil{
t.Error(err)
}
src:=[]byte{0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}
encrptDst :=make([]byte,len(src))
cipherBlock.Encrypt(encrptDst,src)
t.Log(encrptDst)
plainDst:=make([]byte,len(encrptDst))
cipherBlock.Decrypt(plainDst, encrptDst)
t.Log(plainDst)
}
//out [19 7 34 196 163 153 225 186 223 245 40 131 80 80 70 203]
//out [1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8]
迭代模式
以上討論的三種加密算法都是分組密碼,每次只能處理特定長度的一塊數(shù)據(jù),例如 DES 和 3DES 能處理的這塊數(shù)據(jù)長度為 8 bytes,AES 的為 16 bytes。而我們的日常需要加密的明文基本上都是大于這個(gè)長度,這就需要我們將明文的內(nèi)容進(jìn)行分組并迭代加密,這個(gè)迭代加密的方式就是模式。
ECB 模式
電子密碼本模式(electronic codebook ),最簡單的模式,將明文分組直接作為加密算法的輸入,加密算法的輸出直接作為密文分組。
CBC 模式
密文分組鏈接模式(Cipher Block Chaining),密文之間是鏈狀的,明文分組跟上個(gè)密文分組異或之后作為加密算法的輸入,加密算法的輸出作為密文分組。第一個(gè)明文分組加密時(shí)需要一個(gè)初始化向量。
CFB 模式
密文反饋模式(Cipher FeedBack),上一個(gè)密文分組作為下一個(gè)加密算法的輸入,加密算法的輸出與明文分組異或結(jié)果作為密文分組。同樣需要一個(gè)初始化向量
OFB 模式
輸出反饋模式(OutPut FeedBack),上一個(gè)加密算法的輸出作為下一個(gè)加密算法的輸入,明文與加密算法的輸出異或作為密文分組。需要初始化向量
CTR 模式
計(jì)數(shù)器模式(Counter),將計(jì)數(shù)器作為加密算法的輸入,加密算法的輸出與明文分組異或作為密文分組,計(jì)數(shù)器是累加的。需要一個(gè)初始的計(jì)數(shù)器值
以上各種模式,ECB 不推薦使用
golang 代碼實(shí)戰(zhàn):
func TestCBCMode(t *testing.T) {
key:=[]byte{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}
cipherBlock,err:=aes.NewCipher(key)
if err!=nil{
t.Error(err)
}
src:=[]byte{0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}
inv:=[]byte{0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}
cbcEncrypter:=cipher.NewCBCEncrypter(cipherBlock,inv)
encrptDst :=make([]byte,len(src))
cbcEncrypter.CryptBlocks(encrptDst,src)
t.Log(encrptDst)
plainDst:=make([]byte,len(encrptDst))
cbcDecrypter:=cipher.NewCBCDecrypter(cipherBlock,inv)
cbcDecrypter.CryptBlocks(plainDst,encrptDst)
t.Log(plainDst)
}
//out [182 174 175 250 117 45 192 139 81 99 151 49 118 26 237 0 98 117 59 208 145 166 116 62 43 199 115 70 250 251 56 226]
//out [1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8]
關(guān)于本文作者更多信息請查看: https://tpkeep.com
密碼學(xué)系列 - 對稱加密
本文討論的對稱加密算法主要包括 DES、3DES、AES
DES
明文:64 bit 密文:64 bit 密鑰:56/64 bit(每 7 位插入一個(gè)校驗(yàn)位的時(shí)候?yàn)?64 bit) 其設(shè)計(jì)思想充分體現(xiàn)了香農(nóng)提出的混淆和擴(kuò)散原則

DES 使用的是 Feistel 結(jié)構(gòu)來加密的,一共需要 16 輪,加密過程如下:
- 將明文進(jìn)行初始置換(通過置換表)
- 將置換后的數(shù)據(jù)分為左右 L1 R1 各 32 bit
- 將 48 bit 的子密鑰與 R1 作為輪函數(shù)F的輸入
- 將 L1 與輪函數(shù)的輸出異或運(yùn)算,得到 L1密文
- 將 L1 密文與 R1 交換位置,分別作為下一輪的 R2,L2
- 將 2-5 再重復(fù) 15 次
- 將 L17 R17 交換位置,并拼接為 64bit 數(shù)據(jù)
- 將 64bit 數(shù)據(jù)進(jìn)行逆初始置換,得到最終密文
需要注意的是:
- 子密鑰在每一輪中都是不一樣的
- 每一輪之間會(huì)將左側(cè)和右側(cè)對調(diào)(右側(cè)沒有加密)
- 解密的過程就是將輸出用相同的子密鑰再走一遍,如果加密的子密鑰順序是key1 key2 key3,則解密的子密鑰為key3 key2 key1
- 輪函數(shù)可以設(shè)計(jì)為不可逆函數(shù)如hash,對解密沒有影響

golang 代碼實(shí)戰(zhàn):
func TestDesEncrypt(t *testing.T) {
key:=[]byte{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}
cipherBlock,err:=des.NewCipher(key)
if err!=nil{
t.Error(err)
}
src:=[]byte{0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}
encrptDst :=make([]byte,len(src))
cipherBlock.Encrypt(encrptDst,src)
t.Log(encrptDst)
plainDst:=make([]byte,len(encrptDst))
cipherBlock.Decrypt(plainDst, encrptDst)
t.Log(plainDst)
}
//out: [206 173 55 61 184 14 171 248]
//out: [1 2 3 4 5 6 7 8]
三重DES
明文:64 bit 密文:64 bit 密鑰:56/64 * 3 bit(加入校驗(yàn)位的時(shí)候?yàn)?4 bit)
為了增加 DES 的強(qiáng)度,明文經(jīng)過 3 次 DES 處理后變成最后的密文,因此密鑰長度為 56/64 * 3 bit。3 次 DES 處理并不是簡單的 3 次加密的過程,而是加密、解密、加密,解密的過程相應(yīng)的就是解密、解密、解密。這樣設(shè)計(jì)是因?yàn)樵?3 個(gè)密鑰相同時(shí),可以兼容 DES 算法

golang 代碼實(shí)戰(zhàn):
func TestTripleDesEncrypt(t *testing.T) {
key:=[]byte{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}
cipherBlock,err:=des.NewTripleDESCipher(key)
if err!=nil{
t.Error(err)
}
src:=[]byte{0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}
encrptDst :=make([]byte,len(src))
cipherBlock.Encrypt(encrptDst,src)
t.Log(encrptDst)
plainDst:=make([]byte,len(encrptDst))
cipherBlock.Decrypt(plainDst, encrptDst)
t.Log(plainDst)
}
//此處3個(gè)密鑰相同,兼容DES
//out: [206 173 55 61 184 14 171 248]
//out: [1 2 3 4 5 6 7 8]
AES
明文:128 bit 密文:128 bit 密鑰:128/192/256 bit (分別需要10/12/14輪)
AES 標(biāo)準(zhǔn)最后評選出的算法是 Rijindale 算法,該算法支持密鑰 128/192/256 bit ,分別需要 10/12/14 輪,本文討論的是 128 bit密鑰。它的加密過程并沒有使用 DES 的 feistel 結(jié)構(gòu),而是使用了一種新的 SPN 結(jié)構(gòu),需要 10-14 輪計(jì)算,如下圖:

其中每一輪計(jì)算過程如下:
- SubBytes(字節(jié)替換):以字節(jié)大小為索引,與s_box表中字節(jié)映射
- ShiftRows(行移位-擴(kuò)散):從上到下從左到右的順序組成 4 * 4 數(shù)組,從 0 行開始,第 n 行向左平移 n 個(gè)字節(jié)
- MixColums(列混肴-擴(kuò)散):對每一列進(jìn)行矩陣運(yùn)算,共四列
- AddRoundKey(輪密鑰加):與輪密鑰即子密鑰異或運(yùn)算
需要注意的是:
- 最后一輪沒有列混淆
- 加密時(shí):SubBytes -> ShiftRows -> MixColums -> AddRoundKey 解密時(shí):AddRoundkey -> InvMixColums -> InvShiftRows -> InvSubBytes (Inv代表逆運(yùn)算)
golang 代碼實(shí)戰(zhàn):
func TestAesEncrypt(t *testing.T){
key:=[]byte{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}
cipherBlock,err:=aes.NewCipher(key)
if err!=nil{
t.Error(err)
}
src:=[]byte{0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}
encrptDst :=make([]byte,len(src))
cipherBlock.Encrypt(encrptDst,src)
t.Log(encrptDst)
plainDst:=make([]byte,len(encrptDst))
cipherBlock.Decrypt(plainDst, encrptDst)
t.Log(plainDst)
}
//out [19 7 34 196 163 153 225 186 223 245 40 131 80 80 70 203]
//out [1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8]
迭代模式
以上討論的三種加密算法都是分組密碼,每次只能處理特定長度的一塊數(shù)據(jù),例如 DES 和 3DES 能處理的這塊數(shù)據(jù)長度為 8 bytes,AES 的為 16 bytes。而我們的日常需要加密的明文基本上都是大于這個(gè)長度,這就需要我們將明文的內(nèi)容進(jìn)行分組并迭代加密,這個(gè)迭代加密的方式就是模式。
ECB 模式
電子密碼本模式(electronic codebook ),最簡單的模式,將明文分組直接作為加密算法的輸入,加密算法的輸出直接作為密文分組。
CBC 模式
密文分組鏈接模式(Cipher Block Chaining),密文之間是鏈狀的,明文分組跟上個(gè)密文分組異或之后作為加密算法的輸入,加密算法的輸出作為密文分組。第一個(gè)明文分組加密時(shí)需要一個(gè)初始化向量。
CFB 模式
密文反饋模式(Cipher FeedBack),上一個(gè)密文分組作為下一個(gè)加密算法的輸入,加密算法的輸出與明文分組異或結(jié)果作為密文分組。同樣需要一個(gè)初始化向量
OFB 模式
輸出反饋模式(OutPut FeedBack),上一個(gè)加密算法的輸出作為下一個(gè)加密算法的輸入,明文與加密算法的輸出異或作為密文分組。需要初始化向量
CTR 模式
計(jì)數(shù)器模式(Counter),將計(jì)數(shù)器作為加密算法的輸入,加密算法的輸出與明文分組異或作為密文分組,計(jì)數(shù)器是累加的。需要一個(gè)初始的計(jì)數(shù)器值
以上各種模式,ECB 不推薦使用
golang 代碼實(shí)戰(zhàn):
func TestCBCMode(t *testing.T) {
key:=[]byte{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}
cipherBlock,err:=aes.NewCipher(key)
if err!=nil{
t.Error(err)
}
src:=[]byte{0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}
inv:=[]byte{0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}
cbcEncrypter:=cipher.NewCBCEncrypter(cipherBlock,inv)
encrptDst :=make([]byte,len(src))
cbcEncrypter.CryptBlocks(encrptDst,src)
t.Log(encrptDst)
plainDst:=make([]byte,len(encrptDst))
cbcDecrypter:=cipher.NewCBCDecrypter(cipherBlock,inv)
cbcDecrypter.CryptBlocks(plainDst,encrptDst)
t.Log(plainDst)
}
//out [182 174 175 250 117 45 192 139 81 99 151 49 118 26 237 0 98 117 59 208 145 166 116 62 43 199 115 70 250 251 56 226]
//out [1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8]