正規(guī)的網(wǎng)站建設(shè)seo博客網(wǎng)站
SHA-2算法概述
SHA-2家族成員(SHA-224、SHA-256、SHA-384、SHA-512 分別返回不同比特的結(jié)果)
SHA-2算法核心步驟
- 消息預(yù)處理(填充與長度附加)
- 初始化
- 消息分塊處理
- 格式化輸出
步驟詳細(xì)
消息預(yù)處理(填充與長度附加)
6. 在原始消息末尾添加一個’1’位(十六進(jìn)制0x80)
7. 填充0x00位直到 填充后的消息長度 ≡ 448 mod 512 單位是bit (512 bit = 64 字節(jié))
8. 最后添加64 bit (8 字節(jié))的原始消息長度(大端序)
不足64字節(jié) 可填充部分 > 9字節(jié) (64 > 41 + 9 )
41Byte = 41 * 8 = 328bit = 0x0148 bit
不足64字節(jié), 可填充部分 = 9字節(jié) (64 = 55 + 9)
55Byte = 55 * 8 = 440bit = 0x01B8 bit
不足64字節(jié), 可填充部分 < 9字節(jié) (64 < 56 + 9)
56Byte = 56 * 8 = 448bit = 0x01C0 bit
初始化(K數(shù)組和H數(shù)組)
K數(shù)組: 取自自然數(shù)中前64個素數(shù)的立方根的小數(shù)部分的前32bit (8字節(jié))
H數(shù)組: 取自自然數(shù)中前8個素數(shù)的平方根的小數(shù)部分的前32位(8字節(jié))
// 初始化常量K(前64個素數(shù)的立方根的小數(shù)部分的前32位)
var K = [64]uint32{0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
}// 初始化哈希值(前8個素數(shù)的平方根的小數(shù)部分的前32位)
var H = [8]uint32{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
}
消息分塊處理
- 消息調(diào)度:
- 將512位塊分為16個32位字
- 使用σ0和σ1函數(shù)擴(kuò)展生成64個字
- 壓縮函數(shù):
- 初始化8個工作變量(a-h)
- 執(zhí)行64輪迭代,每輪使用:
- 選擇函數(shù)(Ch)
- 多數(shù)函數(shù)(Maj)
- Σ0和Σ1函數(shù)
- 常量K[i]
- 調(diào)度字w[i]
- 更新hash
- 將工作變量的結(jié)果累加到當(dāng)前哈希值
- 使用模232加法
blocks := len(data) / 64hash := H // 使用初始哈希值for i := 0; i < blocks; i++ {// 從當(dāng)前塊創(chuàng)建消息調(diào)度數(shù)組var w [64]uint32block := data[i*64 : (i+1)*64]// 將前16個元素設(shè)置為消息塊的內(nèi)容for j := 0; j < 16; j++ {w[j] = binary.BigEndian.Uint32(block[j*4 : (j+1)*4])}// 擴(kuò)展消息調(diào)度數(shù)組(16-63)for j := 16; j < 64; j++ {w[j] = sigma1(w[j-2]) + w[j-7] + sigma0(w[j-15]) + w[j-16]}// 初始化工作變量a, b, c, d, e, f, g, h := hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7]// 3. 主循環(huán)(64輪)for j := 0; j < 64; j++ {// 計算臨時變量t1 := h + sum1(e) + ch(e, f, g) + K[j] + w[j]t2 := sum0(a) + maj(a, b, c)// 更新工作變量h = gg = ff = ee = d + t1d = cc = bb = aa = t1 + t2}// 4. 更新哈希值hash[0] += ahash[1] += bhash[2] += chash[3] += dhash[4] += ehash[5] += fhash[6] += ghash[7] += h}
格式化輸出
1. 將8個32位哈希值轉(zhuǎn)換為大端序字節(jié)數(shù)組
2. 拼接成32字節(jié)的最終結(jié)果
XOR
定義
- XOR(通常表示為 ⊕)
作用
- ?交換變量值?:XOR運算可以在不使用臨時變量的情況下交換兩個變量的值。具體操作如下:假設(shè)有兩個變量A和B,初始值分別為X和Y??梢詫與B進(jìn)行XOR運算,結(jié)果存儲在臨時變量T中。然后,將T與A進(jìn)行XOR運算,恢復(fù)A的原始值。最后,將B與T進(jìn)行XOR運算,實現(xiàn)B的值變?yōu)閅,同時A的值也變?yōu)閄。這種方法不僅適用于簡單的數(shù)值交換,還可以擴(kuò)展到更大的數(shù)據(jù)結(jié)構(gòu)和復(fù)雜的邏輯操作中?
?條件判斷?:在布爾運算中,XOR運算的特點是當(dāng)兩個操作數(shù)一真一假時,結(jié)果為真;否則為假。
?數(shù)據(jù)安全?:XOR運算常用于數(shù)據(jù)加密和校驗。通過將明文與密鑰進(jìn)行XOR運算,可以得到密文,從而實現(xiàn)數(shù)據(jù)的加密。同樣,通過將密文與密鑰進(jìn)行XOR運算,可以恢復(fù)出原始數(shù)據(jù)。
字節(jié)序
0x01020304, 0x05060708
小端序 :
大端序 :
完整函數(shù)
package mainimport ("encoding/binary""fmt"
)// 初始化常量K(前64個素數(shù)的立方根的小數(shù)部分的前32位)
var K = [64]uint32{0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
}// 初始化哈希值(前8個素數(shù)的平方根的小數(shù)部分的前32位)
var H = [8]uint32{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
}// 輔助函數(shù):循環(huán)右移
作用:執(zhí)行32位整數(shù)的循環(huán)右移操作原理:
將x右移n位,獲取右側(cè)n位
將x左移(32-n)位,獲取左側(cè)32-n位
通過位或(|)操作合并兩部分示例:rotr(0x12345678, 8) → 0x78123456func rotr(x uint32, n uint) uint32 {return (x >> n) | (x << (32 - n))
}// 輔助函數(shù):按位選擇函數(shù)(Ch)
作用:根據(jù)e的位值選擇f或g的對應(yīng)位真值表:e f g 結(jié)果
0 0 0 0
0 0 1 1
0 1 0 0
0 1 1 1
1 0 0 0
1 0 1 0
1 1 0 1
1 1 1 1原理:當(dāng)e=1時,選擇f的對應(yīng)位 當(dāng)e=0時,選擇g的對應(yīng)位func ch(e, f, g uint32) uint32 {return (e & f) ^ (^e & g)
}// 輔助函數(shù):多數(shù)函數(shù)(Maj)
作用:返回a,b,c三個輸入中占多數(shù)的位值真值表:a b c 結(jié)果
0 0 0 0
0 0 1 0
0 1 0 0
0 1 1 1
1 0 0 0
1 0 1 1
1 1 0 1
1 1 1 1
原理:當(dāng)至少兩個輸入為1時輸出1func maj(a, b, c uint32) uint32 {return (a & b) ^ (a & c) ^ (b & c)
}// 輔助函數(shù):Σ0函數(shù)
作用:對輸入進(jìn)行非線性擴(kuò)散操作:
循環(huán)右移2位
循環(huán)右移13位
循環(huán)右移22位
三個結(jié)果進(jìn)行異或目的:破壞輸入中的位相關(guān)性,增加混func sum0(x uint32) uint32 {return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22)
}// 輔助函數(shù):Σ1函數(shù)
作用:對輸入進(jìn)行非線性擴(kuò)散操作:
循環(huán)右移6位
循環(huán)右移11位
循環(huán)右移25位
三個結(jié)果進(jìn)行異或目的:破壞輸入中的位相關(guān)性,增加混淆func sum1(x uint32) uint32 {return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25)
}// 輔助函數(shù):σ0函數(shù)
作用:消息擴(kuò)展中的非線性變換操作:
循環(huán)右移7位
循環(huán)右移18位
邏輯右移3位三個結(jié)果進(jìn)行異或
目的:擴(kuò)展消息塊時引入非線性特性func sigma0(x uint32) uint32 {return rotr(x, 7) ^ rotr(x, 18) ^ (x >> 3)
}// 輔助函數(shù):σ1函數(shù)
操作:
循環(huán)右移17位
循環(huán)右移19位
邏輯右移10位
三個結(jié)果進(jìn)行異或目的:擴(kuò)展消息塊時引入非線性特性func sigma1(x uint32) uint32 {return rotr(x, 17) ^ rotr(x, 19) ^ (x >> 10)
}// SHA-256主函數(shù)
func sha256(data []byte) [32]byte {// 1. 消息預(yù)處理(填充)ml := uint64(len(data) * 8) // 原始消息長度(位)data = append(data, 0x80) // 添加1個1位和7個0位(0x80 = 10000000)// 計算需要填充的0字節(jié)數(shù)padding := (56 - (len(data) % 64)) % 64if padding < 0 {padding += 64}// 添加填充字節(jié)(0x00)data = append(data, make([]byte, padding)...)// 添加64位原始消息長度(大端序)mlBytes := make([]byte, 8)binary.BigEndian.PutUint64(mlBytes, ml)data = append(data, mlBytes...)// 2. 處理每個512位塊blocks := len(data) / 64hash := H // 使用初始哈希值for i := 0; i < blocks; i++ {// 從當(dāng)前塊創(chuàng)建消息調(diào)度數(shù)組var w [64]uint32block := data[i*64 : (i+1)*64]// 將前16個元素設(shè)置為消息塊的內(nèi)容for j := 0; j < 16; j++ {w[j] = binary.BigEndian.Uint32(block[j*4 : (j+1)*4])}// 擴(kuò)展消息調(diào)度數(shù)組(16-63)for j := 16; j < 64; j++ {w[j] = sigma1(w[j-2]) + w[j-7] + sigma0(w[j-15]) + w[j-16]}// 初始化工作變量a, b, c, d, e, f, g, h := hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7]// 3. 主循環(huán)(64輪)for j := 0; j < 64; j++ {// 計算臨時變量t1 := h + sum1(e) + ch(e, f, g) + K[j] + w[j]t2 := sum0(a) + maj(a, b, c)// 更新工作變量h = gg = ff = ee = d + t1d = cc = bb = aa = t1 + t2}// 4. 更新哈希值hash[0] += ahash[1] += bhash[2] += chash[3] += dhash[4] += ehash[5] += fhash[6] += ghash[7] += h}// 5. 格式化輸出為32字節(jié)數(shù)組var result [32]bytefor i, s := range hash {binary.BigEndian.PutUint32(result[i*4:(i+1)*4], s)}return result
}// 輔助函數(shù):將字節(jié)數(shù)組轉(zhuǎn)換為十六進(jìn)制字符串
func toHex(b [32]byte) string {const hextable = "0123456789abcdef"var out [64]bytefor i, v := range b {out[i*2] = hextable[v>>4]out[i*2+1] = hextable[v&0x0f]}return string(out[:])
}func main() {// 測試用例tests := []struct {input stringexpect string}{{"","e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",},{"hello world","b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",},{"The quick brown fox jumps over the lazy dog","d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",},}// 運行測試for _, test := range tests {hash := sha256([]byte(test.input))hex := toHex(hash)fmt.Printf("輸入: %q\n", test.input)fmt.Printf("計算: %s\n", hex)fmt.Printf("預(yù)期: %s\n", test.expect)fmt.Printf("結(jié)果: %t\n\n", hex == test.expect)}
}