SHA1算法实现及详解
2021/5/18 20:55:24
本文主要是介绍SHA1算法实现及详解,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
SHA1算法实现及详解
0X1 SHA1算法详解
SHA1算法是Hash算法的一种。SHA1算法的最大输入长度小于2^64比特的消息,输入消息(明文)以512比特的分组为单位处理,输出160比特的消息摘要(密文)
整个算法的核心是一个包含4轮循环的模块,每轮循环由20个步骤组成。
如下图:
其中Yq代表原始消息, CVq代表初始化的链接变量,最终我们要的密文就是CYq+1
1. 附加填充位
消息必须进行填充,以使其长度在对512取模以后的余数是448。也就是说,(填充后的消息长度)%512 = 448。即使长度已经满足对512取模后余数是448,填充也必须要进行。填充的规则是填充一个“1”和若干个“0”使其长度模512和448同余。然后附加64比特的无符号整数,其值为原始消息的长度
2. 初始化链接变量
和MD5有些类似,将5个32比特的固定数赋值给5个32比特的寄存器(和汇编里面的寄存器不同,可以理解为变量)A、B、C、D、E作为第一次迭代的链接变量输入:
A = 0x67452301, B = 0xEFCDAB89, C = 0x98BADCFE, D = 0x10325476, E = 0xC3D2E1F0
3. 非线性函数f函数
f t ( x , y , z ) = { C h ( x , y , z ) = ( x ⋀ y ) ⨁ ( ┐ x ⋀ z ) , 0 ≤ t ≤ 19 P a r i t y ( x , y , z ) = x ⨁ y ⨁ z , 0 ≤ t ≤ 19 M a j ( x , y , z ) = ( x ⋀ y ) ⨁ ( x ⋀ z ) ⨁ ( y ⋀ z ) 0 ≤ t ≤ 19 P a r i t y ( x , y , z ) = x ⨁ y ⨁ z , 0 ≤ t ≤ 19 f_t(x,y,z) =\begin{cases} Ch(x, y ,z) = (x \bigwedge y) \bigoplus ( \urcorner x \bigwedge z),& 0 \leq t \leq 19 \\ Parity(x, y ,z) =x \bigoplus y\bigoplus z,& 0 \leq t \leq 19 \\ Maj(x, y ,z) = (x \bigwedge y) \bigoplus(x \bigwedge z) \bigoplus(y \bigwedge z) & 0 \leq t \leq 19 \\ Parity(x, y ,z) =x \bigoplus y\bigoplus z,& 0 \leq t \leq 19 \end{cases} ft(x,y,z)=⎩⎪⎪⎪⎨⎪⎪⎪⎧Ch(x,y,z)=(x⋀y)⨁(┐x⋀z),Parity(x,y,z)=x⨁y⨁z,Maj(x,y,z)=(x⋀y)⨁(x⋀z)⨁(y⋀z)Parity(x,y,z)=x⨁y⨁z,0≤t≤190≤t≤190≤t≤190≤t≤19
4. K值的获取
步数 | Kr |
---|---|
r = 1 (0 <= t <= 19) | 0x5A827999 |
r = 2 (20 <= t <= 39) | 0x6ED9EBA1 |
r = 3 (40 <= t <= 59) | 0x8F1BBCDC |
r = 4 (60 <= t <= 79) | 0xCA62C1D6 |
当然你也可以自己计算,四个值的获取分别是2、3、5和10的平方根,然后乘以2^30 = 1 073 741 824最后取乘积的整数部分。
5. W值的获取
R
O
T
L
n
(
x
)
表
示
对
32
位
比
特
的
变
量
循
环
左
移
n
比
特
ROTL^n(x)表示对32位比特的变量循环左移n比特
ROTLn(x)表示对32位比特的变量循环左移n比特
注意是循环左移n比特
W一共分为80组,其中从W[0]到W[15]为获得的原始消息均分为16组。
{ W t = M t ( i ) 0 ≤ t ≤ 15 W t = R O T L 1 ( W ( t − 3 ) ⨁ W ( t − 8 ) ⨁ W ( t − 14 ) ⨁ W ( t − 16 ) , 16 ≤ t ≤ 79 \begin{cases} W_t = M_t^{(i)} & 0 \leq t \leq 15 \\ W_t =ROTL^1(W_{(t-3)}\bigoplus W_{(t-8)}\bigoplus W_{(t-14)}\bigoplus W_{(t-16)},& 16 \leq t \leq 79 \end{cases} {Wt=Mt(i)Wt=ROTL1(W(t−3)⨁W(t−8)⨁W(t−14)⨁W(t−16),0≤t≤1516≤t≤79
6. 步函数
A
=
(
R
O
T
L
5
(
A
)
+
f
t
(
B
,
C
,
D
)
+
E
+
W
t
+
K
r
)
m
o
d
2
32
B
=
A
C
=
R
O
T
L
30
(
B
)
m
o
d
2
32
D
=
C
E
=
D
A = (ROTL^5(A) + f^t(B,C,D) + E + W^t + K^r)mod 2^{32}\\B=A\\C= ROTL^{30}(B)mod2^{32}\\D=C\\E=D
A=(ROTL5(A)+ft(B,C,D)+E+Wt+Kr)mod232B=AC=ROTL30(B)mod232D=CE=D
其中t是步数,0 <= t <= 79,r为轮数, 0 <= r <= 4.
0X2源代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #pragma warning(disable:4996) //初始化链接变量 unsigned int A = 0x67452301, B = 0xEFCDAB89, C = 0x98BADCFE, D = 0x10325476, E = 0xC3D2E1F0; //第一次迭代的链接变量 unsigned int K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; //循环中用到的常量 unsigned int A0 = 0x67452301, B0 = 0xEFCDAB89, C0 = 0x98BADCFE, D0 = 0x10325476, E0 = 0xC3D2E1F0; // 字节转换,将四个字节转换为一个整型 int CharToWord(unsigned char *context, int i) { return (((int)context[i] & 0x000000ff) << 24) | (((int)context[i + 1] & 0x000000ff) << 16) | (((int)context[i + 2] & 0x000000ff) << 8) | ((int)context[i + 3] & 0x000000ff); } // 填充补位获得原始明文 void SHA1_fill(unsigned char *plaintext, unsigned int *group, int length) { printf("补位后获得的明文:\n"); int temp = length / 32, len = length; while (len > 0) { if (len = len / 32) { for (int j = 0; j < temp; j++) { group[j] = CharToWord(plaintext, 4 * j); printf("%08X\n", group[j]); } } else { plaintext[length / 8] = 0x80; group[temp] = CharToWord(plaintext, temp * 4); printf("%08X\n", group[temp]); break; } } group[15] = length; for (int i = temp + 1; i < 16; i++) printf("%08X\n", group[i]); } // f函数 unsigned int f(int B, int C, int D, int t) { return (t >= 0 && t <= 19) ? ((B&C) | (~B&D)) : ((t >= 20 && t <= 39) ? (B ^ C ^ D) : ((t >= 40 && t <= 59) ? ((B&C) | (B&D) | (C&D)) : ((t >= 60 && t <= 79) ? B ^ C ^ D : 0))); } //获得Kr unsigned int GetK(int r) { /* if (r >= 0&& r <= 19) { return K[0]; }else if (r >= 20 && r <= 39) { return K[1]; }else if (r >= 40 && r <= 59) { return K[2]; }else if (r >= 60 && r <= 79) { return K[3]; } */ return (r >= 0 && r <= 19) ? K[0] : ((r >= 20 && r <= 39) ? K[1] : ((r >= 40 && r <= 59) ? K[2] : ((r >= 60 && r <= 79) ? K[3] : 0))); } //获得 Wt void GetW(unsigned int w[]) { /* for (int i = 16; i < 80; i++) w[i] = ((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) << 1) | ((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) >> 31); */ for (int i = 16; i < 80; w[i++] = ((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) << 1) | ((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) >> 31)); } // 步函数 void StepFunction(unsigned int w[], int t) { unsigned int temp = ((A << 5) | (A >> 27)) + f(B, C, D, t) + E + w[t] + GetK(t); E = D, D = C, C = ((B << 30) | (B >> 2)), B = A, A = temp; } // 获得密文 void GetCipher(unsigned int * cipher) { cipher[0] = A0 + A; cipher[1] = B0 + B; cipher[2] = C0 + C; cipher[3] = D0 + D; cipher[4] = E0 + E; } void SHA1(unsigned char *context,unsigned int * cipher) { int len = strlen((char*)context) * 8; unsigned int group[80] = { 0 }; SHA1_fill(context, group, len); GetW(group); for (int t = 0; t < 80; t++) { StepFunction(group, t); } GetCipher(cipher); } int main() { unsigned char m[56]; unsigned int c[5] = { 0 }; printf("请输入长度小于56且不包含空格的明文:"); scanf("%s", m); SHA1(m,c); /*密文输出*/ printf("密文为:"); for (int j = 0; j <= 4; j++) printf("%08X", c[j]); printf("\n"); system("pause"); return 0; }
这篇关于SHA1算法实现及详解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-19永别了,微服务架构!
- 2024-05-15鸿蒙生态设备数量超8亿台
- 2024-05-13TiDB + ES:转转业财系统亿级数据存储优化实践
- 2024-05-09“2024鸿蒙零基础快速实战-仿抖音App开发(ArkTS版)”实战课程已上线
- 2024-05-09聊聊如何通过arthas-tunnel-server来远程管理所有需要arthas监控的应用
- 2024-05-09log4j2这么配就对了
- 2024-05-09nginx修改Content-Type
- 2024-05-09Redis多数据源,看这篇就够了
- 2024-05-09Google Chrome驱动程序 124.0.6367.62(正式版本)去哪下载?
- 2024-05-09有没有大佬知道这种数据应该怎么抓取呀?