信息摘要算法之三:sha256算法分析与实现

木南创智 木南创智     2022-10-12     607

关键词:

前面一篇中我们分析了SHA的原理,并且以SHA1为例实现了相关的算法,在这一片中我们将进一步分析SHA2并实现之。

1SHA简述

前面的篇章中我们已经说明过,SHA实际包括有一系列算法,分别是SHA-1、SHA-224、SHA-256、SHA-384以及SHA-512。而我们所说的SHA2实际是对后面4中的统称。各种SHA算法的数据比较如下表,其中的长度单位均为位:

从上表中我们不难发现,SHA-224和SHA-256、SHA-384和SHA-512在消息长度、分组长度、计算字长以及计算步骤各方面分别都是一致的。事实上通常认为SHA-224是SHA-256的缩减版,而SHA-384是SHA-512的缩减版。所以在接下来的讨论中,我们把SHA-224和SHA-256作为一组,而把SHA-384和SHA-512作为另一组来讨论。在这一篇我们先来分析和实现SHA-224和SHA-256算法。

2、消息的填充与解析

在这里我们讨论的散列函数用于在计算机中将根据作为输入消息或者数据文件生成其对应的信息摘要。消息或数据文件通常被作为是位字符串。消息的长度是消息中的比特数(空消息的长度为0)。如果消息中的比特数是8的倍数,那么我们就可以用十六进制来表示消息的紧凑性。消息填充的目的是为了在消息填充后,在SHA-224和SHA-256中消息的长度正好是512位的整数倍。

接下来我们说明消息或者数据文件将如何实现填充。总的来说就是,先添加一个“1”,再后跟多个“0”,然后再追加一个64位的消息长度信息,使得填充完成后的消息长度正好是512位的整数倍。追加的64位的消息长度信息是原始消息的位长,填充完成的消息会被分成512位的消息分组。

对于SHA-224和SHA-256来说消息的最大长度L<264,在对消息进行散列运算之前需要对消息做相应的填充处理。

首先,在原始信息之后填充一个“1”,例如:如果原始信息是"01010000",完成这一填充之后就是 "010100001"。

接下来,在完成上一步填充后,在其后面需天充一定数量的“0”,数量记为K,则K的取值必须是满足下述表达式的最小非负整数值。

( L + 1 + K ) mod 512 = 448

最后,在填充完必的消息后,追加64位的原始消息长度,因为消息的长度不会超过264位,所以其长度数据的值不会超过64位。填充完毕后,所有的消息分组都将是一个512位。

3、迭代函数与常数

SHA算法这类散列算法的计算过程都需要用到逻辑函数和计算常量。但由于具体算法的不同所使用的具体的函数和常数略有差别。我们在前面的篇章中说过MD5和SHA1,它们都有4个逻辑函数,而在SHA2的一系列算法中都采用了6个逻辑函数。接下来将说明SHA-224和SHA-256的逻辑函数和常量。

SHA-224和SHA-256采用6个逻辑函数,每个函数均基于32位字运算,这些输入的32位字我们记为x、y、z,同样的这些函数的计算结果也是一个32位字。这些逻辑函数表示如下:

CH( x, y, z) = (x AND y) XOR ( (NOT x) AND z)

MAJ( x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)

BSIG0(x) = ROTR^2(x) XOR ROTR^13(x) XOR ROTR^22(x)

BSIG1(x) = ROTR^6(x) XOR ROTR^11(x) XOR ROTR^25(x)

SSIG0(x) = ROTR^7(x) XOR ROTR^18(x) XOR SHR^3(x)

SSIG1(x) = ROTR^17(x) XOR ROTR^19(x) XOR SHR^10(x)

SHA-224和SHA-256采用相同的,64个32位的常数序列。通常记为:K0、K1、……、K63,这些常数的取值是前64个质数的立方根的小数部分的前32位。这些数以16进制表示如下:

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

4、计算过程

前面,我们已经介绍了消息的预处理及散列逻辑函数,接下来我们将说明摘要的计算过程。

每个安全散列函数的输出,在应用到一个分为N个分组的消息后,结果记为散列量H(N)。对于SHA-224和SHA-256,H(i)可以被认为是8个32位的字,记为:H(i)0、H(i)1、…、H(i)7。

散列字被初始化为一个特定的值,并在处理完每一个消息分组后对它进行更新,并在处理最后一个块后将其连接起来以产生输出。对于SHA-256,所有的H(N)变量都是串联的,而SHA-224散列值是通过最后连接时,省略一些而产生的。

接下来我们说明一下SHA-224和SHA-256的计算过程。首先初始化链接变量。对于SHA-224来说,初始散列值H(0)由以下8个32位的十六进制数组成:

H(0)0 = c1059ed8

H(0)1 = 367cd507

H(0)2 = 3070dd17

H(0)3 = f70e5939

H(0)4 = ffc00b31

H(0)5 = 68581511

H(0)6 = 64f98fa7

H(0)7 = befa4fa4

而对于SHA-256来说,初始散列值H(0)由以下8个32位的十六进制数组成。这些字由前8个质数的平方根的小数部分的钱32位组成。

H(0)0 = 6a09e667

H(0)1 = bb67ae85

H(0)2 = 3c6ef372

H(0)3 = a54ff53a

H(0)4 = 510e527f

H(0)5 = 9b05688c

H(0)6 = 1f83d9ab

H(0)7 = 5be0cd19

接下来我们描述一下摘要计算,SHA-224和SHA-256在消息分组执行相同的处理,只在初始化H(0)和如何生成最终输出的过程中有所不同。SHA-224和SHA-256可以用来散列处理长度为L位的消息,其中0 < L< = 264。算法使用一个64个32位字的消息列表, 8个工作变量32位以及8个32位字的散列值。

消息列表每32位分为一个子分组,被标记为W0、W1、…、W63。8个工作变量分别为a、b、c、d、e、f、g和h,8个散列值被标记为h(i)0、h(i)1、…、H(i)7,并保留初始散列值H(0),替换为每一个连续的中间散列值(在处理完每个消息分组后) H(i),并以最终的散列值H(N)结束,在处理完所有N块后。它们还使用两个临时变量T1和T2。

从前面我们知道,填充完了之后消息被分为了512位的消息分组。每个分组被分为16个32位的子分组,记为:M(i)0、M(i)1、...、M(i)15。将对N个消息分组进行如下操作。

a64个消息列表的生成

For t = 0 to 15

Wt = M(i)t

For t = 16 to 63

Wt = SSIG1(W(t-2)) + W(t-7) + SSIG0(w(t-15)) + W(t-16)

b、初始化工作变量

a = H(i-1)0

b = H(i-1)1

c = H(i-1)2

d = H(i-1)3

e = H(i-1)4

f = H(i-1)5

g = H(i-1)6

h = H(i-1)7

c、执行散列计算

For t = 0 to 63

T1 = h + BSIG1(e) + CH(e,f,g) + Kt + Wt

T2 = BSIG0(a) + MAJ(a,b,c)

h = g

g = f

f = e

e = d + T1

d = c

c = b

b = a

a = T1 + T2

d、计算中间散列值

H(i)0 = a + H(i-1)0

H(i)1 = b + H(i-1)1

H(i)2 = c + H(i-1)2

H(i)3 = d + H(i-1)3

H(i)4 = e + H(i-1)4

H(i)5 = f + H(i-1)5

H(i)6 = g + H(i-1)6

H(i)7 = h + H(i-1)7

在对所有消息分组完成上述计算之后,计算最终输出。对于SHA-256,是所有H(N)0、H(N)1到H(N)7的串联。对于SHA-224,则是H(N)0、H(N)1直到H(N)6的串联。

5、代码实现

前面我们已经说明了SHA-256(SHA-224)的计算过程,接下来我们将这一过程代码化。同样的首先定义一个上下文的结构。

 1 /** 定义SHA-256哈希操作的内容信息结构体 */
 2 typedef struct SHA256Context {
 3   uint32_t Intermediate_Hash[SHA256HashSize/4]; /* 信息摘要 */
 4   uint32_t Length_High;                         /* 按位计算的信息长度高字 */
 5   uint32_t Length_Low;                          /* 按位计算的信息长度低字 */
 6   int_least16_t Message_Block_Index;            /* 信息分组数组的索引 */
 7   uint8_t Message_Block[SHA256_Message_Block_Size];/* 512位信息分组 */
 8   int Computed;                                 /* 摘要计算标识 */
 9   int Corrupted;                                /* 信息摘要损坏标识 */
10 } SHA256Context;

接下来实现SHA256Context结构的初始化,为后续的计算过程做准备。

 1 static SHAStatusCode SHA224_256Reset(SHA256Context *context, uint32_t *H0)
 2 {
 3   if (!context) return shaNull;
 4   context->Length_High = context->Length_Low = 0;
 5   context->Message_Block_Index = 0;
 6   context->Intermediate_Hash[0] = H0[0];
 7   context->Intermediate_Hash[1] = H0[1];
 8   context->Intermediate_Hash[2] = H0[2];
 9   context->Intermediate_Hash[3] = H0[3];
10   context->Intermediate_Hash[4] = H0[4];
11   context->Intermediate_Hash[5] = H0[5];
12   context->Intermediate_Hash[6] = H0[6];
13   context->Intermediate_Hash[7] = H0[7];
14   context->Computed = 0;
15   context->Corrupted = shaSuccess;
16   return shaSuccess;
17 }

接下来实现信息分组的输入,这个函数接受一个字节数组作为下一个消息分组以便进行处理。

 1 SHAStatusCode SHA256Input(SHA256Context *context, const uint8_t *message_array,unsigned int length)
 2 {
 3   if (!context) return shaNull;
 4   if (!length) return shaSuccess;
 5   if (!message_array) return shaNull;
 6   if (context->Computed) return context->Corrupted = shaStateError;
 7   if (context->Corrupted) return context->Corrupted;
 8   while (length--)
 9   {
10     context->Message_Block[context->Message_Block_Index++] =*message_array;
11     if ((SHA224_256AddLength(context, 8) == shaSuccess) &&(context->Message_Block_Index == SHA256_Message_Block_Size))
12       SHA224_256ProcessMessageBlock(context);
13     message_array++;
14   }
15   return context->Corrupted;
16 }

当然还需要一个消息处理及最终摘要输出的函数,这个函数将返回一个224位或者256位的信息摘要到调用者给定的Message_Digest数组。返回的信息摘要,第一个元素索引为0,最后一个元素索引为27(SHA-2244)或者31(SHA-256)。

 1 static SHAStatusCode SHA224_256ResultN(SHA256Context *context,uint8_t Message_Digest[ ], int HashSize)
 2 {
 3   int i;
 4   if (!context) return shaNull;
 5   if (!Message_Digest) return shaNull;
 6   if (context->Corrupted) return context->Corrupted;
 7   if (!context->Computed)
 8     SHA224_256Finalize(context, 0x80);
 9   for (i = 0; i < HashSize; ++i)
10     Message_Digest[i] = (uint8_t)(context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ));
11   return shaSuccess;
12 }

至此我们就完成了SHA-256(SHA-224)的编码,在后续我们将对这一编码进行验证。

6、结论

上一节我们实现了SHA-256(SHA-224)的编码,接下来我们来对这一实现进行验证。我们输入明文“abcd”并输出结果:

 

同时我们对比一下其他工具生成的“abcd”的SHA-256的信息摘要结果如下:

 

对比上述两个结果,我们发现是完全一致的,说明我们的编码是没有问题的。

欢迎关注:

信息摘要算法之五:hmac算法分析与实现

...也经常被称作HMAC算法。1、HMAC概述HMAC算法首先它是基于信息摘要算法的。目前主要集合了MD和SHA两大系列消息摘要算法。其中MD系列的算法有HmacMD2、HmacMD4、HmacMD5三种算法;SHA系列的算法有Hmac 查看详情

信息摘要算法之二:sha1算法分析及实现

...之一,并被广泛使用。1、概述SHA算法能计算出一个数位信息所对应到的,长度固定的字串,又称信息摘要。而且如果输入信息有任何的不同,输出的对应摘要不同的机率非常高。因此SHA算法也是FIPS所认证的五种安全杂凑算法之... 查看详情

sha1、sha2安全hash算法

...256种组合sha1有2^160种组合。sha的实现原理与md5实现原理在信息填充(补位),扩展长度的处理是相同的,在数据处理,输出长度是不同的。数据完整性校验例如ssl的身份认证等 查看详情

什么是安全散列算法sha256

...的消息摘要。SHA1有如下特性:不可以从消息摘要中复原信息;两个不同的消息不会产生同样的消息摘要。一、术语和概念(一)位(Bit),字节(Byte)和字(Word)SHA1始终把消息当成一个位(bit)字符串来处理。本文中,一个“字... 查看详情

sha-256算法和区块链原理初探(代码片段)

...全证明,可以认为是一种实践中产生的算法。基本流程将信息m补齐到长度对512取模为448得到m‘将信息m‘尾部添加一个用64位表示的长度得到m"将信息m"按512位分割成n份,循环处理n次,最终获得一个256位的信息摘要m‘‘... 查看详情

使用 sha-256 摘要算法在 WSO2 ESB 中签署 SOAP 消息

】使用sha-256摘要算法在WSO2ESB中签署SOAP消息【英文标题】:SigningSOAPMessagesinWSO2ESBusingsha-256digestAlgorithm【发布时间】:2015-03-1813:25:31【问题描述】:我在使用wso2ESB中的壁垒来签署我的肥皂消息时遇到问题,我使用附加到传出端点... 查看详情

信息摘要算法之六:hkdf算法分析与实现

HKDF是一种特定的键衍生函数(KDF),即初始键控材料的功能,KDF从其中派生出一个或多个密码强大的密钥。在此我们想要描述的是基于HMAC的HKDF。1、HKDF概述密钥派生函数(KDF)是密码系统的基本组成部分。它的目标是获取一些初始的... 查看详情

第十五章加密算法实例1--注册登录(消息摘要算法)

...用户密码采用上述相同的算法加密,之后再与数据库中的信息进行比对,若相同,则登录15.2、实现(这里采用了SHA256算法,其他摘要算法MD5/SHA1/MAC类似)注意:这里的程序是在我之前写的一个maven+spring+springmvc+mybatis+velocity整合... 查看详情

jwt认证方案与禁用令牌策略(代码片段)

...碰撞)由于其唯一性,一般将数据的哈希值称为数据的摘要信息,称为数据的"指纹",用于检测数据是否被修改代表算法sha1sha256md5缺点哈希算法是公开的,如果可以获取到明文,就可以穷举出使用的算法消息认证MA哈希算法基础上混入秘... 查看详情

摘要算法

1、CRC8、CRC16、CRC32 2、MD2、MD4、MD5 3、SHA1、SHA256、SHA384、SHA512 4、RIPEMD、PANAMA、TIGER、ADLER32等  查看详情

sha256

首先SHA256和HMAC-SHA256是不一样的,HMAC-SHA256需要密钥生成摘要,而SHA256不需要。简述SHA-256算法的安全性 作者:ice 转载并学习。SHA安全加密标准,是至今世界上使用最广泛且安全的压缩算法之一,随着密码学研究的不断深... 查看详情

比特币背后的算法与数学(代码片段)

比特币实现中的哈希算法  可以说比特币的整个实现就是建立在已有的甚至存在多年的计算机科学领域里的技术或概念的整合,其中哈希算法在比特币中的应用几乎是方方面面,主要包括SHA256和RIPEMD160,比特币将这两个哈... 查看详情

常用的签名算法

...术A写在前面:加密和签名是两回事,加密的目的是防止信息泄露,签名的目的是防止篡改和伪造MD5、SHA-1、SHA-256、HMAC-SHA256等属于哈希算法,计算数字摘要,不可逆,有碰撞DES、AES、RSA等属于加密算法,对数据进行加解密,可逆... 查看详情

md5,sha1,sha256分别输出多少位啊?

...生出一个128位(16字节)的散列值(hashvalue),用于确保信息传输完整一致。2、SHA1安全哈希算法(SecureHashAlgorithm)主要适用于数字签名标准里面定义的数字签名算法。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要... 查看详情

python中hashlib模块的使用

hashlib是python下一款与加密相关的库包,提供摘要算法:md5、sha1、sha224、sha256、sha384、sha512、blake2b、blake2s、sha3_224、sha3_256、sha3_384、sha3_512、shake_128、shake_256。摘要算法通过摘要函数(单向函数)对任意长度的数据计算出固定长... 查看详情

c#|上位机开发新手指南摘要算法(代码片段)

...复杂的计算,将原始数据转换为一个固定长度的摘要信息。而且无论输入的数据大小,输出的摘要信息长度都是一样的。那么摘要算法有什么用处呢?比如数字签名,确保数据的来源和内容没有被篡改。还有密码... 查看详情

自己实现一个和python的库一模一样的sha_256算法(代码片段)

...这个算法和python3本身的实现相同,所以,同样的字串,摘要是相同的。importstructimportbinasciiimporthashlib#64个常数K_K=(0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a 查看详情

公钥、私钥、哈希、加密算法基础概念

...(又称Hash,常见的哈希算法有MD5、SHA等)得到一串摘要信息,然后用自己的私钥将摘要信息加密同文件发给B,B收到加密串和文件后,再用A的公钥来解密加密串,得到原始文件的摘要信息,与此同时,对接收到的文件进行摘要... 查看详情