SHA256算法原理及其实现
SHA-2 族算法简介
一个n位的哈希函数就是一个从任意长的消息到n位哈希值的映射,一个n位的加密哈希函数就是一个单向的、避免碰撞的n位哈希函数。这样的函数是目前在数字签名和密码保护当中极为重要的手段。
当前比较流行的哈希函数主要有128位的MD4和MD5和160位的SHA-1,今天介绍的SHA-2族有着更多位的输出哈希值,破解难度更大,能够提高更高的安全性。
SHA-2,名称来自于安全散列算法2(英语:Secure Hash Algorithm 2)的缩写,一种密码散列函数算法标准,由美国国家安全局研发,由美国国家标准与技术研究院(NIST)在2001年发布。属于SHA算法之一,是SHA-1的后继者。其下又可再分为六个不同的算法标准,包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。
这些变体除了生成摘要的长度、循环运行的次数等一些细微差异之外,基本结构是一致的。本文主要讲一讲SHA256。
SHA256原理详解
概述
对于任意长度的消息,SHA256都会产生一个256位的哈希值,称作消息摘要。这个摘要相当于是个长度为32个字节的数组,通常有一个长度为64的十六进制字符串来表示,其中1个字节=8位,一个十六进制的字符的长度为4位。
来看一个具体的例子:
1 | BlockChain |
这句话经过哈希函数SHA256后得到的哈希值为:
1 | 3a6fed5fc11392b3ee9f81caf017b48640d7458766a8eb0382899a605b41f2b9 |
总体上,SHA256与MD4、MD5以及HSA-1等哈希函数的操作流程类似,待哈希的消息在继续哈希计算之前首先要进行以下两个步骤:
- 对消息进行补位处理,是的最终的长度是512位的倍数,然后
- 以512位为单位对消息进行分块为
消息区块将进行逐个处理:从一个固定的初始哈希开始,进行以下序列的计算:
其中是SHA256的压缩函数,是mod加法,即将两个数字加在一起,如果对取余, 是消息区块的哈希值.
算法详细描述
SHA256的压缩函数主要对512位的消息区块和256位的中间哈希值进行操作,本质上,它是一个通过将消息区块为密钥对中间哈希值进行加密的256位加密算法。
因此,为了描述SHA256算法,有以下两方面的组件需要描述:
- SHA256压缩函数
- SHA256消息处理流程
以下的描述当中所使用到的标记如下:
- : 按位异或
- : 按位与
- : 按位或
- : 补位
- : 相加以后对求余
- : 右移n位
- : 循环右移n位
以上所有的操作都是针对32位字节.
常量初始化
初始哈希值取自自然数中前面8个素数(2,3,5,7,11,13,17,19)的平方根的小数部分, 并且取前面的32位. 下面举个例子:
小数部分约为0.414213562373095048, 而其中
于是, 质数2的平方根的小数部分取前32位就对应0x6a09e667.
如此类推, 初始哈希值由以下8个32位的哈希初值构成:
SHA256算法当中还使用到64个常数, 取自自然数中前面64个素数的立方根的小数部分的前32位, 如果用16进制表示, 则相应的常数序列如下:
1 | 428a2f98 71374491 b5c0fbcf e9b5dba5 |
消息预处理
在计算消息的哈希摘要之前需要对消息进行预处理:
- 对消息进行补码处理: 假设消息的二进制编码长度为位. 首先在消息末尾补上一位"1", 然后再补上个"0", 其中为下列方程的最小非负整数
举个例子, 以消息"abc"为例显示补位的过程.
a,b,c对应的ASCII码和二进制编码分别如下:
1 | 原始字符 ASCII码 二进制编码 |
因此, 原始信息"abc"的二进制编码为:01100001 01100010 01100011, 第一步补位, 首先在消息末尾补上一位"1", 结果为: 01100001 01100010 01100011 1;
然后进行第二步的补位, 因为, 可以得到, 在第一步补位后的消息后面再补423个"0", 结果如下:
最后还需要在上述字节串后面继续进行补码, 这个时候补的是原消息"abc"的二进制长度的64位二进制表示形式, 补完以后的结果如下:
最终补完以后的消息二进制位数长度是512的倍数.
这里需要注意的两点是不管原来的消息长度是多少, 即使长度已经满足对512取模后余数是448,补位也必须要进行,这时要填充512位. 另外, 考虑到最后要将消息长度转换为64位二进制编码, 因此, 长度的必须小于, 绝大多数情况, 这个足够大了.
- 将补码处理后的消息以512位为单位分块为: , 其中第个消息块的前32位表示为: , 后面32位为: , 以此类推, 最后32位的消息块可表示为: . 我们采用Big endian约定对数据进行编码, 即认为第一个字节是最高位字节, 因此, 对于每一个32位字节, 最最左边的比特是最大的比特位.
摘要计算主循环
哈希计算算法如下:
- ( = 补码后消息块个数)
- 用第
个中间哈希值来对 进行初始化, 当时, 就使用初始化哈希, 即:
- 用第
- 应用SHA256压缩函数来更新
-
- 计算(具体定义如下)
-
- 计算第个中间哈希值
- 为最终需要的哈希。
逻辑函数定义
SHA256算法当中所使用到的6个逻辑函数如下:每个函数都对32位字节进行操纵,并输出32位字节。
扩展消息块通过以下方式进行计算:
图形表示
SHA256压缩函数的图形表示如下:

扩展消息块的求解算法可以表示如下:

SHA伪代码
1 | Note 1: All variables are 32 bit unsigned integers and addition is calculated modulo 232 |
SHA256代码实现
下面是基于上述伪代码用go语言对SHA256进行的实现.
1 | package main |