【密码学】一文读懂SHA-1

简介: SHA-1(Secure Hash Algorithm 1)是一种密码散列函数,美国国家安全局设计,并由美国国家标准技术研究所(NIST)发布为联邦资料处理标准(FIPS)。SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。

一文读懂SHA-1


VKM%_NK{%_GBIRT$VYGJ841.jpg一文读懂SHA-1


SHA-1简介

SHA-1(Secure Hash Algorithm 1)是一种密码散列函数,美国国家安全局设计,并由美国国家标准技术研究所(NIST)发布为联邦资料处理标准(FIPS)。SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。【维基百科】


SHA-1实现步骤

消息填充(Message Padding)

这个消息填充方案和MD5类似(注意这里有些不同, 我最开始实现的时候没太注意, 直接复制了之前写MD5的算法, 导致结果不一样),按照如下的步骤进行填充。

步骤一: 数据填充(Append Padding Bits)

SHA-1是按照分块进行处理的,分块长度为512bit, 大多数情况下,数据的长度不会恰好满足是512的整数倍,因此需要进行「padding」到给定的长度。

「填充规则」: 原始明文消息的b位之后补100..., 直到满足b + paddingLength % 512 = 448, 那如果b % 512[448, 512(0)]之间呢,则在增加一个分块,按照前面的规则填充即可。

步骤二: 长度填充

之前说了,需要满足b + paddingLength % 512 = 448, 那么对于最后一个分块,就还剩512 - 448 = 64 bit 这剩下的64bit存放的是原始消息的长度,也就是b「SHA-1」最多可以处理明文长度小于等于2^64 bit的数据。

经过上面两个步骤的处理,最终得到的处理后的数据如下图所示:

4PMZ`W$T1RN%@1KD~~{X)PB.png

image.gifSHA-1-Padding

注: 这里我没有完全按照RFC当中的Message Padding来描述,我合并了RFC当中的a, b

计算摘要(Computing the Message Digest)

`UH@}J{@EAYRM)146PWWJ@T.png计算摘要

首先, 初始化5个常量, 如下所示, 类比于「MD5」可以看做是「MDBuffer」:

H0 = 0x67452301
H1 = 0xEFCDAB89
H2 = 0x98BADCFE
H3 = 0x10325476
H4 = 0xC3D2E1F0

然后对于消息按照如下的方式进行处理:

  • 前16个字节([0, 15]),转换成32位无符号整数。
  • 对于后面的字节([16, 79])按照下面的公式进行处理
W(t) = S^1(W(t-3) XOR W(t-8) XOR W(t-14) XOR W(t-16))
  • A = H0, B = H1, C = H2, D = H3, E = H4
  • 做如下80轮的散列操作
TEMP = S^5(A) + f(t;B,C,D) + E + W(t) + K(t);
E = D;
D = C;
C = S^30(B);
B = A;
A = TEMP;
  • H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E

解释一下,其中f函数如下:

f(t;B,C,D) = (B AND C) OR ((NOT B) AND D)         ( 0 <= t <= 19)
f(t;B,C,D) = B XOR C XOR D                        (20 <= t <= 39)
f(t;B,C,D) = (B AND C) OR (B AND D) OR (C AND D)  (40 <= t <= 59)
f(t;B,C,D) = B XOR C XOR D                        (60 <= t <= 79)

k函数如下:

K(t) = 0x5A827999         ( 0 <= t <= 19)
K(t) = 0x6ED9EBA1         (20 <= t <= 39)
K(t) = 0x8F1BBCDC         (40 <= t <= 59)
K(t) = 0xCA62C1D6         (60 <= t <= 79)

输出

最后H0~H4即为最终「SHA-1」的输出结果。


代码实现

pub struct SHA1 {}
impl SHA1 {
    fn padding(message: &[u8]) -> Vec<u8> {
        let mut result = message.to_owned();
        // padding 1
        result.push(0x80);
        // padding 0
        while ((result.len() * 8) + 64) % 512 != 0 {
            result.push(0b00000000);
        }
        // padding message length 注意这里和MD5不同,没仔细看踩了一个大坑 这里长度padding到前面
        for byte in &((message.len() * 8) as u64).to_be_bytes() {
            result.push(*byte);
        }
        return result;
    }
    fn k(t: usize) -> u32 {
        match t {
            n if n < 20 => 0x5A827999,
            n if 20 <= n && n < 40 => 0x6ED9EBA1,
            n if 40 <= n && n < 60 => 0x8F1BBCDC,
            n if 60 <= n && n < 80 => 0xCA62C1D6,
            _ => 0,
        }
    }
    fn f(t: usize, b: u32, c: u32, d: u32) -> u32 {
        match t {
            n if n < 20 => (b & c) | ((!b) & d),
            n if 20 <= n && n < 40 => b ^ c ^ d,
            n if 40 <= n && n < 60 => (b & c) | (b & d) | (c & d),
            n if 60 <= n && n < 80 => b ^ c ^ d,
            _ => 0,
        }
    }
    pub fn hash(message: &[u8]) -> String {
        let padding_message = SHA1::padding(message);
        let mut buf: [u32; 5]; // Buffer one, A..E
        let mut h: [u32; 5] = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
        let mut w = [0u32; 80]; // Sequance of W(0)..W(79)
        let mut temp: u32;
        for chunk in padding_message.chunks(64) {
            // 注意这里用的是big-edition
            let m: Vec<u32> = chunk.chunks(4).map(|i| {
                ((i[0] as u32) << 24) | ((i[1] as u32) << 16) | ((i[2] as u32) << 8) | ((i[3] as u32) << 0)
            }).collect();
            for i in 0..16 {
                w[i] = m[i];
            }
            for t in 16..80 {
                // W(t) = S^1(W(t-3) XOR W(t-8) XOR W(t-14) XOR W(t-16)).
                w[t] = (w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]).rotate_left(1);
            }
            buf = h;
            for t in 0..80 {
                // TEMP = S^5(A) + f(t;B,C,D) + E + W(t) + K(t);
                temp = buf[0].rotate_left(5).wrapping_add(
                    SHA1::f(t, buf[1], buf[2], buf[3])
                        .wrapping_add(buf[4].wrapping_add(w[t].wrapping_add(SHA1::k(t)))),
                );
                buf[4] = buf[3]; // E = D
                buf[3] = buf[2]; // D = C
                buf[2] = buf[1].rotate_left(30); // C = S^30(B)
                buf[1] = buf[0]; // B = A
                buf[0] = temp; // A = TEMP
            }
            for i in 0..5 {
                h[i] = h[i].wrapping_add(buf[i]);
            }
        }
        // output
        return String::from(format!(
            "{:08x}{:08x}{:08x}{:08x}{:08x}",
            h[0], h[1], h[2], h[3], h[4]
        ));
    }
}
#[cfg(test)]
mod test {
    use crate::sha1::SHA1;
    #[test]
    fn test() {
        println!("sha1([empty string]) = {}", SHA1::hash("".as_bytes()));
        println!("sha1([The quick brown fox jumps over the lazy dog]) = {}", SHA1::hash("The quick brown fox jumps over the lazy dog".as_bytes()));
    }
}


番外


计算sign(LittleQ)的值,依然没有反调试, 欢迎尝试还原算法。

链接: https://pan.baidu.com/s/1Gtdszf76q_ZYBK3j14LECw 提取码: 9vmb

相关文章
|
Rust 算法 安全
【密码学】一文读懂HMAC
本文将来聊一聊基于哈希函数的消息认证码,在此之前,先来科普一下什么是 「消息认证码」 (MAC), 先来看一个简单的栗子
1541 0
【密码学】一文读懂HMAC
|
Rust 算法 数据安全/隐私保护
【密码学】一文读懂XTEA加密
本篇文章,我们来看一下上一次讲过的TEA加密算法的一个升级版XTEA, 相比于TEA, XTEA的安全性显然是更高的,其中的过程要比TEA稍微复杂一点点。
1217 0
【密码学】一文读懂XTEA加密
|
Rust 算法 Go
【密码学】一文读懂MurMurHash3
本文应该是MurMurHash算法介绍的最后一篇,来一起看一下最新的MurMurHash算法的具体过程,对于最新的算法来说,整个流程和之前的其实也比较相似,这里从维基百科当中找到了伪代码,也就不贴出来Google官方给出的推荐代码了,先来看一下维基百科给出的伪代码,这里只有32位的伪代码。
1970 0
【密码学】一文读懂MurMurHash3
|
Rust 算法 安全
【密码学】一文读懂MurMurHash2
上次我们聊过了一代的MurMurHash算法,是的,我又来水文章了,今天呢,接着来聊一下二代的MurMurHash算法,二代算法的整体结构实际上和一代算法差不太多,只是对于每一轮数据的处理过程当中的运算有一些差异,算法的来源依然是来自于Google官网给提供的源码,对着源码看的结构,对于这个算法呢,有两个版本,一个是32位的,一个是64位的,对于32位的算法和64位的算法,区别在于两个初始的魔数不同,整体运算过程还是十分相似的。
2085 0
【密码学】一文读懂MurMurHash2
|
3月前
|
安全 算法 Java
密码学基础知识与加密算法解析
密码学基础知识与加密算法解析
|
Rust 算法 数据安全/隐私保护
【密码学】一文读懂RSA的随机数生成器
本文接着来聊一个比较轻松的内容,再来说一个随机数生成器,对于这个随机数生成器呢,这里和之前讲到过的BBS有一些类似,直接来看具体的内容蛤。
1076 1
【密码学】一文读懂RSA的随机数生成器
|
算法 Serverless 数据安全/隐私保护
【密码学】一文读懂SHA-2
SHA-2安全散列算法2(Secure Hash Algorithm 2)一种密码散列函数算法标准,由美国国家安全局研发,由美国国家标准与技术研究院(NIST)在2001年发布。属于SHA算法之一,是SHA-1的后继者。其下又可再分为六个不同的算法标准,包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。
【密码学】一文读懂SHA-2
|
Rust 算法 数据安全/隐私保护
【密码学】一文读懂AES
AES加密算法 本文将不会讲述过多有关AES的数学知识, 如果有兴趣的可以自行了解。
1693 0
【密码学】一文读懂AES
|
Rust 算法 安全
【密码学】一文读懂RSA
本文来聊聊RSA, 这是一个非对称密码,和之前所提到的AES与DES不同的是,这个加密方式有两个密钥,一个是公钥,一个是私钥,公钥用来加密,私钥用来解密。相比于对称密码,非对称密码大多基于某个数学难题,比如接下来要谈论的RSA即基于大整数分解的困难性来的,因此为了说明白这个加密算法,首先要先补充&quot;一&quot;点点数学知识。
|
Rust 算法 数据安全/隐私保护
【密码学】一文读懂MD5
曾经沧海难为水,除却巫山不是云。-- 元稹
【密码学】一文读懂MD5