區塊鏈教程區塊鏈背後的信息安全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
未完待續感謝關注兄弟連區塊鏈教程分享!