信息摘要算法之四:sha512算法分析与实现

木南创智 木南创智     2022-10-13     413

关键词:

前面一篇中我们分析了SHA256的原理,并且实现了该算法,在这一篇中我们将进一步分析SHA512并实现之。

1SHA简述

尽管在前面的篇章中我们介绍过SHA算法,但出于阐述的完整性我依然要简单的说明一下SHA算法。SHA主要有SHA-1、SHA-224、SHA-256、SHA-384以及SHA-512。各种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算法并实现之。

2、消息的填充与解析

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

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

对于SHA-384和SHA-512来说消息的最大长度L<2128,在对消息进行散列运算之前也需要对消息做相应的填充处理。SHA-384和SHA-512的消息填充过程与SHA-224和SHA-256的填充过程是基本一致的。

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

接下来,填充K个“0”,所不同的是消息分组的长度是1024位,所以K的取值必须是满足下述表达式的最小非负整数值。

( L + 1 + K ) mod 1024 = 896

最后,在填充完必的消息后,追加128位的原始消息长度,因为消息的长度不会超过2128位,所以其长度数据的值不会超过128位,这也是为什么上一步中需要取模余896的原因。填充完毕后,所有的消息分组都将是一个1024位。

3、迭代函数与常数

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

SHA-384和SHA-512也都有6个迭代函数,但是每个函数操作64位的输入字(x、y、z),输出也是一个新的 64 位字。这些逻辑函数表示如下:

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^28(x) XOR ROTR^34(x) XOR ROTR^39(x)

BSIG1(x) = ROTR^14(x) XOR ROTR^18(x) XOR ROTR^41(x)

SSIG0(x) = ROTR^1(x) XOR ROTR^8(x) XOR SHR^7(x)

SSIG1(x) = ROTR^19(x) XOR ROTR^61(x) XOR SHR^6(x)

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

428a2f98d728ae22 7137449123ef65cd b5c0fbcfec4d3b2f e9b5dba58189dbbc

3956c25bf348b538 59f111f1b605d019 923f82a4af194f9b ab1c5ed5da6d8118

d807aa98a3030242 12835b0145706fbe 243185be4ee4b28c 550c7dc3d5ffb4e2

72be5d74f27b896f 80deb1fe3b1696b1 9bdc06a725c71235 c19bf174cf692694

e49b69c19ef14ad2 efbe4786384f25e3 0fc19dc68b8cd5b5 240ca1cc77ac9c65

2de92c6f592b0275 4a7484aa6ea6e483 5cb0a9dcbd41fbd4 76f988da831153b5

983e5152ee66dfab a831c66d2db43210 b00327c898fb213f bf597fc7beef0ee4

c6e00bf33da88fc2 d5a79147930aa725 06ca6351e003826f 142929670a0e6e70

27b70a8546d22ffc 2e1b21385c26c926 4d2c6dfc5ac42aed 53380d139d95b3df

650a73548baf63de 766a0abb3c77b2a8 81c2c92e47edaee6 92722c851482353b

a2bfe8a14cf10364 a81a664bbc423001 c24b8b70d0f89791 c76c51a30654be30

d192e819d6ef5218 d69906245565a910 f40e35855771202a 106aa07032bbd1b8

19a4c116b8d2d0c8 1e376c085141ab53 2748774cdf8eeb99 34b0bcb5e19b48a8

391c0cb3c5c95a63 4ed8aa4ae3418acb 5b9cca4f7763e373 682e6ff3d6b2b8a3

748f82ee5defb2fc 78a5636f43172f60 84c87814a1f0ab72 8cc702081a6439ec

90befffa23631e28 a4506cebde82bde9 bef9a3f7b2c67915 c67178f2e372532b

ca273eceea26619c d186b8c721c0c207 eada7dd6cde0eb1e f57d4f7fee6ed178

06f067aa72176fba 0a637dc5a2c898a6 113f9804bef90dae 1b710b35131c471b

28db77f523047d84 32caab7b40c72493 3c9ebe0a15c9bebc 431d67c49c100d4c

4cc5d4becb3e42b6 597f299cfc657e2a 5fcb6fab3ad6faec 6c44198c4a475817

4、计算过程

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

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

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

与前面类似,对于SHA-384,初始化散列值有下述8个64为的16进制数组成。这些数由第9到16个质数平方根的小数部分的前64位得到。

H(0)0 = cbbb9d5dc1059ed8

H(0)1 = 629a292a367cd507

H(0)2 = 9159015a3070dd17

H(0)3 = 152fecd8f70e5939

H(0)4 = 67332667ffc00b31

H(0)5 = 8eb44a8768581511

H(0)6 = db0c2e0d64f98fa7

H(0)7 = 47b5481dbefa4fa4

对于SHA-384,初始化散列值有下述8个64为的16进制数组成。这些数由前8个质数平方根的小数部分的前64位得到。

H(0)0 = 6a09e667f3bcc908

H(0)1 = bb67ae8584caa73b

H(0)2 = 3c6ef372fe94f82b

H(0)3 = a54ff53a5f1d36f1

H(0)4 = 510e527fade682d1

H(0)5 = 9b05688c2b3e6c1f

H(0)6 = 1f83d9abfb41bd6b

H(0)7 = 5be0cd19137e2179

SHA-384和SHA-512对消息分组执行相同的处理,只在初始化H(0)和如何生成最终输出的过程中有所不同。SHA-384和SHA-5126可以用来散列处理长度为L位的消息,其中0 < L< = 2128。算法使用一个80个64位字的消息列表, 8个工作变量64位以及8个64位字的散列值。

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

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

a、准备消息列表

For t = 0 to 15

Wt = M(i)t

For t = 16 to 79

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 79

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-12来说,,是所有H(N)0、H(N)1到H(N)7的串联。对于SHA-384,则是H(N)0、H(N)1直到H(N)5的串联。

5、代码实现

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

 1 /** 定义SHA-512哈希操作的内容信息结构体 */
 2 typedef struct SHA512Context {
 3 #ifdef USE_32BIT_ONLY
 4 
 5   uint32_t Intermediate_Hash[SHA512HashSize/4]; /* 信息摘要 */
 6   uint32_t Length[4];                           /* 按位计算的信息摘要的长度 */
 7 
 8 #else /* !USE_32BIT_ONLY */
 9 
10   uint64_t Intermediate_Hash[SHA512HashSize/8]; /* 信息摘要 */
11   uint64_t Length_High;                         /* 按位计算的信息摘要的长度 */
12   uint64_t Length_Low;                          /* 按位计算的信息摘要的长度 */
13 
14 #endif /* USE_32BIT_ONLY */
15 
16   int_least16_t Message_Block_Index;            /* 信息分组数组的索引 */
17   uint8_t Message_Block[SHA512_Message_Block_Size];/* 1024位信息分组 */
18   int Computed;                                 /* 摘要计算标识*/
19   int Corrupted;                                /* 信息摘要损坏标识 */
20 } SHA512Context;

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

 1 #ifdef USE_32BIT_ONLY
 2 static SHAStatusCode SHA384_512Reset(SHA512Context *context,uint32_t H0[SHA512HashSize/4])
 3 #else /* !USE_32BIT_ONLY */
 4 static SHAStatusCode SHA384_512Reset(SHA512Context *context,uint64_t H0[SHA512HashSize/8])
 5 #endif /* USE_32BIT_ONLY */
 6 {
 7   int i;
 8 
 9   if (!context) return shaNull;
10 
11   context->Message_Block_Index = 0;
12 
13 #ifdef USE_32BIT_ONLY
14 
15   context->Length[0] = context->Length[1] =
16   context->Length[2] = context->Length[3] = 0;
17   for (i = 0; i < SHA512HashSize/4; i++)
18     context->Intermediate_Hash[i] = H0[i];
19 
20 #else /* !USE_32BIT_ONLY */
21 
22   context->Length_High = context->Length_Low = 0;
23   for (i = 0; i < SHA512HashSize/8; i++)
24     context->Intermediate_Hash[i] = H0[i];
25 
26 #endif /* USE_32BIT_ONLY */
27 
28   context->Computed = 0;
29   context->Corrupted = shaSuccess;
30 
31   return shaSuccess;
32 }

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

 1 SHAStatusCode SHA512Input(SHA512Context *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 
 9   while (length--)
10   {
11     context->Message_Block[context->Message_Block_Index++] =*message_array;
12 
13     if ((SHA384_512AddLength(context, 8) == shaSuccess) &&
14     (context->Message_Block_Index == SHA512_Message_Block_Size))
15       SHA384_512ProcessMessageBlock(context);
16     message_array++;
17   }
18   return context->Corrupted;
19 }

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

 1 static SHAStatusCode SHA384_512ResultN(SHA512Context *context,uint8_t Message_Digest[ ], int HashSize)
 2 {
 3   int i;
 4 
 5 #ifdef USE_32BIT_ONLY
 6   int i2;
 7 #endif /* USE_32BIT_ONLY */
 8 
 9   if (!context) return shaNull;
10   if (!Message_Digest) return shaNull;
11   if (context->Corrupted) return context->Corrupted;
12   if (!context->Computed)
13 
14   SHA384_512Finalize(context, 0x80);
15 
16 #ifdef USE_32BIT_ONLY
17   for (i = i2 = 0; i < HashSize; ) {
18     Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>24);
19     Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>16);
20     Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>8);
21     Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2++]);
22     Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>24);
23     Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>16);
24     Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>8);
25     Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2++]);
26   }
27 
28 #else /* !USE_32BIT_ONLY */
29   for (i = 0; i < HashSize; ++i)
30     Message_Digest[i] = (uint8_t)(context->Intermediate_Hash[i>>3] >> 8 * ( 7 - ( i % 8 ) ));
31 #endif /* USE_32BIT_ONLY */
32 
33   return shaSuccess;
34 }

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

6、结论

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

 

同样,我们也采用其他工具生成同一信息输入(“abcd”)的SHA-512信息摘要如下:

 

我们对比上述两项的输出结果,很显然是完全一致的,这说明我们的SHA-512的编码实现是正确的。

欢迎关注:

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

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

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

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

Python 请求 - HTTPDigest:在摘要授权中将哈希算法设置为 SHA-512

】Python请求-HTTPDigest:在摘要授权中将哈希算法设置为SHA-512【英文标题】:Pythonrequests-HTTPDigest:SettingthehashalgorithmtoSHA-512inDigestauthorization【发布时间】:2020-04-0411:38:06【问题描述】:我正在尝试编写一个小的Python函数来连接到一... 查看详情

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

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

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

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

摘要算法

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

sha1、sha2安全hash算法

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

什么是安全散列算法sha256

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

软件应用开发技术之四:md5算法解析及实现

MD5即Message-DigestAlgorithm5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。1、MD5算法简介MD5在90年代初由MIT的计算机科学实验室和R... 查看详情

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

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

python中hashlib模块的使用

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

md5算法原理及实现

...息MD5值的过程如下:在计算消息的MD5值之前,首先对原始信息进行填充,这里的信息填充分为两步。第一步,对原始信息进行填充,填充之后,要求信息的长度对512取余等于448。填充的规则如下:假设原始信息长度为bbit,那么... 查看详情

信息摘要算法之七:sha在区块链中的应用

最近几年比特币的火爆带动了人们对区块链技术的研究。当然我们在这里并不讨论区块链技术本身,而是讨论一下区块链中的SHA算法的应用。对于SHA系列算法我们已经在前面作了说明,在这里也不再重复。1、区块链中的SHA区块... 查看详情

1.crypto加密算法

...长度的输出,该输出就是散列值。常用的哈希算法有:MD5信息摘要算法(MD5Message-DigestAlgorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值,用于确保信息传输完整一致。SHA(SecureHashAlgorithm),即... 查看详情

sha1算法原理

...始报文长度不能超过2的64次方,然后SHA1生成160位的报文摘要。SHA1算法简单而且紧凑,容易在计算机上实现。表8-2-1列出了对MD5及SHA1的比较差异之处。让我们根据各项特性,简要说明其间的不同。表8-2-1 MD5与SHA1 查看详情

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

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

hmac加密的消息摘要码

HMAC(HashMessageAuthenticationCode)哈希消息授权码,它在消息摘要算法(例如MD5,SHA系列算法)的基础上,使用密钥对消息摘要进行加密.它相当于一个马甲,内里可以使用MD5,SHA1,SHA256,SHA384,SHA512等MessageDigest算法,在生成的消息摘要的基础上再多... 查看详情

java基础加密之sha加密

...密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。SHA-1,SHA-224,SHA-256,SHA-384,和SHA-512这几种单向散列算法。... 查看详情