一、消息摘要
消息摘要是一种与消息认证结合使用以确保消息完整性的技术,消息摘要采用单向Hash函数将加密的明文“摘要”成一串密文,则这串密文亦称为数字指纹(Finger Print),则接受者通过对接受到信息的新产生的摘要与原摘要比较,就知道消息是否被修改了
特点:
- 唯一性
- 不可逆
- 不需要秘钥
- 长度固定,无论输入的明文有多长,计算出的消息摘要的长度总数固定的
原理:消息摘要就是将需要摘要的数据作为参数,经过Hash函数计算,得到的散列值
常用消息摘要算法:MD(Message Digest,消息摘要算法)、SHA(Secure Hash Algorithm, 安全散列算法)、MAC(Message AuthenticationCode,消息认证码算法),目前广泛使用算法MD5、SHA1
@Test
public void testMD() throws Exception {
String plainText = "USE MD";
System.out.println("明文:" + plainText);
// 使用getInstance("算法")来获得消息摘要
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
// 开始使用算法
messageDigest.update(plainText.getBytes());
// 得到摘要
byte[] digestByte = messageDigest.digest();
// 摘要长度始终为16个字节,128位
System.out.println("摘要长度:" + digestByte.length);
// 输出算法运算结果,防止乱码,使用Base64编码
String encode = Base64.getEncoder().encodeToString(digestByte);
System.out.println("摘要:" + encode);
}
结果:
摘要始终不变
明文:USE MD
摘要长度:16
摘要:fa3mkoztZ4XtArxxV4vPGg==
二、对称加密
消息发送方和消息接收方必须使用相同的密钥
对称加密常用算法:DES(Data Encryption Standard, 数据加密标准)、AES(Advanced Encryption Standard, 高级加密标准)
@Test
public void testAES() throws Exception {
String plainText = "USE AES";
System.out.println("明文:" + plainText);
// 得到一个使用AES算法的KeyGenerator的实例
KeyGenerator kenGen = KeyGenerator.getInstance("AES");
// 定义秘钥长度128位
kenGen.init(128);
// 通过KeyGenerator产生一个key(秘钥算法刚才已定义,为AES)
Key key = kenGen.generateKey();
// 1.获取加密工具类,定义Cipher的基本信息,ECB是加密方法,PKCS5Padding是填充方法
// 算法/工作模式/填充模式(algorithm/mode/padding
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// 2.加密,对工具类对象进行初始化
cipher.init(Cipher.ENCRYPT_MODE, key);
// 3.用加密工具类对象对明文进行加密
byte[] encipherByte = cipher.doFinal(plainText.getBytes());
String encode = Base64.getEncoder().encodeToString(encipherByte);
System.out.println("加密:" + encode);
// 2.解密
cipher.init(Cipher.DECRYPT_MODE, key);
// 3.用加密工具类对象对密文进行解密
byte[] decode = Base64.getDecoder().decode(encode);
byte[] decipherByte = cipher.doFinal(decode);
String decipherText = new String(decipherByte);
System.out.println("解密:" + decipherText);
}
结果:
每次执行后,密文不同的
明文:USE AES
加密:LcZyK4nD7BdSe2OY+4yYIw==
解密:USE AES
三、非对称加密
非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)
非对称加密常用算法:RSA
@Test
public void testRSA() throws Exception {
String plainText = "USE RSA";
System.out.println("明文:" + plainText);
// 产生一个RSA秘钥生成器KeyPairGenerator(一对钥匙生成器)
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
// 定义秘钥长度512位
keyGen.initialize(512);
// 通过KeyPairGenerator产生秘钥,注意这里的key是一对钥匙
KeyPair key = keyGen.generateKeyPair();
// 1.获取加密工具类
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
// 2.使用公钥加密,对工具类对象进行初始化
cipher.init(Cipher.ENCRYPT_MODE, key.getPublic());
// 3.用加密工具类对象对明文进行加密
byte[] encipherByte = cipher.doFinal(plainText.getBytes());
String encode = Base64.getEncoder().encodeToString(encipherByte);
System.out.println("加密:" + encode);
// 2.使用私钥解密,对工具类对象进行初始化
// PrivateKey privateKey = KeyFactory.getInstance("RSA")
// .generatePrivate(new PKCS8EncodedKeySpec(key.getPrivate().getEncoded()));
// cipher.init(Cipher.DECRYPT_MODE, privateKey);
cipher.init(Cipher.DECRYPT_MODE, key.getPrivate());
// 3.用加密工具类对象对密文进行解密
byte[] decode = Base64.getDecoder().decode(encode);
byte[] decipherByte = cipher.doFinal(decode);
String decipherText = new String(decipherByte);
System.out.println("解密:" + decipherText);
}
结果:
每次执行后,密文不同的
明文:USE RSA
加密:P4YisfnFrY4fERKWIJEpp2QdNO8UMJBmgeZt5Q6JmNSOhqbW87k7+74xA8L6z7IkjSZITJk3c1ULDB80jAizIg==
解密:USE RSA
四、数字签名
数字签名的主要作用就是保证了数据的有效性(验证是谁发的)和完整性(证明信息没有被篡改)
摘要经过加密,就得到数字签名
签名算法有:MD5withRSA、SHA1withRSA、SHA256withRSA
@Test
public void testSign() throws Exception {
String plainText = "USE RSA TO SIGNATURE";
System.out.println("正文:" + plainText);
// 形成RSA公钥对
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(512);
KeyPair key = keyGen.generateKeyPair();
// 1.获取签名工具类
Signature sig = Signature.getInstance("MD5withRSA");
// 2.初始化签名,使用私钥签名
sig.initSign(key.getPrivate());
sig.update(plainText.getBytes());
// 3.得到签名
byte[] signByte = sig.sign();
String encode = Base64.getEncoder().encodeToString(signByte);
System.out.println("签名:" + encode);
// 2.初始化验证,使用公钥验证
sig.initVerify(key.getPublic());
sig.update(plainText.getBytes());
// 3.进行验证
byte[] decode = Base64.getDecoder().decode(encode);
if (sig.verify(decode)) {
System.out.println("签名验证正确!");
} else {
System.out.println("签名验证失败!");
}
}
结果:
每次执行后,签名不同的
正文:USE RSA TO SIGNATURE
签名:U8p07Agh4/BcxmZ2oh6IaTtFaNBi4X2PfruTTIJlISp2bUEInwx5W47XMsn6oBbRN+SuOCnz8zi1Xpmv7yqCIw==
签名验证正确!