这篇文章主要介绍了关于SHA算法原理与常用实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
看本文前,最好先看看之前的这一篇关于MD5算法的介绍。
MD5算法原理与常用实现
定义
SHA算法(Secure Hash Algorithm),又叫安全散列算法。
SHA算法是基于MD4算法的基础上,演变而来。
但SHA算法出生好,是美国国家安全局设计的。
SHA算法,是一个系列家族,包括SHA-1,SHA-2(SHA-224、SHA-256、SHA-384、SHA-512),括号中的四个通常被统称为SHA-2。
JDK中对SHA-1、SHA-256、SHA-384、SHA-512都有实现。
- SHA-1的最终密码长度是160位。
- SHA-256的最终密码长度是256位。
- SHA-384的最终密码长度是384位。
- SHA-512的最终密码长度是512位。
SHA算法,实际上也是一种消息摘要算法,这个和MD算法是类似的。
本文主要介绍SHA-256算法。
任意长度的消息文件,通过SHA-256算法加密,最终得到的密文都是256位(32字节),通常用一个长度为64的十六进制字符串来表示。
效果上,SHA算法,与MD5算法都差不多,主要特点都是不可逆。
MD5和SHA-1的碰撞问题
碰撞问题,就是指对于一个算法,由明文生成的密文,并不是唯一的,甚至可以人为的通过构造新的明文去得到指定的密文。
对于能出现这种情况的算法,我们就说这个算法是有碰撞问题的,简单理解就是两个不同的明文,通过算法加密,却得到了同样的密文。
目前为止,MD5算法和SHA-1算法,都被证实了存在碰撞问题。
所以在安全性特别高的场景下,都不会用MD5算法和SHA-1算法,至少都用SHA-256算法了。
常见应用场景
1、类似MD5的应用场景
MD5的应用场景,SHA算法基本也都可以使用。
2、比特币
比特币中,挖矿算法其实就是SHA-256算法,矿工们根据不断修改随机数,不断的进行SHA-256运算,最终算的快的挖到矿。
3、https签名算法会用到
打开浏览器,以谷歌为例,查看任意一个整数的详情:
签名算法就是:带 RSA 加密的 SHA-256,如下图:
SHA-256算法原理
SHA家族的基本算法思想,都和MD5一样,先定义常量,然后循环计算,最后组装,不同的就是循环里面的计算方式。
1、填补信息
类似MD5
2、拿到初始值
MD5中有4个初始值,而SHA-256中,有8个。
h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19
3、真正的计算
计算分为多次循环,每次循环,都是用ABCD和原文在第一步填补完的信息,进行计算,最终得到新的ABCD。最后将最后一次ABCD拼成字符串,就是最终的密文。
- 循环先分为主循环,每个主循环中又套有子循环。
- 主循环次数 = 原文长度/512。
- 子循环次数 = 64次。
我们看看单次子循环都做了什么:
下面是单次子循环真正的计算逻辑(这段实现摘自网友):
java实现和使用
其实看过上一篇MD5介绍的,就会发现,其实SHA的java实现,和MD5的java实现,几乎一模一样。
唯一的不同,就是MessageDigest.getInstance(“SHA”);这个方法中:
- SHA-1算法的入参是SHA
- SHA-256算法的入参是SHA-256
- SHA-384算法的入参是SHA-384
- SHA-512算法的入参是SHA-512
MD5的入参是MD5
public class SHA1Util {
public static void main(String[] args) throws IOException {
System.out.println(encodeString("123"));
}
public static String encodeString(String plainText) throws UnsupportedEncodingException {
return encodeBytes(plainText.getBytes("UTF-8"));
}
public static String encodeBytes(byte[] bytes) {
try {
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(bytes);
byte b[] = md.digest();
int i;
StringBuffer buf = new StringBuffer("");
for (int offset = 0; offset < b.length; offset++) {
i = b[offset];
if (i < 0) {
i += 256;
}
if (i < 16) {
buf.append("0");
}
buf.append(Integer.toHexString(i));
}
return buf.toString();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程学习网。
本文标题为:关于SHA算法原理与常用实现方式
基础教程推荐
- Java文件管理操作的知识点整理 2023-05-19
- Java数据结构之对象比较详解 2023-03-07
- Java实现查找文件和替换文件内容 2023-04-06
- ConditionalOnProperty配置swagger不生效问题及解决 2023-01-02
- springboot自定义starter方法及注解实例 2023-03-31
- Java并发编程进阶之线程控制篇 2023-03-07
- java基础知识之FileInputStream流的使用 2023-08-11
- Java实现线程插队的示例代码 2022-09-03
- JDK数组阻塞队列源码深入分析总结 2023-04-18
- java实现多人聊天系统 2023-05-19