深入理解 SHA 系列加密算法及Go语言运用

SHA 是一系列的加密算法,有 SHA-1、SHA-2、SHA-3 三大类,而 SHA-1 已经被破解,SHA-3 应用较少,目前应用广泛相对安全的是 SHA-2 算法,这也是本篇文章重点要讲述的算法。

一、算法核心思想和特点

该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段密文,也可以简单的理解为取一串输入码,并把它们转化为长度较短、位数固定的输出序列即散列值的过程。

1. 单向性

单向散列函数的安全性在于其产生散列值的操作过程具有较强的单向性。如果在输入序列中嵌入密码,那么任何人在不知道密码的情况下都不能产生正确的散列值,从而保证了其安全性。SHA 将输入流按照每块 512 位进行分块,并产生 160 位的被称为信息认证代码或信息摘要的输出。

2. 数字签名

通过散列算法可实现数字签名,数字签名的原理是将要传送的明文通过一种函数运算(Hash)转换成报文摘要,报文摘要加密后与明文一起传送给接受方,接受方将接受的明文产生新的报文摘要与发送方的发来报文摘要比较,比较结果一致表示明文未被改动,如果不一致表示明文已被篡改。

二、hash碰撞

哈希算法的一个重要功能是产生独特的散列,当两个不同的值或文件可以产生相同的散列,则称碰撞。保证数字签名的安全性,就是在不发生碰撞时才行。碰撞对于哈希算法来说是极其危险的,因为碰撞允许两个文件产生相同的签名。当计算机检查签名时,即使该文件未真正签署,也会被计算机识别为有效的。

一个哈希位有 0 和 1 两个可能值,则每一个独立的哈希值通过位的可能值的数量对于 SHA-256,有 2 的 256 次方种组合,这是一个庞大的数值。哈希值越大,碰撞的机率就越小。每个散列算法,包括安全算法,都会发生碰撞,而 SHA-1 的大小结构发生碰撞的机率比较大,所以 SHA-1 被认为是不安全的。

三、Go语言使用SHA256算法

//方法一
func digest1(data []byte)([]byte,error){
	h := sha256.Sum256(data)
	return h[:],nil
}

//方法二
func digest2(data []byte) ([]byte, error) {
	h := sha256.New()
	h.Write(data)

	return h.Sum(nil),nil
}

四、SHA 256 算法原理解析

SHA-256 算法输入报文的最大长度不超过2^64 bit,输入按512-bit 分组进行处理,产生的输出是一个256-bit 的报文摘要。

SHA256算法主流程分三大模块:常量的初始化、信息预处理、使用到的逻辑运算。

1. 常量的初始化

这些常量的作用是和数据源进行计算,增加数据的加密性,那么大家可以想一下,如果常量是一些如 1、2、3 之类的整数,是不是就没什么加密可言了,所以需要这些常量很复杂,生成的规则是:对自然数中前 8 个(或 64 个)质数(2、3、5、7、11、13、17、19)的平方根的小数部分取前 32 bit(在后面的映射的过程中会用到这些常量)。

例如,2 的平方根的小数部分约为 0.414213562373095048,然后 0.414213562373095048 ≈ 6 ∗ 16−1 + a ∗ 16−2 + 0 ∗ 16−3+…

所以 2 的平方根的小数部分取前 32 bit 就得到:0 x 6a09e667。

2. SHA256 中用到两种常量

(1)8 个哈希初值=>自然数中前 8 个质数(2、3、5、7、11、13、17、19)的平方根的小数部分取前 32bit:

  			h0 := 0x6a09e667
  			h1 := 0xbb67ae85
  			h2 := 0x3c6ef372
  			h3 := 0xa54ff53a
  			h4 := 0x510e527f
  			h5 := 0x9b05688c
  			h6 := 0x1f83d9ab
  			h7 := 0x5be0cd19

(2)64 个哈希常量=>自然数中前 64 个质数(2、3、5、7、11、13、17、19、23、29、31、37、41、43、47、53、59、61、67、71、73、79、83、89、97…)的立方根的小数部分取前 32 bit:

  			428a2f98 71374491 b5c0fbcf e9b5dba5
  			3956c25b 59f111f1 923f82a4 ab1c5ed5
  			d807aa98 12835b01 243185be 550c7dc3
  			72be5d74 80deb1fe 9bdc06a7 c19bf174
  			e49b69c1 efbe4786 0fc19dc6 240ca1cc
  			2de92c6f 4a7484aa 5cb0a9dc 76f988da
  			983e5152 a831c66d b00327c8 bf597fc7
  			c6e00bf3 d5a79147 06ca6351 14292967
  			27b70a85 2e1b2138 4d2c6dfc 53380d13
  			650a7354 766a0abb 81c2c92e 92722c85
  			a2bfe8a1 a81a664b c24b8b70 c76c51a3
  			d192e819 d6990624 f40e3585 106aa070
  			19a4c116 1e376c08 2748774c 34b0bcb5
  			391c0cb3 4ed8aa4a 5b9cca4f 682e6ff3
  			748f82ee 78a5636f 84c87814 8cc70208
  			90befffa a4506ceb bef9a3f7 c67178f2

3. 信息预处理

预处理分两部分,第一部分是附加填充比特,第二部分是附加长度。目的是让整个消息满足指定的结构,从而处理起来可以统一化、格式化,这个也是计算机的基本思维方式,就是把复杂的数据转化为特定的格式,化繁为简、“去伪存真”。

4.附加填充比特

在报文末尾进行填充,使报文长度在对 512 取模以后的余数是 448。具体是:先补第一个比特为 1,然后都补 0,直到长度满足对 512 取模后余数是 448。需要注意即使长度已经满足对 512 取模后余数是 448,补位也必须要进行,这时要填充 512 个比特。所以,填充是至少补一位,最多补 512 位。例如:“abc”补位的过程。

  • a、b、c 对应的 ASCII 码分别是 97、98、99。
  • 对应的二进制编码为:01100001 01100010 01100011;
  • 首先补一个“1”:0110000101100010 01100011 1;
  • 然后补 423 个“0”:01100001 01100010 01100011 10000000 00000000 … 00000000;
  • 补位完成后的数据如下:
  			61626380 00000000 00000000 00000000
  			00000000 00000000 00000000 00000000
  			00000000 00000000 00000000 00000000
  			00000000 00000000

5. 附加长度值

是将原始数据的长度信息补到已经进行了填充操作的消息后面(就是第一步预处理后的信息),SHA256 用一个 64 位的数据来表示原始消息的长度。所以 SHA256 加密的原始信息长度最大是 264。

用上面的消息“abc”来操作,3 个字符,占用 24 个 bit,在进行了补长度的操作以后,整个消息就变成:

  		61626380 00000000 00000000 00000000
  		00000000 00000000 00000000 00000000
  		00000000 00000000 00000000 00000000
  		00000000 00000000 00000000 00000018

6. 逻辑运算

  • ∧ → 按位“与”
  • ¬ → 按位“补”
  • ⊕ → 按位“异或”
  • Sn → 右移 n 个 bit
  • Rn → 循环右移 n 个 bit

7. 核心算法

准备工作做好了,下面开始进入算法阶段。

**数据分解:**将原始数据分解成 512-bit 大小的块,例如,消息 M 可以被分解为 n 个块,于是整个算法需要做的就是完成 n 次迭代,n 次迭代的结果就是最终的哈希值,即 256bit 的数字摘要。

每次迭代进行的映射用 Map(Hi−1)=Hi 表示,摘要的初始值 H0,经过第一个映射后,得到 H1,即完成了第一次迭代,H1 经过第二次映射得到 H2,……,依次处理,最后得到 Hn,Hn 即为最终的 256-bit 消息摘要。

在 SHA256 算法中的最小运算单元称为“字”(Word),一个字是 32 位(byte),就是 4 个字节(bit),256 个字节(bit)就是 64 个字(word)。

映射 Map(Hi−1)=Hi 包含了 64 次加密循环,即进行 64 次加密循环即可完成一次迭代,通过维基百科上的流程图来看更直观一些:

说明:

  • 深蓝色方块是事先定义好的非线性函数,里面是逻辑运算。
  • ABCDEFGH 一开始分别是八个初始值,就是预处理中第一部分的 8 个常量。
  • Kt 是第 t 个密钥,密钥从预处理中第二部分 64 个常量里取。
  • Wt 是本区块产生第 t 个 word。

原消息被切成固定长度的区块,对每一个区块,产生 n 个 word,透过重复运作循环 n 次对 ABCDEFGH 这八个工作区块循环加密。最后一次循环所产生的八段字符串合起来即是此区块对应到的散列字符串。若原消息包含数个区块,则最后还要将这些区块产生的散列字符串加以混合才能产生最后的散列字符串。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值