常见哈希算法、Hmac算法和BouncyCastle

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

作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。
哈希算法最重要的特点就是:
1.相同的输入一定得到相同的输出
2.不同的输入大概率得到不同的输出(可能会出现哈希碰撞,即不同输出得到相同输出)

哈希算法可以验证原始数据是否被篡改,所以可以用来校验下载文件,另外还可以用来存储用户密码。

但因为相同的输入通过哈希算法会得到相同的结果,所以简单的密码和口令在数据泄露容易遭到彩虹表攻击(彩虹表即常用口令和他们MD5的对照表),数据泄露时常用口令很容易通过MD5被反查到。

当然我们可以对要进行哈希算法的口令额外增加随机数,这个方法称为“加盐”,可以有效增加密码和口令的安全性。

常用的哈希算法

算法 输出长度(位)输出长度(字节)
MD5  128bits16bytes
SHA-1160bits20bytes
RipeMD-160160bits20bytes
SHA-256256bits32bytes
SHA-512512bits64bytes

MD5算法为例,在用MD5进行编码时,首先需要根据编码方式创建MessageDigest实例,然后调用update(byte[ ])更新原始数据,再通过digest()方法获得byte[ ]形式的加密后的结果 ,最后转化为十六进制的字符串。

具体代码如下:

package com.gjh.demo02;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Text02 {
	public static void main(String[] args) {
		
		try {
			String password="wbjxxmynhmyzgq123";
			//获取基于MDS加密算法的工具对象
			MessageDigest digest=MessageDigest.getInstance("MD5");
			//更新原始数据
			digest.update(password.getBytes());
			//获取加密后的结果
			byte[] resultByteArray=digest.digest();
			
			System.out.println(resultByteArray);
			System.out.println(resultByteArray.length);
			StringBuilder result1=new StringBuilder();
			for(byte resultByte:resultByteArray) {
				result1.append(String.format("%02x", resultByte));
			}
			System.out.println(result1);
			System.out.println(result1.length());
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		
	}

}

可以看到以下是它的实现结果:

由于转化为十六进制的字符串时,我们设置一个字节占2个字符,所以得到的字符串长度为32个字符

SHA-1算法的编码方式与MD5完全一致,只需要在创建MessageDigest实例时将编码方式改为"SHA-1"

以下为MD5和SHA-1算法结果长度的对比的代码:

package com.gjh.demo02;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

public class Text04 {
	public static void main(String[] args)  {
	
		String password="wxshfg";
		String salt="acsvd";
		try {
			MessageDigest digest=MessageDigest.getInstance("SHA-1");
			MessageDigest digest1=MessageDigest.getInstance("MD5");
			
			digest.update(password.getBytes());
			digest.update(salt.getBytes());
			
			digest1.update(password.getBytes());
			digest1.update(salt.getBytes());
			
			byte[] result=digest.digest();
			byte[] result1=digest1.digest();
			System.out.println("使用SHA-1的byte数组result值");
			System.out.println(result);
			System.out.println(result.length);
			System.out.println("使用MD5的byte数组result值");
			System.out.println(result1);
			System.out.println(result1.length);
			
			StringBuilder sb=new StringBuilder();
			for(byte b:result) {
				sb.append(String.format("%02x", b));
			}
			StringBuilder sb1=new StringBuilder();
			for(byte b1:result1) {
				sb1.append(String.format("%02x", b1));
			}
			System.out.println("使用SHA-1的StringBuilder值");
			System.out.println(sb);
			System.out.println(sb.length());
			System.out.println("使用MD5的StringBuilder值");
			System.out.println(sb1);
			System.out.println(sb1.length());
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
	}

}

 可以看到以下是它的实现结果:

Hmac算法

Hmac算法是一种基于密钥的消息认证码算法,是一种更安全的消息摘要算法。
Hmac算法总是和某种哈希算法配合起来用的。例如,我们使用MD5算法,对应的就是Hmac MD5算法,它相当于“加盐”的MD5。

HmacMD5与MD5相比

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

在用HmacMD5进行编码时,首先需要根据编码方式创建KeyGenerator实例,KeyGenerator实例再调用generateKey()方法获取秘钥key,通过key.getEncoded()获取秘钥key的字节数组,再将其转化为十六进制的字符串。

在加密过程,需要通过名称HmacMD5获取Mac实例,对Mac实例调用update(byte[ ])输入要进行加密的数据,再调用Mac实例的doFinal()获得最终的哈希值,再将其转化为十六进制的字符串。

具体代码如下:

package com.gjh.demo03;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;

public class Text01 {
	public static void main(String[] args)  {
		String password="nhmyzgq";
		try {
			//1.生成秘钥
			//2.秘钥生成器keyGenerator
			KeyGenerator keyGe=KeyGenerator.getInstance("HmacMD5");
			//生成秘钥
			SecretKey key=keyGe.generateKey();
			//获取秘钥key的字节数组(64)
			byte[] ketByteArray=key.getEncoded();
			System.out.println(ketByteArray);
			System.out.println("秘钥的长度"+ketByteArray.length+"字节");
			
			StringBuilder sb=new StringBuilder();
			for(byte b:ketByteArray) {
				sb.append(String.format("%02x", b));
			}
			System.out.println("秘钥的内容"+sb);
			System.out.println(sb.length());
			
			Mac mac=Mac.getInstance("HmacMD5");
			mac.init(key);
			//更新原始内容
			mac.update(password.getBytes());
			//加密
			byte[] resultByteArray=mac.doFinal();
			System.out.println("加密结果"+resultByteArray.length+"字节");
			StringBuilder resultStr=new StringBuilder();
			for(byte by:resultByteArray) {
				resultStr.append(String.format("%02x", by));
			}
			
			System.out.println("加密结果:"+resultStr);
			System.out.println("加密结果长度:"+resultStr.length());
			
			
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
	}

}

 可以看到以下是它的实现结果:

除了通过Hmac计算的秘钥,也可以通过指定的字节数组恢复秘钥,恢复秘钥的语句就是new SecretKeySpec(hkey, "HmacMD5")。

具体代码如下:

package com.gjh.demo03;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class Text02 {
	public static void main(String[] args) {
		String password="nhmyzgq";
		try {
			byte[] keyByteArray= {126, 49, 110, 126, -79, -5, 66, 34, -122, 123, 107, -63, 106, 100, -28, 67, 19, 23, 1, 23, 47, 63, 47, 109, 123, -111, -27, -121, 103, -11, 106, -26, 110, -27, 107, 40, 19, -8, 57, 20, -46, -98, -82, 102, -104, 96, 87, -16, 93, -107, 25, -56, -113, 12, -49, 96, 6, -78, -31, -17, 100, 19, -61, -58};
			SecretKey key=new SecretKeySpec(keyByteArray ,"HmacMD5");
			Mac mac=Mac.getInstance("HmacMd5");
			mac.init(key);
			mac.update(password.getBytes());
			byte[] resultByteArray=mac.doFinal();
			StringBuilder resultStr=new StringBuilder();
			for(byte b:resultByteArray) {
				resultStr.append(String.format("%02x", b));
			}
			System.out.println("加密结果"+resultStr);
			
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
		
	}

}

 BouncyCastle

BouncyCastle是一个提供了很多哈希算法和加密算法的第三方开源库。它提供了很多Java标准库没有提供的哈希算法和加密算法,例如,RipeMD160哈希算法。

与MD5算法不同的是,我们要使用BouncyCastle提供的RipeMD160算法,需要先注册BouncyCastle提供的通知类对象BouncyCastleProvider

具体代码如下:

package com.gjh.demo;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;

public class Text01 {
	public static void main(String[] args) {
		try {
			//注册BouncyCastle提供的通知类对象BouncyCastleProvider
			Security.addProvider(new BouncyCastleProvider());
			//获取RipeMD160算法的“消息摘要对象”(加密对象)
			MessageDigest msg=MessageDigest.getInstance("RipeMD160");
			//更新原始数据
			msg.update("hello".getBytes());
			//获取消息摘要(加密)
			byte[] result=msg.digest();
			//消息摘要的字节长度和内容
			System.out.println(result);   //160位=20字节
			System.out.println(result.length);
			//16进制内容字符串
			String hex=new BigInteger(1,result).toString();   //20字节,40个字符,按一个字节占2个字符
			System.out.println(hex);
			
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		
	}

}

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值