Java哈希算法

news2024/11/24 0:37:08

哈希算法

  • 哈希算法
    • 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: 68e109f0f40ca72a15e05cc22786f8e6
        byte[] 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: db8ac1c259eb89d4a131b253bacfca5f319d54f2
        byte[] 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.coloradmin.cn/o/1987026.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OrangePi AIpro学习3 —— vscode开发昇腾DVPP程序

目录 一、VScode配置 1.1 下载和安装 1.2 安装和配置需要的插件 二、构建项目 2.1 项目架构 2.2 解决代码高亮显示 2.3 测试编译 2.4 总结出最简单的代码 2.5 vscode报错找不到头文件解决方法 三、代码简单讲解 3.1 初始化部分 3.2 拷贝数据到NPU显存中 3.3 准备裁…

Leetcode每日一题之仅仅反转字母(C++)

在学习之余对于知识的巩固也尤为重要,不论难度高低,都会对代码的理解有所加深,下面我们开始练习 思路解析 关于本题的核心思路就是如何判断字符串中元素是否为字母以及如何遍历字符串以达到仅反转的目的,这里用到的知识就是关于 s…

【数据结构与算法 | 二叉树篇】AVL树

1. 前言 AVL树是一种自平衡的二叉搜索树。为什么会出现AVL树。众所周知,虽然普通的二叉搜索树的平均时间复杂度为O(logn),但最差的情况的时间复杂度为O(n)。为了避免最差的这种情况,出现了AVL树。 我们规定:如果树有个节点它的左…

大模型LLM——微调的七种方法

大模型的七种微调方法 文章目录 大模型的七种微调方法1. LoRA2. QLoRA3. 适配器调整4. 前缀调整5. 提示调整6. P-Tuning7. P-Tuning v2 1. LoRA LoRA的主要步骤包括: 选择微调目标权重矩阵:首先在大型模型(如GPT)中识别需要微调…

学习vue3 五,传送,缓存组件以及过渡和过渡列表

目录 Teleport传送组件 keep-alive缓存组件 transition动画组件 1. 过渡的类名 2. 自定义过渡class名 3. transition的生命周期 4.appear transition-group 1. 过渡列表 2. 列表的移动过渡 3. 状态过渡 Teleport传送组件 Teleport Vue 3.0新特性之一。 Teleport 是一…

AI技术如何重塑企业EHS安全健康环保体系,附实践案例

随着人工智能技术的快速发展,其在环境、健康和安全(EHS)管理领域的应用日益广泛。AI技术通过大数据分析、模式识别和预测建模等手段,为EHS管理提供了新的视角和工具。这一变革不仅提升了风险评估和事故预防的效率,同时…

Can‘t use Subversion command line client:svn不能使用Subversion命令行客户端:svn

1、导入idea中会报Can’t use Subversion command line client… 2、在提交svn代码的时候,出现这样的错误:Can’t use Subversion command line client: svn Probably the path to Subversion executable is wrong. Fix it. 问题原因:在安…

实验8-1-4 拆分实数的整数与小数部分

本题要求实现一个拆分实数的整数与小数部分的简单函数。 函数接口定义&#xff1a; void splitfloat( float x, int *intpart, float *fracpart );其中x是被拆分的实数&#xff08;0≤x<10000&#xff09;&#xff0c;intpart和fracpart分别是将实数x拆分出来的整数部分与…

sqli-labs1-24通关教程

目录 前置知识 第一关 1、第一关是单引号字符型注入,输入id1‘会报错 2、输入注释符正常显示 3、爆出列数为联合做准备 4、使用联合查询爆出数据库名 5、使用information_schema爆出表名 6、猜测用户名再users表中&#xff0c;爆出列名 ​编辑 7、利用查出来的表名数据…

【第2期】2024 搜索客 Meetup | Elasticsearch 的代码结构和写入查询流程的解读

本次活动由 搜索客社区、极限科技&#xff08;INFINI Labs&#xff09;联合举办&#xff0c;活动主题将深入探讨 Elasticsearch 的两个核心方面&#xff1a;代码结构以及写入和查询的关键流程。本次活动将为 Elasticsearch 初学者和有经验的用户提供宝贵的见解&#xff0c;欢迎…

叉车(工业车辆)安全监控管理系统,叉车安全方案

叉车作为特种设备的一种&#xff0c;存在一定的危险性&#xff0c;操作过程出现意外的情况可谓是不胜枚举&#xff0c;轻则伤财、受些皮外伤&#xff0c;重则直接致人死亡。为加强叉车操作的安全管理&#xff0c;从2023年12月1日起实施的TSG 81-2022《场&#xff08;厂&#xf…

【网络安全学习】SQL注入02:使用sqlmap进行注入

1.sqlmap的基本功能 sqlmap的基本功能是对Web应用中的数据库进行自动化的检测、利用和攻击。 使用pikachu靶场进行sqlmap的基础功能使用。 1️⃣ 第一步&#xff1a;先检查是否有注入点&#xff1a; # -u : 指定目标url&#xff0c;也就是指定注入点 sqlmap -u "http:…

终端命令行|CLI工具|CMD|PowerShell

基本概念 终端是一个文本界面&#xff0c;用于执行基于文本的程序。 果你正在运行任何用于 web 开发的工具&#xff0c;你一定需要打开命令行并运行一些命令来使用你所选择的工具 (这样的工具被称为CLI 工具也就是命令行接口工具)。 命令行接口工具 (CLI 工具) 是什么&#xf…

延伸--人工鱼群算法

目录 基本原理 改进策略 代码示例 应用实例 总结 人工鱼群算法在解决多峰函数问题中的具体应用案例和效果如何&#xff1f; 双群人工鱼群算法与传统人工鱼群算法相比&#xff0c;有哪些具体的改进和优势&#xff1f; 步长自适应调整在人工鱼群算法中的实现机制是什么&a…

vue3踩坑问题记录

//vue3element-plus //1、placeholder换行显示 const startTxt ref() const contentText ref<any>() startTxt.value "请描述问题内容、例如&#xff1a;" historyData.prompt.forEach((el:any)>{contentText.value \n${el.question}}) <ElInputv-mo…

点赞收藏测试文章(让我看看有多少机器人在刷互动量)

前言 这里有一些看似合理但实际毫无意义的句子&#xff0c;我需要用它来看看跟我互动的有多少机器人 如果你是人类用户&#xff0c;可以用评论来代替点赞&收藏&#xff0c;爱你~ 目录 前言 正文 1. 紫色的大象在夜空中游泳。 2. 月亮上的饼干师烤出了一片海洋。 3. 时…

数据结构(邓俊辉)学习笔记】词典 03—— 排解冲突(1)

文章目录 1. 一山二虎2. 泾渭分明3. 开放定址4. 线性试探5. 赖惰删除 1. 一山二虎 此前我们已经多次指出&#xff0c;对于需要动态维护的散列表冲突是不可避免的&#xff0c;无论你的散列函数设计的有多么精妙&#xff0c;因此我们不得不回答的第二个重要问题就是一旦发生冲突&…

苹果电脑维护工具:CleanMyMac X让你的Mac焕发新生!

在我们的数字生活中&#xff0c;苹果电脑&#xff08;Mac&#xff09;已成为不可或缺的一部分&#xff0c;无论是为工作披星戴月&#xff0c;还是为娱乐畅游云端。但是&#xff0c;就像任何长时间运行的机器一样&#xff0c;Mac也可能会因为积累的文件和不必要的数据而开始变慢…

DAMA学习笔记(十一)-元数据管理

1.引言 元数据最常见的定义是“关于数据的数据”。它描述了数据本身&#xff08;如数据库、数据元素、数据模型&#xff09;&#xff0c;数据表示的概念&#xff08;如业务流程、应用系统、软件代码、技术基础设施&#xff09;&#xff0c;数据与概念之间的联系&#xff08;关系…

60页PPT数据湖 + 数据中台实施方案

关注智慧方案文库&#xff0c;学习8700多份智慧城市&#xff0c;智慧医院&#xff0c;智能制造&#xff0c;数字化转型&#xff0c;新质生产力&#xff0c;算力&#xff0c;大模型&#xff0c;AIGC&#xff0c;工业互联网&#xff0c;数字孪生......持续更新热点行业解决方案。…