SHA1 算法加密技术核心思想
SHA1 算法加密技术核心思想
一、认知
1、在我们的平时生活中,经常会接触到一些密码,通过这些密码,能对我们的一些资产和隐私的东西做到保护作用,比如:
- 古墓密码锁
- 暗号:天王盖地虎,。。。。。
- 美国的摩尔斯在 1844 年发明的摩尔斯电码,也叫摩斯密码
- 银行,手机,游戏的账号密码
2、那么,在软件中又是用什么来实现的加密与解密的呢,作为一名程序猿,我们站在巨人的肩膀上前行,不用重复造轮子,但是我们也要知道轮子是怎么造的,今天我们就来了解一下加密与解密的核心思想。
二、常见的加密算法
- 安全哈希算法(Secure Hash Algorithm)SHA-1
- DES 数据加密标准
- Base64
- RSA 公钥加密算法
今天我们就通过 SHA-1 算法来了解一下加密与解密技术的核心思想:
在 APP 开发中,我们常见到 SHA-1 值是在签名文件中,如下图:
那么,SHA1 是什么呢,为什么 Google 要用 SHA1 作为签名文件的证书指纹呢,下面我们一起来了解SHA 算法是什么。
SHA(Secure Hash Algorithm)是安全哈希算法的简称,该算法经过加密专家多年来的发展和改进已日益完善,现在已成为公认的最安全的散列算法之一,并被广泛使用,主要适用于数字签名标准里面定义的数字签名算法。
上面的签名证书 SHA1 值是怎么得到的呢,下面以加密字符串 “abc” 为例,介绍 SHA1 加密的原理及流程。
1、将消息转换成二进制字符串
根据 ASCII 码表,字符对应的 ASCII 码为 ‘a’=97, ‘b’=98, ‘c’=99,再将其转换为二进制后为:
“abc” -> “97 98 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 bit 的信息,用来表示原始信息摘要的长度,在这步操作之后,信息报文便是 512 bit 的倍数。通常来说用一个 64 位的数据表示原始消息的长度,如果消息长度不大于 2^64,那么前 32 bit 就为 0,在进行附加长度值操作后,其“abc”数据报文即变成如下形式:
61626380 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000018
因为 “abc” 占 3 个字节,即 24 位 ,换算为十六进制即为 0x18。
这样,就把整个消息分成一个个 512 位的数据块,再分别处理每个数据块,得到消息摘要。
4、初始化缓存
一个 160 位 MD 缓冲区用以保存中间和最终散列函数的结果。它可以表示为 5 个 32 位的寄存器(H0,H1,H2,H3,H4)。初始化为:
H0 = 0x67452301
H1 = 0xEFCDAB89
H2 = 0x98BADCFE
H3 = 0x10325476
H4 = 0xC3D2E1F0
大端存储模式:高位数据放在低地址,低位数据放在高地址
5、计算消息摘要
- S 函数:循环左移操作符 Sn(x),x 是一个字,也就是 32 bit 大小的变量,n 是一个整数且 0<=n<=32。Sn(X) = (X<<n) OR (X>>32-n)
- 常量字 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) - 非线性函数
所要用到的一系列函数,根据结果无法反推:
Ft(b,c,d) ((b&c)|((~b)&d)) (0 <= t <= 19)
Ft(b,c,d) (bcd) (20 <= t <= 39)
Ft(b,c,d) ((b&c)|(b&d)|(c&d)) (40 <= t <= 59)
Ft(b,c,d) (bcd) (60 <= t <= 79) - 开始计算摘要
- 计算需要一个缓冲区,由 5 个 32 位的字组成,还需要一个 80 个 32 位字的缓冲区。第一个 5 个字的缓冲区被标识为 A,B,C,D,E。80 个字的缓冲区被标识为 W0, W1,…, W79
- 另外还需要一个一个字的TEMP缓冲区。
- 为了产生消息摘要,在补好位的数据中前 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.
6、同类算法
SHA1 SHA224 SHA256 SHA384 SHA512
MD5 HmacMD5
HmacSHA1 HmacSHA224 HmacSHA256 HmacSHA384 HmacSHA512 PBKDF2
注意:只要是哈希函数,就存在碰撞,所谓碰撞的意思是,有两个不同的数据,他们的哈希值相同(SHA1 值相同)
三、实战
废话不多说,实践才是检验真理的唯一标准,下面我们就通过代码来实现这一过程,看看结果如何:
package com.example.sha1;import org.junit.Test;/*** Created by author 2020/08/09*/public class SHA1 {//1.准备工作public static final int[] abcde = {0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0};//摘要数据存储用的数组(存放密文的) 20个字节*8=160;public static int[] h=new int[5];//计算过程中需要用到的临时数据存储数组public static int[] m=new int[80];//定义辅助方法//将字符转换为十六进制字符串public static String byteToHexString(byte b){//97char[] digit={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};char[] ob=new char[2];ob[0]=digit[(b>>>4)&0x0F];//9ob[1]=digit[b&0x0f];//7String s=new String(ob);//"97"return s;}//将字节数组转换为十六进制字符串public static String byteArrayToHexString(byte[] byteArray){String strDigest="";for(int i=0;i<byteArray.length;i++){strDigest+=byteToHexString(byteArray[i]);}return strDigest;}//4字节数组转换为int i个byte合成到byteData[]中public static