数据加密标准(英语:Data Encryption Standard,缩写为 DES)是一种对称密钥加密块密码算法。 DES算法的入口参数有三个:Key、Data、Mode。
- Key: 7个字节共56位,是DES算法的工作密钥;
- Data: 8个字节64位,是要被加密或被解密的数据;
- Mode: 加密或解密。
三重数据加密算法(英语:Triple Data Encryption Algorithm,又称3DES(Triple DES),是一种对称密钥加密块密码,相当于是对每个数据块应用三次数据加密标准(DES)算法。
AESAES,高级加密标准(英语:Advanced Encryption Standard),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。
- 采用对称分组密码体制,密钥长度为 128 位、 192 位、256 位,分组长度128位
- 相对于DES ,AES具有更好的 安全性、效率 和 灵活性。
非对称加密算法需要两个密钥:公钥和私钥。公钥与私钥是成对存在的,如果用公钥对数据进行加密,只有用对应的私钥才能解密。主要的非对称加密算法有:RSA、Elgamal、DSA、D-H、ECC。
RSA算法- RSA加密算法是一种非对称加密算法,广泛应用于加密和数字签名
- RSA算法原理:两个大素数的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
- RSA是被研究得最广泛的公钥算法,从提出到现在,经历了各种攻击的考验,普遍认为是目前最优秀的公钥方案之一。
- DSA(Digital Signature Algorithm,数字签名算法),也是一种非对称加密算法。
- DSA和RSA区别在,DSA仅用于数字签名,不能用于数据加密解密。其安全性和RSA相当,但其性能要比RSA好。
- ECC(Elliptic Curves Cryptography,椭圆曲线密码编码学),基于椭圆曲线加密。
- Ecc主要优势是,在某些情况下,它比其他的方法使用更小的密钥,比如RSA加密算法,提供相当的或更高等级的安全级别。
- 它的一个缺点是,加密和解密操作的实现比其他机制时间长 (相比RSA算法,该算法对CPU 消耗严重)。
国密即国家密码局认定的国产密码算法。为了保障商用密码的安全性,国家商用密码管理办公室制定了一系列密码标准,即SM1,SM2,SM3,SM4等国密算法。
SM1- SM1,为对称加密算法,加密强度为128位,基于硬件实现。
- SM1的加密强度和性能,与AES相当。
- SM2主要包括三部分:签名算法、密钥交换算法、加密算法
- SM2用于替换RSA加密算法,基于ECC,效率较低。
- SM3,即国产消息摘要算法。
- 适用于商用密码应用中的数字签名和验证,消息认证码的生成与验证以及随机数的生成。
- SM4是一个分组算法,用于无线局域网产品。
- 该算法的分组长度为128比特,密钥长度为128比特。
- 加密算法与密钥扩展算法都采用32轮非线性迭代结构。
- 解密算法与加密算法的结构相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。
- 它的功能类似国际算法的DES。
这个小节先介绍一下加签验签需要用到的API吧~
加签相关API- java.security.Signature.getInstance(String algorithm); //根据对应算法,初始化签名对象
- KeyFactory.getInstance(String algorithm);// 根据对应算法,生成KeyFactory对象
- KeyFactory.generatePrivate(KeySpec keySpec); //生成私钥
- java.security.Signature.initSign(PrivateKey privateKey) //由私钥,初始化加签对象
- java.security.Signature.update(byte[] data) //把原始报文更新到加签对象
- java.security.Signature.sign();//加签
「Signature.getInstance(String algorithm);」
- 根据对应算法,初始化签名对象
- algorithm参数可以取SHA256WithRSA或者MD5WithRSA等参数,SHA256WithRSA表示生成摘要用的是SHA256算法,签名加签用的是RSA算法
「KeyFactory.getInstance(String algorithm);」
- 根据对应算法,生成KeyFactory对象,比如你的公私钥用的是RSA算法,那么就传入RSA
「KeyFactory.generatePrivate(KeySpec keySpec)」
- 生成私钥,加签用的是私钥哈,所以需要通过KeyFactory先构造一个私钥对象。
「Signature.initSign(PrivateKey privateKey)」
- 加签用的是私钥,所以传入私钥,初始化加签对象
「Signature.update(byte[] data)」
- 把原始报文更新到加签对象
「java.security.Signature.sign();」
- 进行加签操作
- java.security.Signature.getInstance(String algorithm); //根据对应算法,初始化签名对象
- KeyFactory.getInstance(String algorithm);// 根据对应算法,生成KeyFactory对象
- KeyFactory.generatePublic(KeySpec keySpec); //生成公钥
- java.security.Signature.initVerify(publicKey); //由公钥,初始化验签对象
- java.security.Signature.update(byte[] data) //把原始报文更新到验签对象
- java.security.Signature.verify(byte[] signature);//验签
「Signature.getInstance(String algorithm)」
- 根据对应算法,初始化签名对象,注意验签和加签是需要用相同的algorithm算法参数哦~
「KeyFactory.getInstance(String algorithm);」
- 根据对应算法,生成KeyFactory对象
「KeyFactory.generatePublic(KeySpec keySpec);」
- 生成公钥,验签用的是公钥,通过KeyFactory先构造一个公钥对象
**Signature.initVerify(publicKey); **
- 公钥验签,所以传入公钥对象参数,初始化验签对象
「Signature.update(byte[] data)」
- 把原始报文更新到加签对象
「Signature.verify(byte[] signature);」
- 进行验签操作
前几个小节讨论完概念,是时候上代码实战了,我这边用的是SHA-256作为摘要算法,RSA作为签名验签算法,如下:
package pattern;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
/**
* 加签验签demo
* @Author 捡田螺的小男孩
*/
public class SignatureTest {
//公钥字符串
private static final String PUBLIC_KEY_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaJzVjC5K6kbS2YE2fiDs6H8pB\n"
"JFDGEYqqJJC9I3E0Ebr5FsofdImV5eWdBSeADwcR9ppNbpORdZmcX6SipogKx9PX\n"
"5aAO4GPesroVeOs91xrLEGt/arteW8iSD ZaGDUVV3 wcEdci/eCvFlc5PUuZJou\n"
"M2XZaDK4Fg2IRTfDXQIDAQAB";
//私钥字符串
private static final String PRIVATE_KEY_STR = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANonNWMLkrqRtLZg\n"
"TZ IOzofykEkUMYRiqokkL0jcTQRuvkWyh90iZXl5Z0FJ4APBxH2mk1uk5F1mZxf\n"
"pKKmiArH09floA7gY96yuhV46z3XGssQa39qu15byJIP5loYNRVXf7BwR1yL94K8\n"
"WVzk9S5kmi4zZdloMrgWDYhFN8NdAgMBAAECgYA9bz1Bn0i68b2KfqRdgOfs/nbe\n"
"0XNN1DLQp2t7WDfRCg01iI1zPkZgyFVZWtI85f5/uIrLs5ArLosL1oNuqqc0nNne\n"
"CvJK ZxvA98Hx3ZqYTzDnleR054YhofL5awbhSciYVic204DOG1rhSsYWMqtX7J7\n"
"3geoWL7TYdMfYXcCAQJBAPMMKsz6ZJh98EeQ1tDG5gpAGWFQkYNrxZDelP/LjeO0\n"
"TP3XkQnIpcaZoCs7V/rRGRGMWwQ2BUdc/01in89ZZ5ECQQDlx2oBc1CtOAm2UAhN\n"
"1xWrPkZWENQ53wTrwXO4qbTGDfBKon0AehLlGCSqxQ71aufLkNO7ZlX0IHTAlnk1\n"
"TvENAkAGSEQ69CXxgx/Y2beTwfBkR2/gghKg0QJUUkyLqBlMz3ZGAXJwTE1sqr/n\n"
"HiuSAiGhwH0ByNuuEotO1sPGukrhAkAMK26a2w nzPL u hkrwKPykGRZ1zGH Cz\n"
"19AYNKzFXJGgclCqiMydY5T1knBDYUEbj/UW1Mmyn1FvrciHoUG1AkAEMEIuDauz\n"
"JabEAU08YmZw6OoDGsukRWaPfjOEiVhH88p00veM1R37nwhoDMGyEGXVeVzNPvk7\n"
"cELg28MSRzCK";
public static void main(String[] args) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException, IOException, InvalidKeySpecException {
//原始报文
String plain = "欢迎大家关注我的公众号,捡田螺的小男孩";
//加签
byte[] signatureByte = sign(plain);
System.out.println("原始报文是:" plain);
System.out.println("加签结果:");
System.out.println(new BASE64Encoder().encode(signatureByte));
//验签
boolean verifyResult = verify(plain, signatureByte);
System.out.println("验签结果:" verifyResult);
}
/**
* 加签方法
* @param plain
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws UnsupportedEncodingException
* @throws SignatureException
*/
private static byte[] sign(String plain) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, SignatureException {
//根据对应算法,获取签名对象实例
Signature signature = Signature.getInstance("SHA256WithRSA");
//获取私钥,加签用的是私钥,私钥一般是在配置文件里面读的,这里为了演示方便,根据私钥字符串生成私钥对象
PrivateKey privateKey = getPriveteKey(PRIVATE_KEY_STR);
//初始化签名对象
signature.initSign(privateKey);
//把原始报文更新到对象
signature.update(plain.getBytes("UTF-8"));
//加签
return signature.sign();
}
/**
* 验签方法
* @param plain
* @param signatureByte
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws IOException
* @throws SignatureException
* @throws InvalidKeySpecException
*/
private static boolean verify(String plain, byte[] signatureByte) throws NoSuchAlgorithmException, InvalidKeyException, IOException, SignatureException, InvalidKeySpecException {
//获取公钥
PublicKey publicKey = getPublicKey(PUBLIC_KEY_STR);
//根据对应算法,获取签名对象实例
Signature signature = Signature.getInstance("SHA256WithRSA");
//初始化签名对象
signature.initVerify(publicKey);
//把原始报文更新到签名对象
signature.update(plain.getBytes("UTF-8"));
//进行验签
return signature.verify(signatureByte);
}
private static PublicKey getPublicKey(String publicKeyStr) throws InvalidKeySpecException, IOException {
PublicKey publicKey = null;
try {
java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec(
new BASE64Decoder().decodeBuffer(publicKeyStr));
// RSA对称加密算法
java.security.KeyFactory keyFactory;
keyFactory = java.security.KeyFactory.getInstance("RSA");
// 生成公钥对象
publicKey = keyFactory.generatePublic(bobPubKeySpec);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return publicKey;
}
private static PrivateKey getPriveteKey(String privateKeyStr) {
PrivateKey privateKey = null;
PKCS8EncodedKeySpec priPKCS8;
try {
priPKCS8 = new PKCS8EncodedKeySpec(new BASE64Decoder().decodeBuffer(privateKeyStr));
KeyFactory keyf = KeyFactory.getInstance("RSA");
privateKey = keyf.generatePrivate(priPKCS8);
} catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
}
return privateKey;
}
}
「运行结果:」
加签结果:
Oz15/aybGe42eGHbc iMoSYHSCc8tfRskTVjjGSTPD4HjadL0CC5JUWNUW0WxHjUb4MvxWo2oeWE
Qw0 m61d JgBMto/TWcVDcgwL/AbObsbWdQ6E/fVRqG13clkE8MyKsjt9Z7tcbwpycYTv0rUR4co
rndAVfBdtv5KeV OXqM=
验签结果:true
作者:Jay_huaxiao
链接:https://juejin.im/post/5f13474c5188252e677bcbbf