《算法图解》读书笔记

《算法图解》11.7读书笔记

2023-04-04  本文已影响0人  小邱同学_

        SHA是美国的 NIST 和 NSA 设计的一种标准的 Hash 算法,SHA 用于数字签名的标准算法的 DSS 中,也是安全性很高的一种 Hash 算法。

        SHA-1 是第一代 SHA 算法标准,后来的 SHA-224、SHA-256、SHA-384 和 SHA-512 被统称为 SHA-2


一、SHA-1 算法

SHA-1 算法的输入消息长度小于 264bit,最终输出的结果值是 160 Bits,SHA-1 与 MD4 相比较而言,主要增加了扩展变换,将前一轮的输出也加到了下一轮,这样增加了雪崩效应,而且由于其 160 Bits 的输出,对穷举攻击更具有抵抗性。

1、将消息摘要转换成位字符串

因为在 SHA-1 算法中,它的输入必须为位,所以我们首先要将其转化为位字符串,我们以“abc”字符串来说明问题,因为 'a'=97, 'b'=98, 'c'=99,所以将其转换为位串后为:

01100001 01100010 01100011

2、对转换后的位字符串进行补位操作

SHA-1 算法标准规定,必须对消息摘要进行补位操作,即将输入的数据进行填充,使得数据长度对 512 求余的结果为 448,填充比特位的最高位补一个 1,其余的位补 0,如果在补位之前已经满足对 512 取模余数为 448,也要进行补位,在其后补一位 1 即可。总之,补位是至少补一位,最多补 512 位,

我们依然以“abc”为例,其补位过程如下:

初始的信息摘要:01100001 01100010 01100011

第一步补位操作:01100001 01100010 01100011 1

..... ......

最后的补位操作:01100001 01100010 01100011 10.......0 (后面补了 423 个 0)

而后我们将补位操作后的信息摘要转换为十六进制,如下所示:

61626380 00000000 00000000 00000000

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000000

00000000 00000000

3、附加长度值

在信息摘要后面附加 64 Bits 的信息,用来表示原始信息摘要的长度,在这步操作之后,信息报文便是 512 Bits 的倍数。通常来说用一个 64 位的数据表示原始消息的长度,如果消息长度不大于 264,那么前 32 位就为0,在进行附加长度值操作后,其“abc”数据报文即变成如下形式:

61626380 00000000 00000000 00000000

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000018

因为“abc”占 3 个字节,即 24 位 ,换算为十六进制即为 0x18。

4、初始化缓存

一个 160 位 MD 缓冲区用以保存中间和最终散列函数的结果。它可以表示为 5 个 32 位的寄存器(H0, H1, H2, H3, H4),初始化为:

H0 = 0x67452301

H1 = 0xEFCDAB89

H2 = 0x98BADCFE

H3 = 0x10325476

H4 = 0xC3D2E1F0

如果大家对 MD5 不陌生的话,会发现一个重要的现象,其前四个与 MD5 一样,但不同之处为存储为 big-endien format。

5、计算消息摘要

在计算报文之前我们还要做一些基本的工作,就是在我们计算过程中要用到的方法或定义。

1)、循环左移操作符 Sn(x),x 是一个字,也就是 32 Bits 大小的变量,n 是一个整数且 0<=n<=32。

Sn(X) = (X<<n) OR (X>>32-n)

2)、在程序中所要用到的常量,这一系列常量字 k(0)、k(1)、...k(79),将其以十六进制表示如下:

Kt = 0x5A827999  (0 <= t <= 19)

Kt = 0x6ED9EBA1 (20 <= t <= 39)

Kt = 0x8F1BBCDC (40 <= t <= 59)

Kt = 0xCA62C1D6 (60 <= t <= 79)

3)、所要用到的一系列函数

Ft(b,c,d)  ((b&c)|((~b)&d))      (0 <= t <= 19)

Ft(b,c,d) (b^c^d)                    (20 <= t <= 39)

Ft(b,c,d) ((b&c)|(b&d)|(c&d))  (40 <= t <= 59)

Ft(b,c,d) (b^c^d)                    (60 <= t <= 79)

4)、计算需要一个缓冲区,由 5 个 32 位的字组成,还需要一个 80 个 32 位字的缓冲区。第一个 5 个字的缓冲区被标识为 A,B,C,D,E。80 个字的缓冲区被标识为 W0, W1,..., W79。另外还需要一个一个字的 TEMP 缓冲区。

为了产生消息摘要,在第 4 部分中定义的 16 个字的数据块 M1, M2,..., Mn 会依次进行处理,处理每个数据块 Mi 包含 80 个步骤。

现在开始处理 M1, M2, ... , Mn。为了处理 Mi,需要进行下面的步骤:

(1). 将 Mi 分成 16 个字 W0, W1, ... , W15,  W0 是最左边的字

(2). 对于 t = 16 到 79,令 Wt = S1(Wt-3 XOR Wt-8 XOR Wt-14 XOR Wt-16)

(3). 令 A = H0,B = H1,C = H2,D = H3,E = H4

(4). 对于 t = 0 到 79,执行下面的循环

TEMP = S5(A) + ft(B,C,D) + E + Wt + Kt

E = D

D = C

C = S30(B)

B = A

A = TEMP

(5). 进行累加赋值:

H0 = H0 + A

H1 = H1 + B

H2 = H2 + C

H3 = H3 + D

H4 = H4 + E

在处理完所有的 Mn 后,消息摘要是一个160 位的字符串,以下面的顺序标识:

H0 H1 H2 H3 H4

对于SHA-256、SHA-384、SHA-512,也可以用相似的办法来计算消息摘要。对消息进行补位的算法完全是一样的。


二、SHA-256 算法

SHA-256 算法输入报文的最大长度不超过 264 Bits,输入按 512 Bits 分组进行处理,产生的输出是一个 256 Bits 的报文摘要。该算法处理包括以下几步:

1. 附加填充位

对报文进行填充使报文长度与 448 模 512 同余(长度 = 448 mod 512),  填充的比特数范围是 1 到 512,填充比特串的最高位为 1,其余位为 0。 就是先在报文后面加一个 1,再加很多个 0,直到长度满足 mod 512=448。为什么是 448?因为 448+64=512。第二步会加上一个 64 位的原始报文的长度信息。

2. 附加长度值

将用 64 位表示的初始报文(填充前)的位长度附加在步骤 1 的结果后(低位字节优先)。

3. 初始化缓存

使用一个 256 位的缓存来存放该散列函数的中间及最终结果。它可以表示为 8 个 32 位的寄存器(A, B, C, D, E, F, G, H),初始化为:

A=0x6A09E667

B=0xBB67AE85

C=0x3C6EF372

D=0xA54FF53A

E=0x510E527F

F=0x9B05688C

G=0x1F83D9AB

H=0x5BE0CD19

4. 处理 512 位报文分组序列

该算法使用了六种基本逻辑函数,由 64 步迭代运算组成。每步都以 256 位缓存值 ABCDEFGH 为输入,然后更新缓存内容。每步使用一个 32 位常数值 Kt 和一个 32 位 Wt。 其中相关常量如下:

一系列的常量字 K(0),K(1), ... , K(79),如果以 16 进制给出,它们取值如下:

Kt = 0x5A827999      (0<= t <= 19)

Kt = 0x6ED9EBA1    (20<= t <= 39)

Kt = 0x8F1BBCDC  (40<= t <= 59)

Kt = 0xCA62C1D6    (60<= t <= 79)

六种基本函数如下:

参与运算的都是 32 位的数,Wt 是分组之后的报文,512bit=32bit*16。也就是 Wt t=1,2..16 由该组报文产生。 Wt t=17,18,..,64 由前面的 Wt 按递推公式计算出来。

Wt递推公式为:

Kt t=1,2..64 是已知的常数。

上面的计算就是不断更新 a,b,c…h 这 32bit*8 。在每个 512 位的分组里面迭代计算 64 次。

5. 结果输出

所有的 512 位分组处理完毕后,对于 SHA-256 算法最后一个分组产生的输出便是 256 位的报文摘要。

sha0 sha1

# -*- coding: utf-8 -*-

# @Author  : Codeooo

# @Time    : 2022/9/27

import hashlib

data = "Codeooo"  # 要进行加密的数据

data_sha = hashlib.sha1(data.encode('utf-8')).hexdigest()

print(data_sha)

# 0xffffffff is used to make sure numbers dont go over 32

def chunks(messageLength, chunkSize):

    chunkValues = []

    for i in range(0, len(messageLength), chunkSize):   

chunkValues.append(messageLength[i:i + chunkSize])

  return chunkValues

def leftRotate(chunk, rotateLength):

    return ((chunk << rotateLength) | (chunk >> (32 - rotateLength))) & 0xffffffff

def sha1Function(message):

    # initial hash values

    h0 = 0x67452301

    h1 = 0xEFCDAB89

    h2 = 0x98BADCFE

    h3 = 0x10325476

    h4 = 0xC3D2E1F0

messageLength = ""

    # preprocessing

    for char in range(len(message)):

        messageLength += '{0:08b}'.format(ord(message[char]))

    temp = messageLength

    messageLength += '1'

    while (len(messageLength) % 512 != 448):

        messageLength += '0'

    messageLength += '{0:064b}'.format(len(temp))

    chunk = chunks(messageLength, 512)

    for eachChunk in chunk:

        words = chunks(eachChunk, 32)

        w = [0] * 80

        for n in range(0, 16):

            w[n] = int(words[n], 2)

        for i in range(16, 80):

            # sha1

            w[i] = leftRotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1)

            # sha0

            # w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16])

            # Initialize hash value for this chunk:

        a = h0

        b = h1

        c = h2

        d = h3

        e = h4

        # main loop:

        for i in range(0, 80):

            if 0 <= i <= 19:

                f = (b & c) | ((~b) & d)

                k = 0x5A827999

            elif 20 <= i <= 39:

                f = b ^ c ^ d

                k = 0x6ED9EBA1

            elif 40 <= i <= 59:

                f = (b & c) | (b & d) | (c & d)

                k = 0x8F1BBCDC

            elif 60 <= i <= 79:

                f = b ^ c ^ d

                k = 0xCA62C1D6

            a, b, c, d, e = ((leftRotate(a, 5) + f + e + k + w[i]) & 0xffffffff, a, leftRotate(b, 30), c, d)

        h0 = h0 + a & 0xffffffff

        h1 = h1 + b & 0xffffffff

        h2 = h2 + c & 0xffffffff

        h3 = h3 + d & 0xffffffff

        h4 = h4 + e & 0xffffffff

    return '%08x%08x%08x%08x%08x' % (h0, h1, h2, h3, h4)

sha1Hash = sha1Function(data)

print(sha1Hash)

上一篇下一篇

猜你喜欢

热点阅读