Go-Des和3Des算法詳解與代碼您能夠查看倉庫Readme文檔或Go-包管理(管理工具對比及go mod的使用)來進行安裝

目錄git

Des算法

發展史安全

分組密碼算法設計思想app

Des概述ide

初始置換與逆置換函數

Feistel結構工具

輪函數F學習

E擴展測試

密鑰加加密

S盒代換

P置換

密鑰編排

3Des

優缺點

分組模式

CBC

CFB

OFB

Des的Go實現

明文填充

加密

解密

結果截圖

參考


Des

發展史

  • 1973年5月美國聯邦政府提出徵求在傳輸和存儲數據中保護計算機數據的密碼算法的建議;
  • 1975年3月,美國國家標準局(NBS)首次公佈IBM公司提出的算法Lucifer中選;
  • 1977年1月NBS正式向社會公佈,採納IBM公司設計的方案做爲非機密數據的數據加密標準(Data Encryption Standard),DES正式成爲美國聯邦政府信息處理標準,即FIPS-46標準,同年7月開始生效。
  •     此後,每隔5年美國國家保密局(NSA)對DES做新的評估,並從新審定它是否繼續做爲聯邦加密標準。

分組密碼算法設計思想

  1.  若是密碼體制不是冪等的(F2+F),那麼屢次迭代有可能提升密碼體制的安全性。
  2.  採用迭代結構的優勢:軟、硬件實現節省了代碼(硬件)資源。
  3. 混淆:明文/密鑰和密文之間的關係複雜。
  4. 擴散:明文/密鑰的每個比特都影響密文的每個比特。

Des概述

  • 明文和密文分組長度爲64比特
  • 算法包含兩部分:迭代加解密密鑰編排
  • Feistel結構(加解密類似):加密和解密除密鑰編排不一樣外,徹底相同
  • 密鑰長度:56比特(DES的密鑰空間:2^{56}),每7比特後爲一個奇偶校驗位(第8位),共64比特
  • 輪函數採用混亂和擴散的組合,共16輪

總體結構

明文進行初始置換(Initial Permutation,IP),經過密鑰編排算法將密鑰拆成16個,進行16輪迭代,最後經過逆置換獲得密文。

初始置換與逆置換

將輸入的64位數據塊按位從新組合,把輸出分爲L0、R0兩部分,每部分長32位。

58

50

42

34

26

18

10

2

60

52

44

36

28

20

12

4

62

54

46

38

30

22

14

6

64

56

48

40

32

24

16

8

57

49

41

33

25

17

9

1

59

51

43

35

27

19

11

3

61

53

45

37

29

21

13

5

63

55

47

39

31

23

15

7

表中的數字表明新數據中此位置的數據在原數據中的位置,即原數據塊的第58位放到新數據的第1位,第50位放到第2位,……依此類推。置換後的數據分爲L0和R0兩部分。

逆置換就是放回原位置,例如,1位置在40位置,那麼逆置換的第一個就是40,我就不一個個畫了

40 ...
... ...

因爲初始置換是公開的,沒有密碼意義。有不少DES實現都去除了,有人認爲是當時爲了更好放到DES芯片中。

Feistel結構

一輪迭代

按下述規則進行16次迭代,1≤i≤16

L_i=R_i

R_i=L_{i-1}\bigoplus f(R_{i-1},K_i)

輪函數F

F(R_{i-1},K_i)以長度爲32比特串R_{i-1}做爲第一輸入,以長度爲48比特串K_i做爲第二個輸入,產生長度爲32比特的輸出。

E擴展

32

1

2

3

4

5

4

5

6

7

8

9

8

9

10

11

12

13

12

13

14

15

16

17

16

17

18

19

20

21

20

21

22

23

24

25

24

25

26

27

28

29

28

29

30

31

32

1

R_{i-1}擴展爲48位,左右兩列數據是擴展的數據,擴展的數據是從相鄰位置取的一位,可理解爲循環隊列。靠近32位的位爲1,靠近1位的位爲32,其他就是下一行首或上一行末。

密鑰加

R_{i-1}的E擴展和K_i進行異或

S盒代換

使用8個S盒S1……S8,每一個Si是一個固定的4*16階矩陣,其元素取0~15之間的整數。
給定長度爲6的比特串,如Bj=b1b2b3b4b5b6,Sj(Bj)計算以下:

  1. b1b6兩個比特肯定了Sj的行r的二進制表示(0≤r≤3),
  2. b2b3b4b5四個比特肯定了Sj的列c的二進制表示(0≤c≤15),
  3. Sj(Bj)定義成長度爲4的比特串的值Sj(r,c)。由此能夠算出Cj=Sj(Bj),1≤j≤8。

S盒1以下:

14

4

13

1

2

15

11

8

3

10

6

12

5

9

0

7

0

15

7

4

14

2

13

1

10

6

12

11

9

5

3

8

4

1

14

8

13

6

2

11

15

12

9

7

3

10

5

0

15

12

8

2

4

9

1

7

5

11

3

14

10

0

6

13

其餘的我就不粘貼了,都是公開的,網上能找到,這裏只是爲了舉個例子。

假如,S1的輸入Bj爲110011

  1. b1b6爲11,r=3
  2. b2b3b4b5爲1001,c=9
  3. S1(3,9)爲11,二進制爲1011,Cj就是11了,即用1011替換了110011。

P置換

P盒以下:

16

7

20

21

29

12

28

17

1

15

23

26

5

18

31

10

2

8

24

14

32

27

3

9

19

13

30

6

22

11

4

25

長度爲32比特串C=C1C2C3C4C5C6C7C8,根據上面的進行替換,原理和前面的IP同樣,就是按照P盒放原始數據的多少位,第一個就放C的第16位,依次類推,最後組合一下便可,再也不舉例。

密鑰編排

前面是迭代加解密,接下來講下密鑰編排,密鑰編排就是經過密鑰K,得到每輪的密鑰ki,過程以下

 給定64比特密鑰K,根據固定的置換PC-1來處理K獲得PC-1(K)=C0D0,其中C0和D0分別由最前和最後28比特組成。下面是PC-1,注意,不包括8,16,24,32,40,48,56和64,前面提到,這些是校驗位。

57

49

41

33

25

17

9

1

58

50

42

34

26

18

10

2

59

51

43

35

27

19

11

3

60

52

44

36

63

55

47

39

31

23

15

7

62

54

46

38

30

22

14

6

61

53

45

37

29

21

13

5

28

20

12

4

計算Ci=LSi(Ci-1)和Di=LS(Di-1),且Ki=PC-2(CiDi),LSi表示循環左移兩個或一個位置,具體地,若是i=1,2,9,16就移一個位置,不然就移兩個位置,PC-2是另外一個固定的置換。下面是PC-2

14

17

11

24

1

5

3

28

15

6

21

10

23

19

12

4

26

8

16

7

27

20

13

2

41

52

31

37

47

55

30

40

51

45

33

48

44

49

39

56

34

53

46

42

50

36

29

32

以上就是一輪中獲取Ki的過程,每輪選取密鑰K的不一樣48比特進行PC-2的置換,一樣是16個矩陣,長寬與PC-2相同,這裏就不粘貼了,否則文章太長了。

3Des

3DES,顧名思義,使用三次DES算法,有兩種模式。

DES-EEE3模式:使用 P->DES加密->DES加密->DES加密->C 進行加密,使用 C->DES解密->DES解密->DES解密->P 進行解密。

DES-EDE3模式:使用 P->DES加密->DES解密->DES加密->C 進行加密,使用 C->DES解密->DES加密->DES解密->P 進行解密。

優缺點

優勢:

  • 密鑰長度增長到112位或168位,克服了DES面臨的窮舉***。
  • 相對於DES,加強了算法複雜度,提升了安全性。
  • 因爲DES已經大規模使用,升級到3DES比更新新算法成本小得多。
  • DES比其它任何加密算法受到的分析時間都長的多,相應地,3DES抗分析能力更強。

不足:

  • 3DES加解速度較慢。
  • 雖然密鑰長度增長了,但明文分組長度沒變,與密鑰長度的增加不匹配。
分組模式

分組密碼在加密時,明文分組的長度是固定的,而實際應用中待加密消息的數據量是不定的,數據格式多種多樣。爲了能在各類應用場合使用DES,美國在FIPS PUS 74和81中定義了DES的4種運行模式:
ECB,CBC,CFB,OFB,分組密碼工做模式描述瞭如何重複加密比較長的多個數據塊。

ECB,CBC是塊模式,CFB、OFB是流模式。ECB安全性比較差,先不學了,Go的包中也沒有。

CBC

CBC(Cipher Block Chaining, 密碼塊鏈)模式中每個分組要先和前一個分組加密後的數據進行異或操做,而後再進行加密

加密:C_i=E(P_i\oplus C_{i-1},K)

解密:P_i=D(C_i,K) \oplus C_{i-1}

  • IV:initialization vector,初始向量,
  • 將長消息分塊,若最後一個分塊不足分組長度,則須要填充
  • 加密和解密過程分別調用加密算法和解密算法
  • 存在密文擴展(明文填充帶來的擴展和IV傳輸的擴展
  • 密文塊需按順序逐一解密
  • 存在錯誤傳播(只傳播下一塊密文)
  • 適合大於一個分組長度的長數據加密

CFB

CFB(Cipher Feedback, 密碼反饋)模式和CBC模式比較類似,前一個分組的密文加密後當前分組的明文異或操做生成當前分組的密文。

加密:C_i=E(C_{i-1},K)\oplus P_i

解密:P_i=E(C_{i-1},K) \oplus C_i

注意,解密函數與加密函數一致

  • 消息做爲比特流進行加密,無須分組填充
  • 加密和解密過程只調用加密算法
  • 存在密文擴展(IV傳輸的擴展
  • 密文塊需按順序逐一解密
  • 存在錯誤傳播(只傳播後面的幾塊)
  • 適合大於一個分組長度的長數據加密
  • 可用於自同步序列密碼

OFB

OFB(Output Feedback,輸出反饋)模式與CFB模式相似,區別在於使用上一個分組的密碼序列加密生成當前分組的密碼序列。

總結

  • ECB是最快、最簡單的分組密碼模式,但它的安全性最弱,通常不推薦使用ECB加密消息,但若是是加密隨機數據,如密鑰,ECB則是最好的選擇。
  • CBC適合文件加密,並且有少許錯誤時不會形成同步失敗,是軟件加密的最好選擇。
  • CFB一般是加密分組序列所選擇的模式,它也能容忍少許錯誤擴展,且具備同步恢復功能。推薦使用CTR模式代替。
  • OFB是在極易出錯的環境中選用的模式,但需有高速同步機制。推薦使用CTR模式代替。

CTR模式在學AES時再說。

好,以上都沒什麼用,由於DES被破解啦!!!(看到這句話的小夥伴都快哭了)不過,增強版還能夠用,接下來就說說3DES。

Des的Go實現

咱們不是使用Go語言來實現Des,已經有大神寫好了,咱們會調用就能夠了。

des包

func NewCipher(key []byte) (cipher.Block, error)

建立並返回一個使用DES算法的cipher.Block接口。

cipher包

func NewCBCEncrypter(b Block, iv []byte) BlockMode

返回一個密碼分組連接模式的、底層用b加密的BlockMode接口,初始向量iv的長度必須等於b的塊尺寸。

BlockMode的方法

CryptBlocks(dst, src []byte) 

加密或解密連續的數據塊,src的尺寸必須是塊大小的整數倍,src和dst可指向同一內存地址 

func NewCBCDecrypter(b Block, iv []byte) BlockMode

返回一個密碼分組連接模式的、底層用b解密的BlockMode接口,初始向量iv必須和加密時使用的iv相同。 

明文填充

CBC模式須要填充,解密後咱們還須要去掉填充,因爲填充什麼沒有要求,咱們就填充缺乏的長度,這樣去掉填充時就容易切片了。

func PaddingLastGroup(plainText []byte,blockSize int) []byte{
	padNum := blockSize - len(plainText)%blockSize
	char := []byte{byte(padNum)}
	newPlain := bytes.Repeat(char,padNum)
	plainText = append(plainText,newPlain...)
	return plainText
}
func UnpaddingLastGroup(plainText []byte) []byte {
	length := len(plainText)
	number := int(plainText[length-1])
	return plainText[:length-number]
}

加密

  • 使用des.NewCipher獲取塊
  • 填充明文
  • 使用cipher.NewCBCEncrypter生成CBC模式塊
  • 使用模式塊的CryptBlocks進行加密,因爲可指向同一內存地址,咱們仍使用同一變量,節省內存
func DesEncrypt(plainText,iv, key []byte) ([]byte,error) {
	if len(iv) != 8{
		_, file, line, _ := runtime.Caller(0)
		return nil,util.Error(file,line+1,errors.IvError)
	}
	block, err :=des.NewCipher(key)
	if err != nil{
		_, file, line, _ := runtime.Caller(0)
		return nil,util.Error(file,line+1,errors.DesKeyError)
	}
	// padding plainText
	newText := util.PaddingLastGroup(plainText,des.BlockSize)
	// Create a CBC interface
	blockMode := cipher.NewCBCEncrypter(block,iv)
	// use same one to save space
	blockMode.CryptBlocks(newText,newText)
	return newText,nil
}

解密

  • 使用des.NewCipher獲取塊
  • 使用cipher.NewCBCDecrypter生成CBC模式塊
  • 使用模式塊的CryptBlocks進行解密
  • 去掉明文填充
func DesDecrypt(cipherText,iv,key []byte) ([]byte,error) {
	if len(iv) != 8{
		_, file, line, _ := runtime.Caller(0)
		return nil,util.Error(file,line+1,errors.IvError)
	}
	block, err :=des.NewCipher(key)
	if err != nil{
		_, file, line, _ := runtime.Caller(0)
		return nil,util.Error(file,line+1,errors.DesKeyError)
	}
	// Create a CBC interface
	blockMode := cipher.NewCBCDecrypter(block,iv)
	plainText := make([]byte,len(cipherText))
	blockMode.CryptBlocks(plainText,cipherText)
	return util.UnpaddingLastGroup(plainText),nil
}

部分測試代碼

iv := []byte("12345678")
	key := []byte("ladykill")
	plainText := []byte("hellocrypto")
	cipherText,err := DesEncrypt(plainText,iv,key)
	if err != nil{
		fmt.Println(err)
		os.Exit(0)
	}
	fmt.Printf("加密後:%s\n",string(cipherText))
	decryText,_ := DesDecrypt(cipherText,iv,key)
	fmt.Printf("解密後:%s\n",string(decryText))

結果截圖

3Des只須要建立時使用des.NewTripleDESCipher(key)便可。

代碼我放到了gitee上:https://gitee.com/frankyu365/gocrypto

您能夠查看倉庫Readme文檔或Go-包管理(管理工具對比及go mod的使用)來進行安裝

參考

《現代密碼學教程 谷利澤,楊義先等》

Go標準庫-crypto/des

Go標準庫-crypto/cipher

更多Go相關內容:Go-Golang學習總結筆記

有問題請下方評論,轉載請註明出處,並附有原文連接,謝謝!若有侵權,請及時聯繫。·

相關文章
相關標籤/搜索