SHA256算法详解及python实现
1.SHA256介紹(可略過(guò))
SHA256是SHA-2下細(xì)分出的一種算法。SHA-2(安全哈希算法2)是由美國(guó)國(guó)家安全局(NSA)設(shè)計(jì)的一組加密哈希函數(shù)。SHA-2系列由六個(gè)具有224、256、384或512位摘要(哈希值)的哈希函數(shù)組成:SHA-224,SHA-256,SHA-384,SHA-512,SHA-512 / 224,SHA -512/256。SHA-256和SHA-512是分別用32位和64位字計(jì)算的哈希函數(shù)。它們使用不同的移位量和加性常數(shù),但是它們的結(jié)構(gòu)實(shí)際上是相同的,只是輪數(shù)不同。
SHA256其實(shí)就是一個(gè)哈希函數(shù)。哈希函數(shù),又稱散列算法,是一種從任何一種數(shù)據(jù)中創(chuàng)建小的數(shù)字“指紋”的方法。散列函數(shù)把消息或數(shù)據(jù)壓縮成摘要,使得數(shù)據(jù)量變小,將數(shù)據(jù)的格式固定下來(lái)。該函數(shù)將數(shù)據(jù)打亂混合,重新創(chuàng)建一個(gè)叫做散列值(或哈希值)的指紋。散列值通常用一個(gè)短的隨機(jī)字母和數(shù)字組成的字符串來(lái)代表。
對(duì)于任意長(zhǎng)度的消息,SHA256都會(huì)產(chǎn)生一個(gè)256bit長(zhǎng)的哈希值,稱作消息摘要。這個(gè)摘要相當(dāng)于是個(gè)長(zhǎng)度為32個(gè)字節(jié)的數(shù)組,通常用一個(gè)長(zhǎng)度為64的十六進(jìn)制字符串來(lái)表示。
2. SHA算法詳解
2.1常量初始化
SHA256算法中用到了8個(gè)哈希初值以及64個(gè)哈希常量。
SHA256算法的8個(gè)哈希初值為前8個(gè)質(zhì)數(shù)(2,3,5,7,11,13,17,19)的平方根的小數(shù)部分取前32bit而來(lái),如下所示(8個(gè)哈希值為圖中的1所框出的部分,即第一次迭代的(A,B,…,H)值):
#對(duì)于2\sqrt22?≈0.414213562373095048,而0.414213562373095048≈6×16?1+a×16?2+0×16?3+9×16?4+e×16?5+6×16?6+6×16?7+7×16?86×16^{-1}+a×16^{-2}+0×16^{-3}+9×16^{-4}+e×16^{-5}+6×16^{-6}+6×16^{-7}+7×16^{-8}6×16?1+a×16?2+0×16?3+9×16?4+e×16?5+6×16?6+6×16?7+7×16?8。故質(zhì)數(shù)2的平方根的小數(shù)部分取前32bit就對(duì)應(yīng)出了0x6a09e667。
在SHA256算法中,用到的64個(gè)常量如下:
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這些常量是對(duì)自然數(shù)中前64個(gè)質(zhì)數(shù)(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…)的立方根的小數(shù)部分取前32bit而來(lái)(圖中64次迭代的Kt值)。
2.2預(yù)處理
SHA256對(duì)進(jìn)入的信息要進(jìn)行初始化,即使消息滿足指定結(jié)構(gòu)。信息處理主要是消息填充和附加長(zhǎng)度。(1.通過(guò)在消息后增加0,使消息達(dá)到指定長(zhǎng)度。2.并在最后增加消息長(zhǎng)度信息)
(1)在報(bào)文末尾進(jìn)行填充,使報(bào)文長(zhǎng)度在對(duì)512取模以后的余數(shù)是448。
填充是這樣進(jìn)行的:先補(bǔ)第一個(gè)比特為1,然后都補(bǔ)0,直到長(zhǎng)度滿足對(duì)512取模后余數(shù)是448。信息必須進(jìn)行填充,也就是說(shuō),即使長(zhǎng)度已經(jīng)滿足對(duì)512取模后余數(shù)是448,補(bǔ)位也必須要進(jìn)行,這時(shí)要填充512個(gè)比特。(即最少補(bǔ)一位,最多補(bǔ)512位)。
(2)這里余數(shù)是448的原因是填充后,會(huì)再附加上一個(gè)64bit的數(shù)據(jù),用來(lái)表示原始報(bào)文的長(zhǎng)度信息。而448+64=512,正好拼成了一個(gè)完整的結(jié)構(gòu)。附加的64bit的數(shù)據(jù),即用一個(gè)64位的數(shù)據(jù)表示原始消息的長(zhǎng)度(故消息長(zhǎng)度必須小于2^64)。長(zhǎng)度信息的編碼方式為64-bit big-endian integer(可以簡(jiǎn)單地理解成,從最高位開(kāi)始數(shù)數(shù)字長(zhǎng)度)。
2.3邏輯運(yùn)算
| ∧ | 按位“與” |
| ? | 按位“補(bǔ)” |
| ⊕ | 按位“異或” |
| Sn\ S^{n}?Sn | 循環(huán)右移n個(gè)bit |
| Rn\ R^{n}?Rn | 右移n個(gè)bit |
涉及的邏輯函數(shù):
Ch(x,y,z)=(x∧y)⊕(?x∧z)Ch(x,y,z)=(x∧y)⊕(?x∧z)Ch(x,y,z)=(x∧y)⊕(?x∧z)
Ma(x,y,z)=(x∧y)⊕(x∧z)⊕(y∧z)Ma(x,y,z)=(x∧y)⊕(x∧z)⊕(y∧z)Ma(x,y,z)=(x∧y)⊕(x∧z)⊕(y∧z)
Σ0(x)=S2(x)⊕S13(x)⊕S22(x)Σ0(x)=S^2 (x)⊕S^13 (x)⊕S^22 (x)Σ0(x)=S2(x)⊕S13(x)⊕S22(x)
Σ1(x)=S6(x)⊕S11(x)⊕S25(x)Σ1(x)=S^6 (x)⊕S^11 (x)⊕S^25 (x)Σ1(x)=S6(x)⊕S11(x)⊕S25(x)
σ0(x)=S7(x)⊕S18(x)⊕S3(x)σ0(x)=S^7 (x)⊕S^18 (x)⊕S^3 (x)σ0(x)=S7(x)⊕S18(x)⊕S3(x)
σ1(x)=S17(x)⊕S19(x)⊕S10(x)σ1(x)=S^17 (x)⊕S^19 (x)⊕S^10 (x)σ1(x)=S17(x)⊕S19(x)⊕S10(x)
田(x,y)=(x+y)mod232田(x,y)=(x+y)mod 2^{32}田(x,y)=(x+y)mod232
2.4計(jì)算消息摘要
(1)將消息分解成512bit的若干塊。此處若是消息被分成n塊,則整個(gè)代碼就要完成n個(gè)64迭代(圖中的一次運(yùn)算為1個(gè)迭代,每個(gè)塊要經(jīng)過(guò)64次迭代)。
(2)構(gòu)造64個(gè)字,對(duì)于消息分解成的每個(gè)512bit的塊,需要構(gòu)成64個(gè)字(每個(gè)字節(jié)是8位二進(jìn)制,每個(gè)字有4個(gè)字節(jié),故每個(gè)字有32bit)。前16個(gè)字直接由原消息組成,記為W[0] 、…W[15]。對(duì)于其余字則有迭代公式計(jì)算而得:
Wt=σ1(Wt?2)+Wt?7+σ0(W(t?15))+Wt?16W_t=σ1(W_{t-2} )+W_{t-7}+σ0(W_(t-15) )+W_{t-16}Wt?=σ1(Wt?2?)+Wt?7?+σ0(W(?t?15))+Wt?16?
(3)進(jìn)行64次加密循環(huán)。
第一次迭代時(shí),A、B、…H是8個(gè)哈希初始值(見(jiàn)2.1)。
在(a)處:(a)=田(Wt,Kt)\ 田(W_t,K_t )?田(Wt?,Kt?)。(Wt\ W_t?Wt?為2.4(2)中構(gòu)造的字,Kt\ K_t?Kt?為2.1中的哈希常量)。
在(b)處:(b)= 田(Ch(E,F,G), H, (a))。
在(c)處:(c)= 田(Σ1(E), (b))。
在(d)處:(d)= 田(D,(c))。
在(e)處:(e)= 田(Ma(A,B,C),(c))。
在(f)處:(f)= 田(Σ0(A),(e))。
一次循環(huán)可計(jì)算得:Bi=A,Ci=B,Di=C,Ei=(d),Fi=E,Gi=F,Hi=G,Ai=(f)。
經(jīng)過(guò)64次迭代,可以得到第一個(gè)512塊函數(shù)的摘要。
對(duì)于下一個(gè)512bit的塊,將壓縮塊添加到當(dāng)前哈希值:h0:= h0 + Ai;h1:= h1 + Bi;h2:= h2 + Ci;h3:= h3 + Di;h4:= h4 + Ei;h5:= h5 + Fi;h6:= h6 + Gi;h7:= h7 + Hi。
(h0,…,h7初始值見(jiàn)2.1)
最后的計(jì)算的SHA256的值為:digest= h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7。(將h0,…h(huán)7連接起來(lái))
3. SHA256偽代碼
(同wiki)
Note 1: All variables are 32 bit unsigned integers and addition is calculated modulo 232 Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 ≤ i ≤ 63 Note 3: The compression function uses 8 working variables, a through h Note 4: Big-endian convention is used when expressing the constants in this pseudocode,and when parsing message block data from bytes to words, for example,the first word of the input message "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 := 0x6a09e667 h1 := 0xbb67ae85 h2 := 0x3c6ef372 h3 := 0xa54ff53a h4 := 0x510e527f h5 := 0x9b05688c h6 := 0x1f83d9ab h7 := 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 bits append a single '1' bit append K '0' bits, where K is the minimum number >= 0 such that L + 1 + K + 64 is a multiple of 512 append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bitsProcess the message in successive 512-bit chunks: break message into 512-bit chunks for each chunkcreate a 64-entry message schedule array w[0..63] of 32-bit words(The initial values in w[0..63] don't matter, so many implementations zero them here)copy chunk into first 16 words w[0..15] of the message schedule arrayExtend the first 16 words into the remaining 48 words w[16..63] of the message schedule array:for i from 16 to 63s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)s1 := (w[i- 2] rightrotate 17) xor (w[i- 2] rightrotate 19) xor (w[i- 2] rightshift 10)w[i] := w[i-16] + s0 + w[i-7] + s1Initialize working variables to current hash value:a := h0b := h1c := h2d := h3e := h4f := h5g := h6h := h7Compression function main loop:for i from 0 to 63S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)ch := (e and f) xor ((not e) and g)temp1 := h + S1 + ch + k[i] + w[i]S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)maj := (a and b) xor (a and c) xor (b and c)temp2 := S0 + majh := gg := ff := ee := d + temp1d := cc := bb := aa := temp1 + temp2Add the compressed chunk to the current hash value:h0 := h0 + ah1 := h1 + bh2 := h2 + ch3 := h3 + dh4 := h4 + eh5 := h5 + fh6 := h6 + gh7 := h7 + hProduce the final hash value (big-endian): digest := hash := h0 append h1 append h2 append h3 append h4 append h5 append h6 append h74. python實(shí)現(xiàn)代碼
github鏈接
class SHA256:def __init__(self):#64個(gè)常量#圖中Ktself.constants = (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, 0xc67178f2)#迭代初始值,h0,h1,...,h7self.h = (0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19)#x循環(huán)右移b個(gè)bit#rightrotate b bitdef rightrotate(self, x, b):return ((x >> b) | (x << (32 - b))) & ((2**32)-1)#信息預(yù)處理。附加填充和附加長(zhǎng)度值def Pad(self, W):return bytes(W, "ascii") + b"\x80" + (b"\x00" * ((55 if (len(W) % 64) < 56 else 119) - (len(W) % 64))) + ((len(W) << 3).to_bytes(8, "big"))def Compress(self, Wt, Kt, A, B, C, D, E, F, G, H):return ((H + (self.rightrotate(E, 6) ^ self.rightrotate(E, 11) ^ self.rightrotate(E, 25)) + ((E & F) ^ (~E & G)) + Wt + Kt) + (self.rightrotate(A, 2) ^ self.rightrotate(A, 13) ^ self.rightrotate(A, 22)) + ((A & B) ^ (A & C) ^ (B & C))) & ((2**32)-1), A, B, C, (D + (H + (self.rightrotate(E, 6) ^ self.rightrotate(E, 11) ^ self.rightrotate(E, 25)) + ((E & F) ^ (~E & G)) + Wt + Kt)) & ((2**32)-1), E, F, Gdef hash(self, message):message = self.Pad(message)digest = list(self.h)for i in range(0, len(message), 64):S = message[i: i + 64]W = [int.from_bytes(S[e: e + 4], "big") for e in range(0, 64, 4)] + ([0] * 48)#構(gòu)造64個(gè)wordfor j in range(16, 64):W[j] = (W[j - 16] + (self.rightrotate(W[j - 15], 7) ^ self.rightrotate(W[j - 15], 18) ^ (W[j - 15] >> 3)) + W[j - 7] + (self.rightrotate(W[j - 2], 17) ^ self.rightrotate(W[j - 2], 19) ^ (W[j - 2] >> 10))) & ((2**32)-1)A, B, C, D, E, F, G, H = digestfor j in range(64):A, B, C, D, E, F, G, H = self.Compress(W[j], self.constants[j], A, B, C, D, E, F, G, H)return "".join(format(h, "02x") for h in b"".join(d.to_bytes(4, "big") for d in [(x + y) & ((2**32)-1) for x, y in zip(digest, (A, B, C, D, E, F, G, H))]))def main():encoder = SHA256()while True:message = input("Enter string: ")print(f"Output: {encoder.hash(message)}\n")if __name__ == "__main__":main()參考文獻(xiàn)
SHA-2 wiki
總結(jié)
以上是生活随笔為你收集整理的SHA256算法详解及python实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 断言NSAssert的使用
- 下一篇: 【剑指offer】——【python中r