Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说「后端」加密算法之 SHA 算法[通俗易懂],希望能够帮助你!!!。
今天我们开始介绍消息摘要算法中的 SHA(Secure Hash Algorithm)安全散列算法。由于其他曾被广泛使用的 Hash 算法,比如上一篇文章《「后端」加密算法之MD算法》提到的 MD5,后来都被发现存在一定的安全隐患,新的摘要算法算法就出现了。
SHA 算法是由美国国家安全局(NSA)所设计,并由美国国家标准与技术研究院(NIST)于1993年发布,是美国的政府标准。从2005年至今,SHA或许已经成为仅存的Hash算法的标准了。
SHA 家族的五个算法,分别是SHA-1、SHA-224、SHA-256、SHA-384 和 SHA-512。
SHA-0
最初载明的算法于 1993 年发布,称做安全杂凑标准(Secure Hash Standard),FIPS PUB 180。这个版本常被称为 SHA-0。由于很快被发现存在安全隐患,它在发布之后很快就被 NSA 撤回,并且由 1995 年发布的修订版本 FIPS PUB 180-1(通常称为SHA-1)取代。
SHA-1
SHA-1 算法和 MD5 算法都是由 MD4 算法导出,因此他们俩的特点、缺陷、应用场景基本是相同的。
它俩的区别在于 SHA-1 算法在长度上是40位十六进制,即 160 位的二进制;而 MD5 算法是 32 位的十六进制,即128位的二进制,所以 2 的 160 次是远远超过 2 的 128 次这个数量级的,所以 SHA-1 算法相对来说要比 MD5 算法更安全一些。
SHA-2
2002年,NIST 分别发布了 SHA-256、SHA-384、SHA-512,这些算法统称为 SHA-2,2008年又新增了 SHA-224。
由于 SHA-1 已经不太安全,目前 SHA-2 各版本已成为主流。SHA-2 是一系列 SHA 算法变体的总称,其中包含如下子版本:
SHA-3
2012年10月,经过多年的测试和分析,美国 NIST 选择了 Keccak 算法作为 SHA - 3 的标准算法,Keccak 拥有良好的加密性能以及抗解密能力。SHA3算法是以太坊的基础加密算法。
Keccak 算法(读作为“ket-chak”)是 Guido Bertoni, Joan Daemen, Michael Peters, and Giles Van Assche 的工作。 SHA-3 的候选人在 2008 年 10 月提交。
Keccak采用了创新的的“海绵引擎”散列消息文本。它是快速的,在英特尔酷睿2处理器下的平均速度为12.5周期每字节。它设计简单,方便硬件实现。
前面我们简单的介绍了SHA算法家族,接下来我们以SHA-1为例来分析其基本原理。SHA-1是一种数据加密算法,该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段密文,也可以简单的理解为输入一串二进制码,并把它们转化为长度较短、位数固定的输出序列即散列值,也称为信息摘要或信息认证代码的过程。
SHA-1 算法输入报文的最大长度不超过264位,产生的输出是一个 160 位的报文摘要。输入是按 512 位的分组进行处理的。SHA-1 是不可逆的、防冲突,并具有良好的雪崩效应。
一般来说 SHA-1 算法包括有如下的处理过程:
(1)对输入信息进行处理
既然 SHA-1 算法是对给定的信息进行处理得到相应的摘要,那么首先需要按算法的要求对信息进行处理。那么如何处理呢?对输入的信息按 512 位进行分组并进行填充。如何填充信息报文呢?其实即使填充报文后使其按 512 进行分组后,最后正好余 448 位。那填充什么内容呢?就是先在报文后面加一个 1,再加很多个 0,直到长度满足对 512 取模结果为 448。到这里可能有人会奇怪,为什么非得是 448 呢?这是因为在最后会附加上一个64位的报文长度信息,而 448+64 正好是 512。
(2)填充长度信息
前面已经说过了,最后会补充信息报文使其按 512 位分组后余 448 位,剩下的 64 位就是用来填写报文的长度信息的。至次可能大家也明白了前面说过的报文长度不能超过 264 位了。填充长度值时要注意必须是低位字节优先。
(3)信息分组处理
经过添加位数处理的明文,其长度正好为 512 位的整数倍,然后按 512 位的长度进行分组,可以得到一定数量的明文分组,我们用 Y0,Y1,……YN-1 表示这些明文分组。对于每一个明文分组,都要重复反复的处理,这些与 MD5 都是相同的。
(4)初始化缓存
所谓初始化缓存就是为链接变量赋初值。前面我们实现 MD5 算法时,说过由于摘要是 128位,以 32 位为计算单位,所以需要4个链接变量。同样 SHA-1 采用 160 位的信息摘要,也以 32 位为计算长度,就需要 5 个链接变量。我们记为A、B、C、D、E。其初始赋值分别为:A = 0x67452301、B = 0xEFCDAB89、C = 0x98BADCFE、D = 0x10325476、E = 0xC3D2E1F0。
如果我们对比前面说过的 MD5 算法就会发现,前4个链接变量的初始值是一样的,因为它们本来就是同源的。
(5)计算信息摘要
经过前面的准备,接下来就是计算信息摘要了。SHA1 有 4 轮运算,每一轮包括 20 个步骤,一共 80 步,最终产生 160 位的信息摘要,这 160 位的摘要存放在 5 个 32 位的链接变量中。
不同 SHA 算法的数据比较如下表,其中的长度单位均为位:
类别 |
SHA-1 |
SHA-224 |
SHA-256 |
SHA-384 |
SHA-512 |
消息摘要长度 |
160 |
224 |
256 |
384 |
512 |
消息长度 |
<2^64 |
<2^64 |
<2^64 |
<2^128 |
<2^128 |
分组长度 |
512 |
512 |
512 |
1024 |
1024 |
计算字步长 |
32 |
32 |
32 |
64 |
64 |
计算步骤数 |
80 |
64 |
64 |
80 |
80 |
从上表中我们不难发现,SHA-224 和 SHA-256、SHA-384 和 SHA-512 在消息长度、分组长度、计算字长以及计算步骤各方面分别都是一致的。通常认为 SHA-224 是 SHA-256 的缩减版,而 SHA-384 是 SHA-512 的缩减版。
算法 |
摘要长度(bit) |
实现方 |
SHA-1 |
160 |
JDK、Bouncy Castle、Commons Codec |
SHA-224 |
224 |
JDK、Bouncy Castle |
SHA-256 |
256 |
JDK、Bouncy Castle、Commons Codec |
SHA-384 |
384 |
JDK、Bouncy Castle、Commons Codec |
SHA-512 |
512 |
JDK、Bouncy Castle、Commons Codec |
从上面的介绍可以知道,SHA 分为多种算法,上述算法在 JDK 均有实现,以下实现为通用实现方法,例如,当 algorithm 传入对应的算法名称就可以获得对应的算法实例,比如 “SHA-256”:
// SHA 加密
public static String encodeSha(String data, String algorithm) throws Exception {
MessageDigest sha = MessageDigest.getInstance(algorithm);
byte[] srcBytes = data.getBytes();
// 使用srcBytes更新摘要
sha.update(srcBytes);
// 完成哈希计算,得到result
byte[] resultBytes = sha.digest();
// 返回十六进制字符串
return new HexBinaryAdapter().marshal(resultBytes);
}
第三方加密组件包 Bouncy Castle 是对 JDK 的补充,同样也实现了所有的 SHA 算法,以下为算法的通用实现:
public static String encodeSha(String data, String algorithm) throws NoSuchAlgorithmException {
// 加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
// 初始化MessageDigest
MessageDigest sha = MessageDigest.getInstance(algorithm);
// 获取消息摘要
byte[] bytes = sha.digest(data.getBytes());
// 返回十六进制字符串
return Hex.toHexString(bytes);
}
Commons Codec 提供了 SHA 系列算法的消息摘要算法的实现,在使用时可以通过封装的工具类----- DigestUtils 类来进行操作。DigestUtils 类是对 Sun 提供的 MessageDigest 类的一次封装,提供了完整的实现方法。下面是以 SHA-256 算法实现的示例:
public static String encodeSha1Hex(String data) {
return DigestUtils.sha1Hex(data);
}
public static String encodeSha256Hex(String data) {
return DigestUtils.sha256Hex(data);
}
public static String encodeSha384Hex(String data) {
return DigestUtils.sha384Hex(data);
}
public static String encodeSha512Hex(String data) {
return DigestUtils.sha512Hex(data);
}
很多软件,尤其是安全性要求较高的软件,会在官网上公布软件的 SHA 值,用户下载软件后,可以自行计算软件 SHA 值,然后与官网公布的 SHA 值进行比较,确认软件是否被篡改过,和前面介绍的 MD5 的作用是一样的。同样的,Oracle 官网也提供了两个版本的摘要值,分别是 MD5 和 SHA-256,无论使用那种算法,都可以校验文件的完整性。
SHA 也被用于基于口令的加密(Password Based Encryption,PBE),PBE 的原理是将口令和盐(salt)混合后计算其 SHA 值,然后将这个散列值用作加密的秘钥。PBE 可以防御针对口令的字典攻击。
消息认证码是将“发送者和接收者之间的共享秘钥”和“消息”进行混合后计算出的 SHA。使用消息认证码可以检测并防止通信过程中的错误、篡改以及伪装。
数字签名是现实社会中的签名和盖章这样的行为在数字世界中的实现。数字签名的处理过程非常耗时,因此一般不会对整个消息内容施加数字签名,而是先取消息内容的 SHA 值,对 SHA 值进行数字签名。
SHA 算法在许多安全协议中广为使用,包括 TSL/SSL、PGP、SSH、S/MIME 和 IPsec,同时在 TSL/SSL 安全协议数字证书中,也有 SHA 的影子,例如证书指纹一般都是通过 SHA-1来实现的。
SHA 算法在当前生产应用中比较常见的,其中 SHA-256 算法的安全性是被世界各国密码学家所广泛承认的。
文章来源:https://zhuanlan.zhihu.com/p/343822954