兄弟連區塊鏈教程區塊鏈背後的資訊保安2DES、3DES加密演算法原理一
區塊鏈教程區塊鏈背後的資訊保安2DES、3DES加密演算法原理一,2018年下半年,區塊鏈行業正逐漸褪去發展之初的浮躁、迴歸理性,表面上看相關人才需求與身價似乎正在回落。但事實上,正是初期泡沫的漸退,讓人們更多的關注點放在了區塊鏈真正的技術之上。
DES、3DES加密演算法原理及其GO語言實現
DES加密演算法,為對稱加密演算法中的一種。70年代初由IBM研發,後1977年被美國國家標準局採納為資料加密標準,即DES全稱的由來:Data Encryption Standard。 對稱加密演算法,是相對於非對稱加密演算法而言的。兩者區別在於,對稱加密在加密和解密時使用同一金鑰,而非對稱加密在加密和解密時使用不同的金鑰,即公鑰和私鑰。 常見的DES、3DES、AES均為對稱加密演算法,而RSA、橢圓曲線加密演算法,均為非對稱加密演算法。
DES是以64位元的明文為一個單位來進行加密的,超過64位元的資料,要求按固定的64位元的大小分組,分組有很多模式,後續單獨總結,暫時先介紹DES加密演算法。 DES使用的金鑰長度為64位元,但由於每隔7個位元設定一個奇偶校驗位,因此其金鑰長度實際為56位元。奇偶校驗為最簡單的錯誤檢測碼,即根據一組二進位制程式碼中1的個數是奇數或偶數來檢測錯誤。
Feistel網路
DES的基本結構,由IBM公司的Horst Feistel設計,因此稱Feistel網路。 在Feistel網路中,加密的每個步驟稱為輪,經過初始置換後的64位明文,進行了16輪Feistel輪的加密過程,最後經過終結置換後形成最終的64位密文。
64位元明文被分為左、右兩部分處理,右側資料和子金鑰經過輪函式f生成用於加密左側資料的位元序列,與左側資料異或運算,運算結果輸出為加密後的左側,右側資料則直接輸出為右側。 其中子金鑰為本輪加密使用的金鑰,每次Feistel均使用不同的子金鑰。子金鑰的計算,以及輪函式的細節,稍後下文介紹。 由於一次Feistel輪並不會加密右側,因此需要將上一輪輸出後的左右兩側對調後,重複Feistel輪的過程,DES演算法共計進行16次Feistel輪,最後一輪輸出後左右兩側無需對調。
DES加密和解密的過程一致,均使用Feistel網路實現,區別僅在於解密時,密文作為輸入,並逆序使用子金鑰。
go標準庫中DES演算法實現如下:
func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) { b := binary.BigEndian.Uint64(src) //初始置換 b = permuteInitialBlock(b) left, right := uint32(b>>32), uint32(b) var subkey uint64 //共計16次feistel輪 for i := 0; i < 16; i++ { //加密和解密使用子金鑰順序相反 if decrypt { subkey = subkeys[15-i] } else { subkey = subkeys[i] } //feistel輪函式 left, right = right, left^feistel(right, subkey) } //最後一輪無需對調 preOutput := (uint64(right) << 32) | uint64(left) //終結置換 binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput)) } //程式碼位置src/crypto/des/block.go
初始置換和終結置換
進入Feistel輪之前,64位明文需做一次初始置換。Feistel輪結束後,需做一次反向操作,即終結置換。 初始置換和終結置換目的是為加強硬體的破解難度而加的。
附go標準庫中使用的初始置換表和終結置換表如下:
//初始置換表 var initialPermutation = [64]byte{ 6, 14, 22, 30, 38, 46, 54, 62, 4, 12, 20, 28, 36, 44, 52, 60, 2, 10, 18, 26, 34, 42, 50, 58, 0, 8, 16, 24, 32, 40, 48, 56, 7, 15, 23, 31, 39, 47, 55, 63, 5, 13, 21, 29, 37, 45, 53, 61, 3, 11, 19, 27, 35, 43, 51, 59, 1, 9, 17, 25, 33, 41, 49, 57, } //終結置換表 var finalPermutation = [64]byte{ 24, 56, 16, 48, 8, 40, 0, 32, 25, 57, 17, 49, 9, 41, 1, 33, 26, 58, 18, 50, 10, 42, 2, 34, 27, 59, 19, 51, 11, 43, 3, 35, 28, 60, 20, 52, 12, 44, 4, 36, 29, 61, 21, 53, 13, 45, 5, 37, 30, 62, 22, 54, 14, 46, 6, 38, 31, 63, 23, 55, 15, 47, 7, 39, } //程式碼位置src/crypto/des/const.go
子金鑰的計算
DES初始金鑰為64位,其中8位用於奇偶校驗,實際金鑰為56位,64位初始金鑰經過PC-1金鑰置換後,生成56位串。 經PC-1置換後56位的串,分為左右兩部分,各28位,分別左移1位,形成C0和D0,C0和D0合併成56位,經PC-2置換後生成48位子金鑰K0。 C0和D0分別左移1位,形成C1和D1,C1和D1合併成56位,經PC-2置換後生成子金鑰K1。 以此類推,直至生成子金鑰K15。但注意每輪迴圈左移的位數,有如下規定:
var ksRotations = [16]uint8{1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1} //程式碼位置src/crypto/des/const.go
go標準庫中DES子金鑰計算的程式碼如下:
func (c *desCipher) generateSubkeys(keyBytes []byte) { key := binary.BigEndian.Uint64(keyBytes) //PC-1金鑰置換,生成56位串 permutedKey := permuteBlock(key, permutedChoice1[:]) //56位串分左右兩部分,各28位,ksRotate為依次迴圈左移1位 leftRotations := ksRotate(uint32(permutedKey >> 28)) rightRotations := ksRotate(uint32(permutedKey<<4) >> 4) //生成子金鑰 for i := 0; i < 16; i++ { //合併左右兩部分,之後PC-2置換 pc2Input := uint64(leftRotations[i])<<28 | uint64(rightRotations[i]) c.subkeys[i] = permuteBlock(pc2Input, permutedChoice2[:]) } } //程式碼位置src/crypto/des/block.go
附go標準庫中使用的PC-1置換表和PC-2置換表:
//PC-1置換表 var permutedChoice1 = [56]byte{ 7, 15, 23, 31, 39, 47, 55, 63, 6, 14, 22, 30, 38, 46, 54, 62, 5, 13, 21, 29, 37, 45, 53, 61, 4, 12, 20, 28, 1, 9, 17, 25, 33, 41, 49, 57, 2, 10, 18, 26, 34, 42, 50, 58, 3, 11, 19, 27, 35, 43, 51, 59, 36, 44, 52, 60, } //PC-2置換表 var permutedChoice2 = [48]byte{ 42, 39, 45, 32, 55, 51, 53, 28, 41, 50, 35, 46, 33, 37, 44, 52, 30, 48, 40, 49, 29, 36, 43, 54, 15, 4, 25, 19, 9, 1, 26, 16, 5, 11, 23, 8, 12, 7, 17, 0, 22, 3, 10, 14, 6, 20, 27, 24, } //程式碼位置src/crypto/des/const.go
未完待續感謝關注兄弟連區塊鏈教程分享!