非对称加密算法
● 算法特点
- 有2把秘钥,为公钥和私钥。
- 如果使用公钥加密,则必须使用私钥解密。
- 如果使用私钥解密,则必须使用公钥加密。
- 公钥和私钥是一对,成为密钥对。
对于此类加密算法的实现有 RSA,ECC等,也就是说 对称加密,消息摘要以及非对称加密 是一些算法思想,基于思想才有的实现。那么非对称加密的算法实现就是RSA和ECC等。
在JDK中当然也为RSA等算法提供了实现
public class RSATest {
static {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
KeyPair keyPair = keyPairGenerator.generateKeyPair();//密钥对
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String pub = new String(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
String pri = new String(Base64.getEncoder().encodeToString(privateKey.getEncoded()));
System.out.println("公钥:" + pub);
System.out.println("私钥:" + pri);
}catch (Exception e){
e.printStackTrace();
}
}
@Test
public void testKeyPari() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
System.out.println(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
System.out.println("===");
System.out.println(Base64.getEncoder().encodeToString(privateKey.getEncoded()));
String source = "Ja";
System.out.println("加密后的密文:");
String miwen = rsaEncode(source, publicKey);
System.out.println(miwen);
System.out.println("解密后的明文:");
System.out.println(rsaDecode(miwen,privateKey));
}
private String rsaEncode(String source, Key key) throws Exception{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(1,key);
byte[] bytes = cipher.doFinal(source.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(bytes);
}
//RSA算法解密
private String rsaDecode(String source, Key key) throws Exception{
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(2,key);
byte[] bytes = rsa.doFinal(Base64.getDecoder().decode(source.getBytes(StandardCharsets.UTF_8)));
return new String(bytes);
}
}
生成密钥对主要是 KeyPairGenerator 这个对象,可以生成RSA算法需要的公钥和私钥。最后还是需要Cipher 这个对象去实现加解密,同时还要注意,Cipher加解密的结果不一定是一堆完整的字符串,所以往往还需要结合Base64或者Base58等可读性算法来存储或者传输。
数字签名
* 数字签名
- 数字签名是一种验证数据在网络传输过程中完整性、真实性的一种手段。
- 当传输的数据不需要加密而又不希望被篡改时,就可以使用到数字签名,数字签名的过程还是要用到非对称加密算法的,
-
- 首先发送方使用散列函数将发送的内容生成一个消息摘要,也就是一个固定长度的字符串。
-
- 发送方继续使用私钥对散列函数进行加密
-
- 接收方收到内容之后,使用自己的公钥进行解密。
-
- 接收方使用相同的散列函数再次对内容进行加密。
-
- 此时如果接收方计算出的签名结果和发送方相同,则证明没有被篡改过,反之则被篡改过。
public class DigestSign {
@Test
public void testSign() throws Exception {
//生成密钥对
KeyPairGenerator pairGenerator = KeyPairGenerator.getInstance("RSA");
KeyPair keyPair = pairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic(); //公钥
PrivateKey privateKey = keyPair.getPrivate(); //私钥
String pub = Base64.encode(publicKey.getEncoded());
String pri = Base64.encode(privateKey.getEncoded());
System.out.println("公钥:" + pub);
System.out.println("私钥:" + pri);
String content = "南山老妖";
String hashRule = "sha256withrsa";//消息摘要算法
//获取签名
String sign = getSign(privateKey,content,hashRule);
System.out.println("消息的签名是:" + sign);
//接收方验证消息与签名是否匹配
boolean verify = verifySign(publicKey,content,hashRule,sign);
System.out.println("验证签名:" + verify);
}
private boolean verifySign(PublicKey publicKey, String content, String hashRule, String sign) throws Exception {
Signature signature = Signature.getInstance(hashRule);
signature.initVerify(publicKey);
signature.update(content.getBytes(StandardCharsets.UTF_8));
//对比签名
boolean verify = signature.verify(Base64.decode(sign));
return verify;
}
private String getSign(PrivateKey privateKey, String content, String hashRule) throws Exception {
//获取消息签名算法
Signature signature = Signature.getInstance(hashRule);
//设置公钥
signature.initSign(privateKey);
//设置消息摘要泛
signature.update(content.getBytes());
byte[] sign = signature.sign();
return Base64.encode(sign);
}
}
数字签名的过程和RSA的加密解密还有有些相似的,只不过就是在验证数字签名的时候这里要注意,一定是将原文和Base64转码后的签名字节数组去比较。