令人痛苦的细节中的SHA-256

2020-07-16 02:58:25

SHA-2(Secure Hash Algorithm 2,安全散列算法2)是目前最流行的散列算法之一,SHA-256是其中的一部分。在本文中,我们将尽可能简单地分析算法的每个步骤,并手动完成一个真实的示例。

SHA-2以其安全性(它没有像SHA-1那样出现故障)和速度而闻名。在不生成密钥的情况下,例如挖掘比特币,像SHA-2这样的快速散列算法通常占据主导地位。

如果您想了解更多有关散列函数的一般信息,请在此处阅读。也就是说,为了继续前进,让我们回顾一下散列函数的三个主要目的:

SHA-2是一种算法,是如何对数据进行散列的通用思想。SHA-256设置定义SHA-2算法行为的附加常量。其中一个这样的常数是输出大小。“256”和“512”指的是它们各自的输出摘要大小(以位为单位)。

用0填充数据,直到数据是512的倍数,减去64位(在我们的情况下是448位):

01101000 01100101 01100101 01101100 01101100 01101111 00100000 01110111 0110111101110010 01101100 01100100 10000000 00000000 00000000 00000000 0000000000000000 00000000 00000000 00000000 0000000000000000 00000000 00000000 00000000 0000000000000000 00000000 00000000 00000000 0000000000000000 00000000 00000000 00000000 0000000000000000 00000000 00000000 00000000 9686810114 9686810114 9686810114 L.3。

将64位追加到末尾,其中64位是以二进制表示原始输入长度的大端整数。在我们的例子中,88或二进制表示为“1011000”。

01101000 01101100 01101100 00100000 01110111 01101100 01100100 00000000 00000000 0000000000000000 00000000 00000000 00000000 0000000000000000 00000000 00000000 9686810114 9686810114 9686810114(分秒级的),分秒级的,分秒级的分秒级的

现在我们创建8个哈希值。这些是硬编码常数,表示前8个素数的平方根的小数部分的前32位:2、3、5、7、11、13、17、19。

h0:=0x6a09e667h1:=0xbb67ae85h2:=0x3c6ef372h3:=0xa54ff53ah4:=0x510e527fh5:=0x9b05688ch6:=0x1f83d9abh7:=0x5be0cd19。

与步骤2类似,我们将创建一些常量(了解有关常量的更多信息以及何时在此处使用它们)。这一次,他们有64个人。每个值(0-63)是前64个素数(2-311)的立方根的小数部分的前32位。

0x428a2f98 0x71374491 0xb5c0fbcf 0xe9b5dba5 0x3956c25b 0x59f111f1 0x923f82a4 0xab1c5ed50xd807aa98 0x12835b01 0x243185be 0x550c7dc3 0x72be5d74 0x80deb1fe 0x9bdc06a7 0xc19bf1740xe49b69c1 0xefbe4786 0x0fc19dc6 0x240ca1cc 0x2de92c6f 0x4a7484aa 0x5cb0a9dc 0x76f988da0x983e5152 0xa831c66d 0xb00327c8 0xbf597fc7 0xc6e00bf3 0xd5a79147 0x06ca6351 0x142929670x27b70a85 0x2e1b2138 0x4d2c6dfc 0x53380d13 0x650a7354 0x766a0abb 0x81c2c92e 0x92722c850xa2bfe8a1 0xa81a664b 0xc24b8b70 0xc76c51a3 0xd192e819 0xd6990624 0xf40e3585 0x106aa0700x19a4c116 0x1e376c08 0x2748774c 0x34b0bcb5 0x391c0cb3 0x4ed8aa4a 0x5b9cca4f 0x682e6ff30x748f82ee 0x78a5636f 0x84c87814 0x8cc70208 0x90befffa 0xa4506ceb 0xbef9a3f7 0xc67178f2。

对于来自我们输入的每个512位“块”数据,将执行以下步骤。在我们的例子中,因为“hello world”很短,所以我们只有一块。在循环的每次迭代中,我们将改变散列值H0-H7,这将是最终输出。

将步骤1中的输入数据复制到新数组中,其中每个条目都是一个32位字:

再添加48个初始化为零的字,这样我们就有了一个数组w[0…。63]。

对于来自w的i[16…。63]:s1=(w[i-2]右移17)xor(w[i-2]右移19)xor(w[i-2]右移10)

w[1]rightrotate 7:01101111001000000111011101101111->;11011110110111100100000011101110w[1]rightrotate 18:01101111001000000111011101101111->;00011101110110111101101111001000w[1]rightshift 3:01101111001000000111011101101111->;00001101111001000000111011101101s0=11011110110111100100000011101110 XOR 00011101110110111101101111001000 XOR 00001101111001000000111011101101s0=11001110111000011001010111001011w[14]rightrotate 17:00000000000000000000000000000000->;00000000000000000000000000000000w[14]rightrotate19:00000000000000000000000000000000->;00000000000000000000000000000000w[14]rightshift 10:00000000000000000000000000000000->;00000000000000000000000000000000s1=00000000000000000000000000000000 XOR 00000000000000000000000000000000 XOR 00000000000000000000000000000000s1=00000000000000000000000000000000w[16]=w[0]+s0+w[9]+s1w[16]=01101000011001010110110001101100+11001110111000011001010111001011+00000000000000000000000000000000+00000000000000000000000000000000//addition is calculated modulo 2^32w[16]=00110111010001110000001000110111。

01101000011001010110110001101100 0110111100100000011101110110111101110010011011000110010010000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000101100000110111010001110000001000110111 1000011011010000110000000011000111010011101111010001000100001011 0111100000111111010001111000001000101010100100000111110011101101 0100101100101111011111001100100100110001111000011001010001011101 1000100100110110010010010110010001111111011110100000011011011010 1100000101111001101010010011101010111011111010001111011001010101 0000110000011010111000111110011010110000111111100000110101111101 0101111101101110010101011001001100000000100010011001101101010010 0000011111110001110010101001010000111011010111111110010111010110 0110100001100101011000101110011011001000010011100000101010011110 0000011010101111100110110010010110010010111011110110010011010111 0110001111111001010111100101101011100011000101100110011111010111 1000010000111011110111100001011011101110111011001010100001011011 1010000001001111111100100010000111111001000110001010110110111000 0001010010101000100100100001100100010000100001000101001100011101 0110000010010011111000001100110110000011000000110101111111101001 1101010110101110011110010011100000111001001111110000010110101101 1111101101001011000110111110111111101011011101011111111100101001 0110101000110110100101010011010000100010111111001001110011011000 1010100101110100000011010010101101100000110011110011100010000101 1100010010101100100110000011101000010001010000101111110110101101 1011000010110000000111011101100110011000111100001100001101101111 011100100001011110100000011110 1010001011010001100111100110011010 0000000100001111100110010111101111111100000101110100111100001010 1100001011000010111010101100010110。

初始化变量a、b、c、d、e、f、g、h,并将它们分别设置为等于当前散列值。h0、h1、h2、h3、h4、h5、h6、h7。

运行压缩循环。压缩循环将改变…的值。h.压缩循环如下:

a=0x6a09e667=01101010000010011110011001100111b=0xbb67ae85=10111011011001111010111010000101c=0x3c6ef372=00111100011011101111001101110010d=0xa54ff53a=10100101010011111111010100111010e=0x510e527f=01010001000011100101001001111111f=0x9b05688c=10011011000001010110100010001100g=0x1f83d9ab=00011111100000111101100110101011h=0x5be0cd19=01011011111000001100110100011001e rightrotate 6:01010001000011100101001001111111->;11111101010001000011100101001001e rightrotate 11:01010001000011100101001001111111->;01001111111010100010000111001010e rightrotate 25:01010001000011100101001001111111->;10000111001010010011111110101000S1=11111101010001000011100101001001 XOR 01001111111010100010000111001010 XOR 10000111001010010011111110101000S1=00110101100001110010011100101011e and f:01010001000011100101001001111111&;10011011000001010110100010001100=00010001000001000100000000001100not e:01010001000011100101001001111111->;10101110111100011010110110000000(not e)and g:10101110111100011010110110000000&;00011111100000111101100110101011=0000111010100000011000100110000000ch=(e和f)xor((非e)和g)=000100010001000100000000001100 xor 00001110100000011000100110000000=00011111100001011100100110001100//k[i]是舍入常数//w[i]是批量temp1=h+s1+ch+k

h0=h0+a=1011100101001101001001111011111001h1=h1+b=10010011010011111000001000h2=h2+c=10100101001011100101010101h3=h3+d=1101101001111111011010101111111010h4=h4+e=11000100100001001111111111100011h5=h5+f=0。

摘要=h0追加h1追加h2追加h3追加h4追加h5追加h6追加h7=B94D27B9934D3E08A52E52D7DA7DABFAC484EFE37A5380EE9088F7ACE2EFCDE9。

搞定了!我们已经详细地检查了SHA-256中的每一步(没有一些迭代),非常详细的🙂。

如果您想以伪代码的形式查看我们刚才所做的所有步骤,那么这里就是直接来自维基百科的内容:

注1:所有变量均为32位无符号整数,加法以232为模计算。注2:每轮有一个循环常数k[i]和消息调度数组w[i]中的一个条目,0≤i≤63注3:压缩函数使用8个工作变量,a到h注4:在此伪码中表示常量时使用大端约定,当从字节到字解析消息块数据时,例如,输入消息的第一个字";abc"。after padding is 0x61626380Initialize hash values:(first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):h0:=0x6a09e667h1:=0xbb67ae85h2:=0x3c6ef372h3:=0xa54ff53ah4:=0x510e527fh5:=0x9b05688ch6:=0x1f83d9abh7:=0x5be0cd19Initialize array of round constants:(first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):k[0..63]:=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,0xc67178f2Pre-processing(Padding):begin with the original message of length L bitsappend a single';1';bit append K';0';bitappend K';0';bit append K';0';bit;其中K是最小数字&>=0,使得L+1+K+64是512的倍数。将L追加为64位大端整数,使后处理总长度成为512位的倍数。不要紧,如此多的实现在这里将它们清零)将块复制到消息调度数组的前16个字w[0..15]中将前16个字扩展到消息调度数组的剩余48个字w[16..63]:for i from 16到63 s0:=(w[i-15]right trotate 7)xor(w[i-15]right trotate 18)xor(w[i-15]RightShift 3)s1:=(w[i-2]right trotate 17)xor(。]RightShift 10)w[i]:=w[i-16]+s0+w[i-7]+s1将工作变量初始化为当前哈希值:a:=h0 b:=h1 c:=h2 d:=h3 e:=h4 f:=h5 g:=h6 h:=h7压缩函数主循环:对于i从0到63 s1:=(E Right Trotate 6)xor(E Right Trotate 11)xor(e right trotate。+s1+ch+k[i]+w[i]s0:=(a右旋2)xor(a右旋13)xor(a右旋22)maj:=(a和b)xor(a和c)xor(b和c)temp2:=s0+maj h:=g:=f:=e:=d+temp1 d:=c:=b:=a:=temp1+temp1。=h2+c h3:=h3+d h4:=h4+e h5:=h5+f h6:=h6+g h7:=h7+h生成最终哈希值(大端):digest:=hash:=h0追加h1追加h2追加h3追加h4追加h5追加h6追加h7