基础概要知识
消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文.
因此可以对数据传输前后进行两次消息摘要,相同的内容摘要一定相同.一般地,把对一个信息的摘要称为该消息的指纹或数字签名。数字签名是保证信息的完整性和不可否认性的方法。
常见的消息摘要算法有:
hash 算法:(通常也称散列算法,是一种将任意长度的消息变成固定长度的消息摘要算法,不可逆)
- 1 MD5
Message Digest Algorithm 5,流行度极高,但目前被发现存在碰撞冲突风险;
任意长度输出为128bit=16字节摘要
- 2 SHA1
SHA 指Security Hash Algorithm,由美国国家安全局NSA设计的安全散列算法系列;
SHA1 输出长度为160bit=20字节摘要
- 3 SHA256
继SHA1 出现的算法(属于SHA-2类),安全性较SHA1更高;
SHA256 输出长度为256bit=32字节摘要
MAC 算法
Message Authentication Code,消息认证码算法,基于HASH算法之上,增加了密钥的支持以提高安全性。
具体算法包括HmacMD5/HmacSHA1/HmacSHA256等,输入包括数据及密钥,输出长度与HASH算法一致。
密钥可以是任意长度的数据
代码实例
MessageDigest 类是一个引擎类,它是为了提供诸如 SHA1 或 MD5 等密码上安全的报文摘要功能而设计的.
大致的主要步骤
1.获取MessageDigest对象
public static MessageDigest getInstance(String algorithm)//注意:算法名不区分大小写。
2.更新报文摘要对象
计算数据的摘要的第二步是向已初始化的报文摘要对象提供数据。这将通过一次或多次调用以下某个 update(更新)方法来完成:
public void update(byte input) public void update(byte[] input) public void update(byte[] input, int offset, int len)3.计算摘要
通过调用 update 方法提供数据后,程序就调用以下某个 digest(摘要)方法来计算摘要:
public byte[] digest() public byte[] digest(byte[] input) public int digest(byte[] buf, int offset, int len)编码实现:
MD算法:
需要导入的依赖:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.54</version>
</dependency>
package com.fitc.soldier.service.common;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.MD4Digest;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class MDdemo {
private static final String CONTENT="唯梦想与好姑娘不可辜负";
public static void main(String[] args) throws NoSuchAlgorithmException {
jdkMD5(CONTENT);
jdkMD2(CONTENT);
bcMD4(CONTENT);
}
/**
* JDK 提供的MD5实现
* 作为主要的应用
*
*/
public static void jdkMD5(String Content) {
try {
//注意:算法名不区分大小写。例如,以下所有调用都是相等的:
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
// 使用MD5算法对消息摘要(使用digest(byte[])的重载方法update 初始化原始数据)
byte[] digest = messageDigest.digest(Content.getBytes());
// 为了使摘要的结果以String 方式打印 便于对比
String encodeHexString = Hex.encodeHexString(digest);
System.out.println("JDK 的MD5 摘要算法:" + encodeHexString);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
/**
* JDK 提供的MD2实现
*
*/
public static void jdkMD2(String Content) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD2");
// 使用MD5算法对消息摘要
byte[] digest = messageDigest.digest(Content.getBytes());
// 为了使摘要的结果以String 方式打印 便于对比
String encodeHexString = Hex.encodeHexString(digest);
System.out.println("JDK 的MD2 摘要算法:" + encodeHexString);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
/**
* bc支持的MD4
* @throws NoSuchAlgorithmException
*/
public static void bcMD4(String Content) throws NoSuchAlgorithmException {
// Security.addProvider(new BouncyCastleProvider());
// MessageDigest digest=MessageDigest.getInstance("MD4");
// byte[] digest2 = digest.digest(Content.getBytes());
// System.out.println(" bcMD4摘要算法:" + Hex.encodeHexString(digest2));
Digest digest=new MD4Digest();
// 初始化
digest.update(Content.getBytes(), 0, Content.getBytes().length);
int digestSize = digest.getDigestSize();
// 定义摘要后的二进制数据 接收数组
byte[] md4Byte=new byte[digestSize];
// 对消息进行摘要 第二个参数 插入数据的偏移量 即从什么位置插入
digest.doFinal(md4Byte, 0);
System.out.println(" bcMD4摘要算法:" + Hex.encodeHexString(md4Byte));
}
}
MD算法的应用场景:
对于用户的密码数据,在持久化时使用明文存储不符合安全性的要求,此时可以对密码进行摘要算法然后再进行持久化.在此引用慕课网的教程图片:
在注册时存入数据库的是密码的摘要,在登陆时对登录的密码进行摘要然后对比数据库中存储的摘要判断是否登录成功.
SHA算法
/**
* JDK 提供的SHA1等实现
* 作为主要的应用
*
*/
public static void jdkSHA1(String Content) {
try {
//SHA-1 ,SHA-224,SHA-256 ....
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
//初始化参数数据
messageDigest.update(Content.getBytes());;
// 使用SHA1算法对消息摘要
byte[] digest = messageDigest.digest();
// 为了使摘要的结果以String 方式打印 便于对比
String encodeHexString = Hex.encodeHexString(digest);
System.out.println("JDK 的SHA1 摘要算法:" + encodeHexString);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
对于其他SHA算法大同小异,在此不再赘叙.
MAC算法
MAC(也成HMAC)算法与MD以及SHA算法相比,在兼容两种算法的基础上加入了密钥.
在使用密钥时,需要了解几个类:
keyGenerator:秘钥生成器,也就是更具算法类型随机生成一个秘钥,例如HMAC,所以这个大部分用在非可逆的算法中.
KeyPairGenerator:秘钥对生成器,也就是可以生成一对秘钥,也就是公钥和私钥,所以大部分使用在非对称加密中
public static void hmac(String content) throws NoSuchAlgorithmException, InvalidKeyException{
/*
* 根据算法名称获取密钥生成器
*/
KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacMD5");
//生成密钥
SecretKey generateKey = keyGenerator.generateKey();
//还原密钥
// SecretKey restoregenerateKey=new SecretKeySpec(generateKey.getEncoded(), "HmacMD5");
/**
* 创建Mac对象
*/
Mac mac=Mac.getInstance(generateKey.getAlgorithm());
/**
* 初始化
*/
mac.init(generateKey);
byte[] doFinal = mac.doFinal(content.getBytes());
System.out.println("HmacMD5 :"+Hex.encodeHexString(doFinal));
}
应用场景假设:
甲乙双方进行数据交换可以采取如下流程完成
1、甲方向乙方公布摘要算法(就是指定要使用的摘要算法名)
2、甲乙双方按照约定构造密钥,双方拥有相同的密钥(一般是一方构造密钥后通知另外一方,此过程不需要通过程序实现,就是双方约定个字符串,但是这个字符串可不是随便设定的,也是通过相关算法获取的)
3、甲方使用密钥对消息做摘要处理,然后将消息和生成的摘要消息一同发送给乙方
4、乙方收到消息后,使用甲方已经公布的摘要算法+约定好的密钥 对收到的消息进行摘要处理。然后比对自己的摘要消息和甲方发过来的摘要消息。甄别消息是否是甲方发送过来的