Java哈希算法

哈希算法

  • 哈希算法
    • 1.概述
    • 2.哈希碰撞
    • 3.常用的哈希算法
    • 4.哈希算法的用途
      • 4.1校验下载文件
      • 4.2存储用户密码
      • MD5加密
      • 5.SHA-1加密
      • 小结:

哈希算法

1.概述

哈希算法(Hash)又称摘要算法(Digest),它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。
哈希算法最重要的特点就是:
● 相同的输入一定得到相同的输出;
● 不同的输入大概率得到不同的输出。
所以,哈希算法的目的:为了验证原始数据是否被篡改。

Java字符串的hashCode()就是一个哈希算法,它的输入是任意字符串,输出是固定的4字节int整数:

"hello".hashCode(); // 0x5e918d2
"hello, java".hashCode(); // 0x7a9d88e8
"hello, bob".hashCode(); // 0xa0dbae2f

两个相同的字符串永远会计算出相同的hashCode,否则基于hashCode定位的HashMap就无法正常工作。这也是为什么当我们自定义一个class时,覆写equals()方法时我们必须正确覆写hashCode()方法。

2.哈希碰撞

哈希碰撞是指:两个不同的输入得到了相同的输出。
例如:

"AaAaAa".hashCode(); // 0x7460e8c0
"BBAaBB".hashCode(); // 0x7460e8c0"通话".hashCode(); // 0x11ff03
"重地".hashCode(); // 0x11ff03

碰撞能不能避免?答案是不能。碰撞是一定会出现的,因为输出的字节长度是固定的,String的hashCode()输出是4字节整数,最多只有4294967296种输出,但输入的数据长度是不固定的,有无数种输入。所以,哈希算法是把一个无限的输入集合映射到一个有限的输出集合,必然会产生碰撞。
碰撞不可怕,我们担心的不是碰撞,而是碰撞的概率,因为碰撞概率的高低关系到哈希算法的安全性。一个安全的哈希算法必须满足:
● 碰撞概率低;
● 不能猜测输出。
不能猜测输出是指:输入的任意一个bit的变化会造成输出完全不同,这样就很难从输出反推输入(只能依靠暴力穷举)。
假设一种哈希算法有如下规律:

hashA("java001") = "123456"
hashA("java002") = "123457"
hashA("java003") = "123458"

那么很容易从输出123459反推输入,这种哈希算法就不安全。安全的哈希算法从输出是看不出任何规律的:

hashB("java001") = "123456"
hashB("java002") = "580271"
hashB("java003") = ???

3.常用的哈希算法

哈希算法,根据碰撞概率,哈希算法的输出长度越长,就越难产生碰撞,也就越安全。
常用的哈希算法有:

算法输出长度(位)输出长度(字节)
MD5128 bits16 bytes
SHA-1160 bits20 bytes
RipeMD-160160 bits20 bytes
SHA-256256 bits32 bytes
SHA-512512 bits64 bytes

Java标准库提供了常用的哈希算法,通过统一的接口进行调用。以MD5算法为例,看看如何对输入内容计算哈希:

import java.security.MessageDigest;public class main {public static void main(String[] args)  {// 创建一个MessageDigest实例:MessageDigest md = MessageDigest.getInstance("MD5");// 反复调用update输入数据:md.update("Hello".getBytes("UTF-8"));md.update("World".getBytes("UTF-8"));// 16 bytes: 68e109f0f40ca72a15e05cc22786f8e6byte[] results = md.digest(); StringBuilder sb = new StringBuilder();for(byte bite : results) {sb.append(String.format("%02x", bite));}System.out.println(sb.toString());}
}

使用MessageDigest时,我们首先根据哈希算法获取一个MessageDigest实例,然后,反复调用update(byte[])输入数据。当输入结束后,调用digest()方法获得byte[]数组表示的摘要,最后,把它转换为十六进制的字符串。
运行上述代码,可以得到输入HelloWorld的MD5是68e109f0f40ca72a15e05cc22786f8e6。

4.哈希算法的用途

4.1校验下载文件

因为相同的输入永远会得到相同的输出,因此,如果输入被修改了,得到的输出就会不同。我们在网站上下载软件的时候,经常看到下载页显示的MD5哈希值:

image.png

如何判断下载到本地的软件是原始的、未经篡改的文件?我们只需要自己计算一下本地文件的哈希值,再与官网公开的哈希值对比,如果相同,说明文件下载正确,否则,说明文件已被篡改。

4.2存储用户密码

哈希算法的另一个重要用途是存储用户口令。如果直接将用户的原始口令存放到数据库中,会产生极大的安全风险:
● 数据库管理员能够看到用户明文口令;
● 数据库数据一旦泄漏,黑客即可获取用户明文口令。

usernamepassword
adminadmin
useruser
timtim

不存储用户的原始口令,那么如何对用户进行认证?方法是存储用户口令的哈希,例如,MD5。在用户输入原始口令后,系统计算用户输入的原始口令的MD5并与数据库存储的MD5对比,如果一致,说明口令正确,否则,口令错误。
因此,数据库存储用户名和口令的表内容应该像下面这样:

usernamepassword
admin25f9e794323b453885f5181f1b624d0b
user73a90acaae2b1ccc0e969709665bc62f
tim19f9f30bd097d4c066d758fb01b75032

这样一来,数据库管理员看不到用户的原始口令。即使数据库泄漏,黑客也无法拿到用户的原始口令。想要拿到用户的原始口令,必须用暴力穷举的方法,一个口令一个口令地试,直到某个口令计算的MD5恰好等于指定值。
使用哈希口令时,还要注意防止彩虹表攻击。
什么是彩虹表呢?上面讲到了,如果只拿到MD5,从MD5反推明文口令,只能使用暴力穷举的方法。然而黑客并不笨,暴力穷举会消耗大量的算力和时间。但是,如果有一个预先计算好的常用口令和它们的MD5的对照表,这个表就是彩虹表。如果用户使用了常用口令,黑客从MD5一下就能反查到原始口令:

常用口令MD5
hello123f30aa7a662c728b7407c54ae6bfd27d1
1234567825d55ad283aa400af464c76d713c07ad

这就是为什么不要使用常用密码,以及不要使用生日作为密码的原因。
当然,我们也可以采取特殊措施来抵御彩虹表攻击:对每个口令额外添加随机数,这个方法称之为加盐(salt):
digest = md5(salt + inputPassword)
经过加盐处理的数据库表,内容如下:

usernamesaltpassword
bobH1r0aa5022319ff4c56955e22a74abcc2c210
alice7$p2we5de688c99e961ed6e560b972dab8b6a
timz5Sk91eee304b92dc0d105904e7ab58fd2f64
public class Demo05 {public static void main(String[] args) throws NoSuchAlgorithmException, IOException {byte[] password = "liyupiicu@com".getBytes();MessageDigest md5 = MessageDigest.getInstance("MD5");md5.update(password);// 产生随机盐值String uuid = UUID.randomUUID().toString().substring(16);md5.update(uuid.getBytes());// 获取消息摘要对象进行加密byte[] digetByte = md5.digest();System.out.println(Arrays.toString(digetByte));System.out.println(Demo03.byteToHex(digetByte));System.out.println(digetByte.length);}
}

MD5加密

Demo01

public class Demo01 {public static void main(String[] args) throws NoSuchAlgorithmException {// 创建一个MessageDigest实例:MessageDigest md = MessageDigest.getInstance("MD5");byte[] bytes = "测试测试测试".getBytes();// 反复调用update输入数据:md.update(bytes);// 加密:查看内容byte[] result = md.digest();System.out.println(result.length);System.out.println(Arrays.toString(result));}
}

在这里插入图片描述

Demo02

public class Demo02 {public static void main(String[] args) throws NoSuchAlgorithmException {// 获取消息摘要对象MessageDigest md5 = MessageDigest.getInstance("MD5");byte[] b = "我本将心照明月".getBytes();// 数据量小使用信息加密md5.digest(b)
//		byte[] result = md5.digest(b);
//		System.out.println("加密前:" + Arrays.toString(b));
//		System.out.println("加密后:" + Arrays.toString(result));
//		System.out.println("加密后长度:" + result.length);// 数据量大使用md5.update(b)加密md5.update(b);md5.update("爪爪吃蒸饺".getBytes());md5.update("蒸米粉肉".getBytes());//加密,查看内容byte[] result=md5.digest();System.out.println("加密前:" + Arrays.toString(b));System.out.println("加密后:" + Arrays.toString(result));System.out.println("加密后长度:" + result.length);}
}

在这里插入图片描述

Demo03

public class Demo03 {public static void main(String[] args) throws NoSuchAlgorithmException {String password = "wbjxxmy";byte[] bytepassword = password.getBytes();// 获取消息摘要对象MessageDigest md5 = MessageDigest.getInstance("MD5");// 反复添加需要加密的内容md5.update(bytepassword);// 加密byte[] digestpassword = md5.digest();System.out.println(Arrays.toString(bytepassword));System.out.println("加密后数组信息:" + Arrays.toString(digestpassword));System.out.println("加密后16进制字符串信息:" + byteToHex(digestpassword));}public static String byteToHex(byte[] digestpassword) {StringBuffer sb = new StringBuffer();for (byte b : digestpassword) {sb.append(String.format(",%02x", b));}return sb.toString();}
}

Demo04

md5算法对图片进行加密

//md5算法对图片进行加密
public class Demo04 {public static void main(String[] args) throws NoSuchAlgorithmException, IOException {byte[] image = Files.readAllBytes(Paths.get("E:\\apesourcefile\\maomao.jpg"));MessageDigest md5 = MessageDigest.getInstance("MD5");md5.update(image);byte[] result = md5.digest();System.out.println(Arrays.toString(result));System.out.println(Demo03.byteToHex(result));
//		06203919a4288aafd95b78964386f0fd
//		06203919a4288aafd95b78964386f0fd}
}

5.SHA-1加密

SHA-1也是一种哈希算法,它的输出是160 bits,即20字节。SHA-1是由美国国家安全局开发的,SHA算法实际上是一个系列,包括SHA-0(已废弃)、SHA-1、SHA-256、SHA-512等。
在Java中使用SHA-1,和MD5完全一样,只需要把算法名称改为"SHA-1":

import java.security.MessageDigest;public class main {public static void main(String[] args)  {// 创建一个MessageDigest实例:MessageDigest md = MessageDigest.getInstance("SHA-1");// 反复调用update输入数据:md.update("Hello".getBytes("UTF-8"));md.update("World".getBytes("UTF-8"));// 20 bytes: db8ac1c259eb89d4a131b253bacfca5f319d54f2byte[] results = md.digest(); StringBuilder sb = new StringBuilder();for(byte bite : results) {sb.append(String.format("%02x", bite));}System.out.println(sb.toString());}
}

类似的,计算SHA-256,我们需要传入名称"SHA-256",计算SHA-512,我们需要传入名称"SHA-512"。Java标准库支持的所有哈希算法可以在这里https://docs.oracle.com/en/java/javase/14/docs/specs/security/standard-names.html#messagedigest-algorithms查到。

sha-1加密和md5加密

注意:md5加密长度为32位,sha-1加密长度为40位。

public class Demo06 {public static void main(String[] args) throws NoSuchAlgorithmException {byte[] password = "爪爪吃蒸饺".getBytes();// md5加密String resultMd5 = HashUtlis.messageMD5(password);// sha-1加密String resultSha1 = HashUtlis.messageSHA1(password);System.out.println("md5加密后为" + resultMd5);System.out.println("Sha1加密后为" + resultSha1);char[] r1 = resultMd5.toCharArray();char[] r2 = resultSha1.toCharArray();System.out.println(r1.length);System.out.println(r2.length);}
}

在这里插入图片描述

小结:

哈希算法可用于验证数据完整性,具有防篡改检测的功能;
● 常用的哈希算法有MD5、SHA-1等;
● 用哈希存储口令时要考虑彩虹表攻击。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/394048.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[软件测试·研究向] MuJava 工具遇到的问题汇总和体会

MuJava 是初学者(研究向)常常会去使用的一个工具,也是 Java 软件测试的一个老牌工具。用于为 Java 代码生成变异体和运行单元测试。但是此工具已经有十年没有更新了,这款软件可以说现在已经不能够支持对主流软件框架运行测试。但是…

软考-软件设计师 (计算机组成和体系结构习题)

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

优秀的行为验证码的应用场景与行业案例

应用场景 登录注册 : 验证码适用于App、Web及小程序等用户注册场景,可以抵御自动机恶意注册,垃圾注册、抵御撞库登录、暴力破解、验证账号敏感信息的修改,同时可以有效阻止撞库攻击,从源头进行防护,保障正…

ip地址冲突会影响整个网络吗

在数字化时代,网络已成为连接世界的桥梁,而IP地址则是这座桥梁上不可或缺的“门牌号”。然而,当这个独特的身份标识出现冲突时,整个网络的稳定运行将面临严峻挑战。IP地址冲突,这一看似微小的技术问题,实则…

【电路笔记】-无源衰减器

无源衰减器 文章目录 无源衰减器1、概述2、简单衰减器3、无源衰减器示例14、无源衰减器设计5、切换式衰减器6、总结无源衰减器是一种特殊类型的电气或电子双向电路,由完全电阻元件组成。 1、概述 无源衰减器基本上是两个端口电阻网络,旨在将电源提供的功率削弱或“衰减”(因…

递归深度问题和尾调用的关系

当我们在编写计算阶乘的函数,一般我们都会会选择使用迭代或递归的方法来实现。下面就让我们看看,同一个函数的两种实现方法。首先,是使用迭代方式实现的函数,我们使用循环的方式来计算阶乘: // 阶乘函数,计…

java之多线程篇

一、基本概念 1.什么是线程? 线程就是,操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。简单理解就是:应用软件中互相独立,可以同时运行的功能 2.什么是多线程? 有了多线…

无人机之飞行控制系统篇

一、飞行控制系统组成 包括惯性测量单位、GPS接收机、气压高度计、空速计等传感器,以及飞控计算机、伺服作动器等设备。 二、飞行控制原理 通过传感器实时感知无人机的飞行状态,将数据传输给飞控计算机进行处理,计算机再根据预设的飞行计划和…

13-按键的元件模型创建

1.画线的时候,栅格切为10mil 2.放置管脚的时候,栅格切为100mil

开发框架DevExpress XAF v24.2产品路线图预览——增强跨平台性

DevExpress XAF是一款强大的现代应用程序框架,允许同时开发ASP.NET和WinForms。XAF采用模块化设计,开发人员可以选择内建模块,也可以自行创建,从而以更快的速度和比开发人员当前更强有力的方式创建应用程序。 DevExpress XAF是一…

LLaMA- Adapter V2: Parameter-Efficient Visual Instruction Model

发表时间:28 Apr 2023 论文链接:https://arxiv.org/pdf/2304.15010 作者单位: Shanghai Artificial Intelligence Laboratory Motivation:如何有效地将大型语言模型 (LLM) 转换为指令追随者最近是一个流行的研究方向&#xff0…

Linux基于centOS7【内存与OS的随谈】,进程初学【PCB】【fork】【进程排队】

冯诺依曼体系结构——存储器 存储器主要指的是内存,它有个特点就是掉电易失 磁盘等其它输入和输出设备 为什么要在计算机体系结构中要存在内存 我们知道,CPU的处理速度很快很快,但输入设备,以及输出设备,是相对很慢的…

sql注入靶场搭建

1.安装小皮面板(PhpStudy) 1.从官网下载:http://www.xp.cn 2、Sqli-labs环境安装 准备好sqli-labs-php7-master文件 3.安装之前确保本地没有下载mysql服务器 如果电脑下载了MySQL可以把MySQL的服务停掉 此电脑>右键>管理>服务…

QModbus例程分析

由于有一个Modebus上位机的需要,分析一下QModbus Slave的源代码,方便后面的开发。 什么是Modbus Modbus是一种常用的串行通信协议,被广泛应用于工业自动化领域。它最初由Modicon(目前属于施耐德电气公司)于1979年开发…

C++:vector容器

概览 std::vector是C标准模板库(STL)中的一种动态数组容器。它提供了一种类似于数组的数据结构,但是具有动态大小和更安全的内存管理。 定义和基本特性 std::vector是C标准库中的一 个序列容器,它代表了能够动态改变大小的数组。与普通数组一样&#x…

模拟面试题1

目录 一、JVM的内存结构? 二、类加载器分为哪几类? 三、讲一下双亲委派机制 为什么要有双亲委派机制? 那你知道有违反双亲委派的例子吗? 四、IO 有哪些类型? 五、Spring Boot启动机制 六、Spring Boot的可执行…

关于儿童编程语言

青少年通常会通过Scratch或Python开始学习编程。在这两种语言中,代码的编写(或者在Scratch中是构建)方式类似于英语,这使得初学者更容易学习。Scratch的一个重要卖点是对视觉和运动感知学习者非常友好。这些代码块按颜色编码&…

最短路问题中的bellman-ford算法

最短路问题中的bellman-ford算法 题目 如果要处理单源最短路问题当中存在负权边的,那么就需要用到 bellman-ford算法和SPFA算法,一般情况下都是用 SPFA算法,除了有边数限制的情况只能用bellman-ford算法,比如下面这种 题目 给定…

混合密度网络Mixture Density Networks(MDN)

目录 简介1 介绍2 实现3 几个MDN的应用:参考 简介 平方和或交叉熵误差函数的最小化导致网络输出近似目标数据的条件平均值,以输入向量为条件。对于分类问题,只要选择合适的目标编码方案,这些平均值表示类隶属度的后验概率&#x…

《程序猿入职必会(10) · SpringBoot3 整合 MyBatis-Plus》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…