哈希算法总结!!!

2023-11-03

哈希算法(Hash)又称摘要算法(Digest)。

作用:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。
最重要的特点:

  • 相同的输入一定得到相同的输出。
  • 不同的输入大概率得到不同的输出。

哈希算法的目的:为了验证原始数据是否被篡改。

哈希算法的用途:校验下载文件、存储用户密码

 哈希碰撞

哈希碰撞:两个不同的输入得到相同的输出。(eg.“通话”和“重地”)

哈希算法的输出长度越长,就越难产生碰撞,也就越安全。

常用的哈希算法
算法 输出长度(位/bits) 输出长度(字节/bytes)
MD5 128 16
SHA-1 160 20
RipeMD-160 160 20
SHA-256 256 32
SHA-512 512 64

哈希算法消息摘要算法工具类

定义一个哈希算法消息摘要算法工具类 HashTools便于使用。

public class HashTools {

	private static MessageDigest digest;

	private void HashTools() {
	}

	// 将字节数组转换为16进制字符串
	public static String bytesToHex(byte[] bytes) {
		StringBuilder ret = new StringBuilder();
		for (byte b : bytes) {
			// 将字节值转换为2位十六进制字符串
			ret.append(String.format("%02x", b));
		}
		return ret.toString();
	}
}

一、MD5和SHA-1算法

 在Java中SHA-1和MD5是在使用上是完全一样的,只是它们的算法名称和输出长度不一样而已。 

(1)对字符串进行加密

使用MessageDigest时,要先根据MD5(哈希算法)获取一个MessageDigest实例,调用update()方法跟新原始数据。调用digest()方法获得byte[]数组表示的摘要。通过调用HashTools哈希算法消息摘要算法工具类的方法,转换成16进制的字符串。

public class Demo01 {
	public static void main(String[] args) throws NoSuchAlgorithmException {
		//创建基于MD5算法的消息摘要对象
		MessageDigest md5=MessageDigest.getInstance("MD5");
		
		//更新原始数据
		md5.update("搏得明月出,用兰花换锦服".getBytes());
		
		//获取加密后的结果
		byte[] digestBytes=md5.digest();
		System.out.println("加密后的结果(字节数组):"+Arrays.toString(digestBytes));
		System.out.println("加密后的结果(16进制字符串):"+HashTools.bytesToHex(digestBytes));
		System.out.println("加密结果的长度:"+digestBytes.length);
	}	
}

 注!!!相同的输入一定会得到相同的输出

如下图两种输入方式得到的结果是一样

		//方式一
		md5.update("博得明月出,用兰花换锦服".getBytes());
		
        //方式二
        md5.update("博得明月出,".getBytes());
		md5.update("用兰花换锦服".getBytes());

(2)对图片进行加密 

 通过Files工具类的readAllBytes()方法获取到图片的原始字节内容数组。

public class Demo03 {
	public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
		//图片的原始字节内容
		byte[] imageBuf=Files.readAllBytes(Paths.get("D:\\test\\20230521\\mao1.jpg"));
		
		//创建基于算法的消息摘要对象
		MessageDigest md5=MessageDigest.getInstance("MD5");
		
		//原始字节内容
		md5.update(imageBuf);
		
		//获取加密摘要
		byte[] digestBytes=md5.digest();
		System.out.println("加密后的结果(字节数组):"+Arrays.toString(digestBytes));
		System.out.println("加密后的结果(16进制字符串):"+HashTools.bytesToHex(digestBytes));
		System.out.println("加密结果的长度:"+digestBytes.length);  //MD5算法的固定输出长度为16个字节	
	}
}

(3)加盐

彩虹表是一个用于加密散列函数逆运算的预先计算好的表, 为破解密码的散列值(或称哈希值、微缩图、摘要、指纹、哈希密文)而准备的。

为了 抵御彩虹表的攻击,对每个口令添加额外的随机数,使得输出的结果不同。故而,即使是相同的输入内容,得到的输出结果却各不相同。

public class Demo04 {
	public static void main(String[] args) throws NoSuchAlgorithmException {
		//原始密码
		String password="xdsqczkyqs";
		
		//产生随机的盐值
		String salt=UUID.randomUUID().toString().substring(0,4);
		
		//创建基于SHA-1算法的消息摘要对象
		MessageDigest sha1=MessageDigest.getInstance("SHA-1");
		sha1.update(password.getBytes());
		sha1.update(salt.getBytes());
		
		
		//计算加密结果SHA-1的输出结果为20个字节(40)
		String digestHex=HashTools.bytesToHex(sha1.digest());
		System.out.println(digestHex);
	}
}

不加盐的输出结果:9ad8b1bf7c6f9cfb97b81725aa585cd22d8cc977 

加盐后的输出结果:3429c69bd1a48a17313e9ec089193b5fcea6a313 

(4)MD5和SHA-1的输出长度不同

完善工具类,由上文可知,两个算法的使用有很多代码都是一样的,避免冗余故而封装到一个工具类里。

public class HashTools {

	private static MessageDigest digest;

	private void HashTools() {
	}

	// 按照MD5进行消息摘要计算(哈希计算)
	public static String digestByMD5(String source) throws NoSuchAlgorithmException {
		digest = MessageDigest.getInstance("MD5");
		return handler(source);
	}

	// 按照SHA-1进行消息摘要计算(哈希计算)
	public static String digestBySHA1(String source) throws NoSuchAlgorithmException {
		digest = MessageDigest.getInstance("SHA1");
		return handler(source);
	}

	// 通过消息摘要对象处理加密内容
	private static String handler(String source) {
		digest.update(source.getBytes());
		byte[] bytes = digest.digest();
		String hash = bytesToHex(bytes);
		return hash;
	}

	// 将字节数组转换为16进制字符串
	public static String bytesToHex(byte[] bytes) {
		StringBuilder ret = new StringBuilder();
		for (byte b : bytes) {
			// 将字节值转换为2位十六进制字符串
			ret.append(String.format("%02x", b));
		}
		return ret.toString();
	}
}

比较两个算法的输出内容

public class Demo05 {
	public static void main(String[] args) {
		try {
			String md5=HashTools.digestByMD5("xdsqczkyqs");
			String sha1=HashTools.digestBySHA1("xdsqczkyqs");
			
			System.out.println("md5="+md5);
			System.out.println("sha1="+sha1);
			
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
	}
}

输出结果!!!两种算法的输出长度不同

md5=f27c71d02ab0444ce454a13d902f2571
sha1=9ad8b1bf7c6f9cfb97b81725aa585cd22d8cc977 

二、Hmac算法

Hmac 算法就是一种基于密钥的消息认证码算法,它的全称是 Hash-based Message Authenticati on Code,是一种更安全的消息摘要算法。
Hmac 算法总是和某种哈希算法配合起来用的。例如,我们使用MD5 算法,对应的就是Hmac MD5 算法,它相当于“加盐”的MD5。HmacMD5可以看作带有一个安全的key的MD5。

使用 HmacMD5 而不是用 MD5 加 salt有如下好处:

  • HmacMD5使用的 key 长度是 64 字节,更安全。
  • Hmac是标准算法,同样适用于 SHA-1 等其他哈希算法。
  • Hmac 输出和原有的哈希算法长度一致。

(1)对字符串通过密钥进行加密 

通过KeyGenerator获取HmacMD5密钥生成器,生成随机密钥并打印。通过名称 HmacMD5获取 Mac 实例,用 Secretkey 初始化Mac实例,对 Mac实例调用 update(byte[])输入字符串的字节数组数据,调用Mac 实例的 doFinal()获取最终的哈希值。通过调用哈希算法消息摘要算法工具类的方法,获取加密后的字符串。

public class Demo06 {
	public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
		String password="xdsqczkyqs";

		//获取HmacMD5密钥生成器
		KeyGenerator keyGen=KeyGenerator.getInstance("HmacMD5");
		
		//生成随机密钥
		SecretKey key=keyGen.generateKey();
		System.out.println("密钥:"+Arrays.toString(key.getEncoded()));
		System.out.println("密钥长度:"+key.getEncoded().length);
		System.out.println("密钥:"+HashTools.bytesToHex(key.getEncoded()));
		
		//使用密钥进行加密
		//获取HMac加密算法对象
		Mac mac=Mac.getInstance("HmacMD5");
		mac.init(key);   //初始化密钥
		mac.update(password.getBytes());
		byte[] bytes=mac.doFinal();
		String result=HashTools.bytesToHex(bytes);
		System.out.println();
		System.out.println("加密结果16进制字符串:"+result);
		System.out.println("加密结果(字节长度16字节):"+bytes.length);
		System.out.println("加密结果(字节长度32字符):"+result.length());
		
	}
}

 

 (2)恢复密钥

在加密是记录密钥的数据 ,以下使用数据均为上图中的数据!

通过密钥的字节数组

public class Demo07 {
	public static void main(String[] args) {
		//原始密码
		String password="xdsqczkyqs";
		
		
		//密钥(字节数组)
		byte[] keyBytes= {-6, -128, 50, 95, -52, 65, -72, 32, -68, -77, -18, 104, 20, -59, -42, -39, 70, 70, 56, -96, -112, -126, 65, 37, 124, 8, 34, 71, -87, 39, -42, 106, 81, -114, -63, -92, -31, 25, -78, 104, -87, -4, -23, 91, -48, -123, 31, 82, 42, 85, 107, -5, 21, 30, 11, 105, 93, 52, 44, -68, -118, 88, 83, 28};
		
		
		
		try {
			//恢复密钥
			SecretKey key=new SecretKeySpec(keyBytes, "HmacMD5");
			
			//创建Hmac加密算法对象
			Mac mac=Mac.getInstance("HmacMD5");
			mac.init(key);
			mac.update(password.getBytes());
			String result=HashTools.bytesToHex(mac.doFinal());
			
			System.out.println(result);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		}
	}

}

通过密钥的字符串 

public class Demo07 {
	public static void main(String[] args) {
		//原始密码
		String password="xdsqczkyqs";
		
		
		//密钥(字符串)
		String keyStr="fa80325fcc41b820bcb3ee6814c5d6d9464638a0908241257c082247a927d66a518ec1a4e119b268a9fce95bd0851f522a556bfb151e0b695d342cbc8a58531c";
		
		//用于保存密钥密钥长度为64字节
		byte[] keyBytes=new byte[64];
		
		for(int i=0,k=0;i<keyStr.length();i+=2,k++) {
			String s=keyStr.substring(i,i+2);
			keyBytes[k]=(byte) Integer.parseInt(s, 16);
		}
		
		
		try {
			//恢复密钥
			SecretKey key=new SecretKeySpec(keyBytes, "HmacMD5");
			
			//创建Hmac加密算法对象
			Mac mac=Mac.getInstance("HmacMD5");
			mac.init(key);
			mac.update(password.getBytes());
			String result=HashTools.bytesToHex(mac.doFinal());
			
			System.out.println(result);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		}
	}

}

 三、RipeMD160算法

输出值一般是16进制的字符串 

使用该算法时需要导入一个jar包。bcprov-jdk15on-1.70.jar

下载地址:https://mvnrepository.com/search?q=bcprov-jdk15on-1.70.jar

public class Demo08 {
	public static void main(String[] args) throws NoSuchAlgorithmException {
		//注册BouncyCastleProvider通知类
		//将提供的消息摘要算法注册至Security
		Security.addProvider(new BouncyCastleProvider());
		
		//获取RipeMD160算法的消息摘要对象(加密对象)
		MessageDigest ripeMd160=MessageDigest.getInstance("RipeMD160");
		
		//更新原始数据
		ripeMd160.update("xdsqczkyqs".getBytes());
		
		//获取消息摘要(加密)
		byte[] result=ripeMd160.digest();
		
		//消息摘要字节长度和内容
		String hex=new BigInteger(1, result).toString(16);
		System.out.println("加密结果(字符串长度):"+hex.length());
		System.out.println("加密结果(字符串内容):"+hex);
	}

}

加密结果(字符串长度):40
加密结果(字符串内容):71949ee603bf28cbc82b5ee91e67044f8f456026 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

哈希算法总结!!! 的相关文章

  • 如何为最终用户方便地启动Java GUI程序

    用户想要从以下位置启动 Java GUI 应用程序Windows 以及一些额外的 JVM 参数 例如 javaw Djava util logging config file logging properties jar MyGUI jar
  • 在画布上绘图

    我正在编写一个 Android 应用程序 它可以在视图的 onDraw 事件上直接绘制到画布上 我正在绘制一些涉及单独绘制每个像素的东西 为此我使用类似的东西 for int x 0 x lt xMax x for int y 0 y lt
  • 在 java 类和 android 活动之间传输时音频不清晰

    我有一个android活动 它连接到一个java类并以套接字的形式向它发送数据包 该类接收声音数据包并将它们扔到 PC 扬声器 该代码运行良好 但在 PC 扬声器中播放声音时会出现持续的抖动 中断 安卓活动 public class Sen
  • 如何找到给定字符串的最长重复子串

    我是java新手 我被分配寻找字符串的最长子字符串 我在网上研究 似乎解决这个问题的好方法是实现后缀树 请告诉我如何做到这一点或者您是否有任何其他解决方案 请记住 这应该是在 Java 知识水平较低的情况下完成的 提前致谢 附 测试仪字符串
  • INSERT..RETURNING 在 JOOQ 中不起作用

    我有一个 MariaDB 数据库 我正在尝试在表中插入一行users 它有一个生成的id我想在插入后得到它 我见过this http www jooq org doc 3 8 manual sql building sql statemen
  • 无法展开 RemoteViews - 错误通知

    最近 我收到越来越多的用户收到 RemoteServiceException 错误的报告 我每次给出的堆栈跟踪如下 android app RemoteServiceException Bad notification posted fro
  • 控制Android的前置LED灯

    我试图在用户按下某个按钮时在前面的 LED 上实现 1 秒红色闪烁 但我很难找到有关如何访问和使用前置 LED 的文档 教程甚至代码示例 我的意思是位于 自拍 相机和触摸屏附近的 LED 我已经看到了使用手电筒和相机类 已弃用 的示例 但我
  • 反射找不到对象子类型

    我试图通过使用反射来获取包中的所有类 当我使用具体类的代码 本例中为 A 时 它可以工作并打印子类信息 B 扩展 A 因此它打印 B 信息 但是当我将它与对象类一起使用时 它不起作用 我该如何修复它 这段代码的工作原理 Reflection
  • Liferay ClassNotFoundException:DLFileEntryImpl

    在我的 6 1 0 Portal 实例上 带有使用 ServiceBuilder 和 DL Api 的 6 1 0 SDK Portlet 这一行 DynamicQuery query DynamicQueryFactoryUtil for
  • 无法解析插件 Java Spring

    我正在使用 IntelliJ IDEA 并且我尝试通过 maven 安装依赖项 但它给了我这些错误 Cannot resolve plugin org apache maven plugins maven clean plugin 3 0
  • 禁止的软件包名称:java

    我尝试从数据库名称为 jaane 用户名 Hello 和密码 hello 获取数据 错误 java lang SecurityException Prohibited package name java at java lang Class
  • Java按日期升序对列表对象进行排序[重复]

    这个问题在这里已经有答案了 我想按一个参数对对象列表进行排序 其日期格式为 YYYY MM DD HH mm 按升序排列 我找不到正确的解决方案 在 python 中使用 lambda 很容易对其进行排序 但在 Java 中我遇到了问题 f
  • Java Integer CompareTo() - 为什么使用比较与减法?

    我发现java lang Integer实施compareTo方法如下 public int compareTo Integer anotherInteger int thisVal this value int anotherVal an
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • 如何从指定日期获取上周五的日期? [复制]

    这个问题在这里已经有答案了 如何找出上一个 上一个 星期五 或指定日期的任何其他日期的日期 public getDateOnDay Date date String dayName 我不会给出答案 先自己尝试一下 但是 也许这些提示可以帮助
  • Java列表的线程安全

    我有一个列表 它将在线程安全上下文或非线程安全上下文中使用 究竟会是哪一个 无法提前确定 在这种特殊情况下 每当列表进入非线程安全上下文时 我都会使用它来包装它 Collections synchronizedList 但如果不进入非线程安
  • 如何从泛型类调用静态方法?

    我有一个包含静态创建方法的类 public class TestClass public static
  • 声明的包“”与预期的包不匹配

    我可以编译并运行我的代码 但 VSCode 中始终显示错误 早些时候有一个弹出窗口 我不记得是什么了 我点击了 全局应用 从那以后一直是这样 Output is there but so is the error The declared
  • 使用 JMF 创建 RTP 流时出现问题

    我正处于一个项目的早期阶段 需要使用 RTP 广播DataStream创建自MediaLocation 我正在遵循一些示例代码 该代码目前在rptManager initalize localAddress 出现错误 无法打开本地数据端口
  • 如何修复 JNLP 应用程序中的“缺少代码库、权限和应用程序名称清单属性”?

    随着最近的 Java 更新 许多人都遇到了缺少 Java Web Start 应用程序的问题Codebase Permissions and Application name体现属性 尽管有资源可以帮助您完成此任务 但我找不到任何资源综合的

随机推荐

  • Python序列以及切片操作

    1 序列 序列是一个用于存储多个值的连续空间 每个值都对应一个整数编号 称为索引 序列结构主要有列表 元组 集合 字典和字符串 2 索引 正向递增索引 取值范围 0 N 1 反向递减索引 取值范围 1 N 下面我们用索引遍历一下字符串序列
  • 头歌课堂练习5:进程的同步与互斥

    第一关 多线程编程 创建多线程的函数pthread create原型如下 pthread create pthread t tidp const pthread attr t attr void start rtn void void ar
  • Python编写一个函数cacluate, 可以接收任意多个数,返回的是一个元组.元组的第一个值为所有参数的平均值, 第二个值是大于平均值的所有数

    编写一个函数cacluate 可以接收任意多个数 返回的是一个元组 元组的第一个值为所有参数的平均值 第二个值是大于平均值的所有数 详细代码见链接 共同学习 加油 文末有知识点分析 文章所使用的知识点if lese语句 if 条件1 pri
  • js+mysql实现论坛回复功能_php实现简单BBS论坛及回复

    实例简介 该资源主要参考http blog csdn net eastmount article details 44241583文章 讲述了如何通过PHP实现论坛搭建简单的效果 同时包括IFrame实现局部布局 后台数据库通过SAE搭建
  • 2022年 软件工程专业 计算机组成原理 运算器实验报告

    年级 班号 组号 学号 专业 软件工程 日期 2022 年 5 月 11日 姓名 预判你的代码 实验名称 运算器 实验室 实验 目的 或 要求 1 了解运算器的组成结构 2 掌握运算器的工作原理 3 熟悉运算器的设计方法 4 掌握运算器的控
  • AndroidManifest.xml文件综合详解

    http www cnblogs com hnrainll archive 2011 10 26 2225710 html 一 重要性AndroidManifest xml是Android应用程序中最重要的文件之一 它是Android程序的
  • Zend Studio 12 安装及破解

    1 安装 1 1 下载最新版本Zend Studio 12 0 0 http downloads zend com studio eclipse 12 0 0 ZendStudio 12 0 0 win32 win32 x86 msi 12
  • Android10填坑适配指南,实际经验代码,拒绝翻译

    Android10填坑适配指南 包含实际经验代码 绝不照搬翻译文档 1 Region Op相关异常 java lang IllegalArgumentException Invalid Region Op only INTERSECT an
  • 2021年南京天印中学高考成绩查询,2021年南京高中录取分数线是多少及高中排名榜...

    2020年南京的高中录取分数线都已经公布 以下是小编给大家整理的汇总信息 仅供参考 一 2020年南京高中录取分数线是多少 一 科技特长生 学科特长生 科技特长生和学科特长生投档控制线均为548分 二 普通高中指标生 原市区普通高中指标生录
  • STM32——超声波模块

    模块介绍 超声波模块一般使用的都是HC SR04来进行测距 1 产品特点 HC SR04 超声波测距模块可提供 2cm 400cm 的非接触式距离感测功能 测 距精度可达高到的非接触式距离感测功能 测距精度可达高到 3mm 模块包括超声波发
  • 期货用期权对冲(期货用期权对冲吗)

    怎么用期权 option 做对冲 hedge 在期权交易市场中 对冲期权风险可以通过交易不同的合约方向 使用组合策略对自己合约盈利或者合约的亏损进行一个风险对冲 这样可以降低期权交易市场中的风险 在期权交易市场中 投资者一般也会将期权用作对
  • Java 静态变量,静态方法,静态常量简介说明

    转自 Java 静态变量 静态方法 静态常量简介说明 下文笔者将着重讲述静态的相关说明 如下所示 实现思路 当我们在方法 变量 常量前面加上static关键字 则可认为其是一个静态的对象 静态方法注意事项 静态方法不可以使用this关键字
  • 去AV片马赛克,开发者被抓了

    来源丨程序员软件库 怎么去除图片或者视频上的马赛克 自从马赛克这玩意被弄出来后 让大家悲喜交加 你想在社交软件上发一些图片或者视频 有部分比较隐私的东西 那就需要使用马赛克技术遮挡下 保护下自己隐私或者别人隐私是非常好的 比如 新闻在拍摄报
  • python爬取美女图片

    需求 最近对python爬虫感兴趣 于是也依葫芦画瓢试着用爬虫爬取之前喜欢的网站上的美女图片 网站 http www mm131 com xinggan 其中每一套图都是一张一个页面 存一套图如果是手动得点翻几十个页面 但现在用爬虫的话 就
  • 用python算24点及原理详解

    1 描述 给出4个正整数 使用加 减 乘 除4种运算以及括号把4个数连接起来得到一个结果等于24的表达式 注 这里加 减 乘 除以及括号的运算结果和运算优先级跟平常定义一致 例如 对于5 5 5 1 可知 5 5 1 5 24 又如 对于
  • 连接Nacos的服务程序快速无限打日志longPolling、ClientWorker

    问题 一个微服务环境里很多服务启动以后疯狂打日志 日志是从nacos更新配置 日志 星号脱敏ip 端口 com alibaba nacos client Worker longPolling fixed 10 public ClientWo
  • [极客大挑战 2019]LoveSQL

    考点 常规的sql注入 1 万能密码测试 2 解不了码 没用 3 但是可以注入 测试回显几个字段名 慢慢试 4 爆数据库名和用户名 5 爆库名 6 爆表名 1 union select 1 2 group concat table name
  • 树莓派4b之初学者入门人脸识别(手把手完整版)

    目录 前言 硬件配置 一 烧录镜像和环境配置 二 代码详解 1 基础知识 2 相关代码及其详细注释 三 代码部署和运行 前言 树莓派的性能日益强大 树莓派4b相比上一代的能有了很大的提升 采用了博通最新的BCM4908 64bit处理器 内
  • nginx限流配置

    限流 Rate Limitting 是服务降级的一种方式 通过限制系统的输入和输出流量以达到保护系统的目的 比如我们的网站暴露在公网环境中 除了用户的正常访问 网络爬虫 恶意攻击或者大促等突发流量都可能都会对系统造成压力 如果这种压力超出了
  • 哈希算法总结!!!

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