当前位置: 首页 > news >正文

SHA-2

SHA-2算法概述

SHA-2家族成员(SHA-224、SHA-256、SHA-384、SHA-512 分别返回不同比特的结果)

SHA-2算法核心步骤

  1. 消息预处理(填充与长度附加)
  2. 初始化
  3. 消息分块处理
  4. 格式化输出

步骤详细

消息预处理(填充与长度附加)
6. 在原始消息末尾添加一个’1’位(十六进制0x80)
7. 填充0x00位直到 填充后的消息长度 ≡ 448 mod 512 单位是bit (512 bit = 64 字节)
8. 最后添加64 bit (8 字节)的原始消息长度(大端序)

不足64字节 可填充部分 > 9字节 (64 > 41 + 9 )
41Byte = 41 * 8 = 328bit = 0x0148 bit
在这里插入图片描述

不足64字节, 可填充部分 = 9字节 (64 = 55 + 9)
55Byte = 55 * 8 = 440bit = 0x01B8 bit
在这里插入图片描述

不足64字节, 可填充部分 < 9字节 (64 < 56 + 9)
56Byte = 56 * 8 = 448bit = 0x01C0 bit
在这里插入图片描述
初始化(K数组和H数组)
K数组: 取自自然数中前64个素数的立方根的小数部分的前32bit (8字节)
H数组: 取自自然数中前8个素数的平方根的小数部分的前32位(8字节)

// 初始化常量K(前64个素数的立方根的小数部分的前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个素数的平方根的小数部分的前32位)
var H = [8]uint32{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
}

消息分块处理

  1. 消息调度:
    1. 将512位块分为16个32位字
    2. 使用σ0和σ1函数扩展生成64个字
  2. 压缩函数:
    1. 初始化8个工作变量(a-h)
    2. 执行64轮迭代,每轮使用:
    3. 选择函数(Ch)
    4. 多数函数(Maj)
    5. Σ0和Σ1函数
    6. 常量K[i]
    7. 调度字w[i]
  3. 更新hash
    1. 将工作变量的结果累加到当前哈希值
    2. 使用模2³²加法
    blocks := len(data) / 64hash := H // 使用初始哈希值for i := 0; i < blocks; i++ {// 从当前块创建消息调度数组var w [64]uint32block := data[i*64 : (i+1)*64]// 将前16个元素设置为消息块的内容for j := 0; j < 16; j++ {w[j] = binary.BigEndian.Uint32(block[j*4 : (j+1)*4])}// 扩展消息调度数组(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. 主循环(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位哈希值转换为大端序字节数组
2. 拼接成32字节的最终结果

XOR

定义

  1. XOR(通常表示为 ⊕)

作用

  1. 交换变量值‌:XOR运算可以在不使用临时变量的情况下交换两个变量的值。具体操作如下:假设有两个变量A和B,初始值分别为X和Y。可以将A与B进行XOR运算,结果存储在临时变量T中。然后,将T与A进行XOR运算,恢复A的原始值。最后,将B与T进行XOR运算,实现B的值变为Y,同时A的值也变为X。这种方法不仅适用于简单的数值交换,还可以扩展到更大的数据结构和复杂的逻辑操作中‌

条件判断‌:在布尔运算中,XOR运算的特点是当两个操作数一真一假时,结果为真;否则为假。

‌数据安全‌:XOR运算常用于数据加密和校验。通过将明文与密钥进行XOR运算,可以得到密文,从而实现数据的加密。同样,通过将密文与密钥进行XOR运算,可以恢复出原始数据。

字节序

0x01020304, 0x05060708
小端序 : 0x04 0x03 0x02 0x01 0x08 0x07 0x06 0x05

大端序 :
在这里插入图片描述

完整函数

package mainimport ("encoding/binary""fmt"
)// 初始化常量K(前64个素数的立方根的小数部分的前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个素数的平方根的小数部分的前32位)
var H = [8]uint32{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
}// 辅助函数:循环右移
作用:执行32位整数的循环右移操作原理:
将x右移n位,获取右侧n位
将x左移(32-n)位,获取左侧32-n位
通过位或(|)操作合并两部分示例:rotr(0x12345678, 8)0x78123456func rotr(x uint32, n uint) uint32 {return (x >> n) | (x << (32 - n))
}// 辅助函数:按位选择函数(Ch)
作用:根据e的位值选择f或g的对应位真值表:e	f	g	结果
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原理:当e=1时,选择f的对应位 当e=0时,选择g的对应位func ch(e, f, g uint32) uint32 {return (e & f) ^ (^e & g)
}// 辅助函数:多数函数(Maj)
作用:返回a,b,c三个输入中占多数的位值真值表:a	b	c	结果
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
原理:当至少两个输入为1时输出1func maj(a, b, c uint32) uint32 {return (a & b) ^ (a & c) ^ (b & c)
}// 辅助函数:Σ0函数
作用:对输入进行非线性扩散操作:
循环右移2位
循环右移13位
循环右移22位
三个结果进行异或目的:破坏输入中的位相关性,增加混func sum0(x uint32) uint32 {return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22)
}// 辅助函数:Σ1函数
作用:对输入进行非线性扩散操作:
循环右移6位
循环右移11位
循环右移25位
三个结果进行异或目的:破坏输入中的位相关性,增加混淆func sum1(x uint32) uint32 {return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25)
}// 辅助函数:σ0函数
作用:消息扩展中的非线性变换操作:
循环右移7位
循环右移18位
逻辑右移3位三个结果进行异或
目的:扩展消息块时引入非线性特性func sigma0(x uint32) uint32 {return rotr(x, 7) ^ rotr(x, 18) ^ (x >> 3)
}// 辅助函数:σ1函数
操作:
循环右移17位
循环右移19位
逻辑右移10位
三个结果进行异或目的:扩展消息块时引入非线性特性func sigma1(x uint32) uint32 {return rotr(x, 17) ^ rotr(x, 19) ^ (x >> 10)
}// SHA-256主函数
func sha256(data []byte) [32]byte {// 1. 消息预处理(填充)ml := uint64(len(data) * 8) // 原始消息长度(位)data = append(data, 0x80)  // 添加1个1位和7个0位(0x80 = 10000000)// 计算需要填充的0字节数padding := (56 - (len(data) % 64)) % 64if padding < 0 {padding += 64}// 添加填充字节(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++ {// 从当前块创建消息调度数组var w [64]uint32block := data[i*64 : (i+1)*64]// 将前16个元素设置为消息块的内容for j := 0; j < 16; j++ {w[j] = binary.BigEndian.Uint32(block[j*4 : (j+1)*4])}// 扩展消息调度数组(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. 主循环(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字节数组var result [32]bytefor i, s := range hash {binary.BigEndian.PutUint32(result[i*4:(i+1)*4], s)}return result
}// 辅助函数:将字节数组转换为十六进制字符串
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("预期: %s\n", test.expect)fmt.Printf("结果: %t\n\n", hex == test.expect)}
}

相关文章:

  • 安卓9.0系统修改定制化____支持安卓9.0系统修改的一些解包 打包工具解析 基础篇 三
  • 日语学习-日语知识点小记-进阶-JLPT-真题训练-N2阶段(2):2020年12月2018年7月
  • Python基础教学:小数保留位数方法总结-由Deepseek产生
  • c++类型擦除
  • 从bootloader跳到APP需要几步?
  • JavaSE: 数组详解
  • [直播推流] rtmpdump 库学习
  • 严格三角形方程组
  • Unity中的transform.Translate
  • MySQL-DCL数据控制语言详解
  • gcc升级问题
  • Web第二次方向考核复盘
  • MacBook命令行提示符添加git分支信息
  • Git(三) Git 分支工作流管理模型探究与实践
  • C语言空指针异常在Java中的解决方案
  • 深入理解IOC与DI
  • CPU的异常处理
  • java读取yml配置文件2
  • iOS —— UI(2)
  • 机器学习模型评估与选择
  • 完善网站建设报告/企业微信scrm
  • 怎么做幼儿园的网站/优化落实疫情防控新十条
  • 网站建设和推广话术/网站维护一年一般多少钱?
  • 做网站和推广需要多少钱/查询网站信息
  • 哪些网站做外链好/北京网络推广公司wyhseo
  • 南昌百恒信息技术有限公司/如何推广seo