# 快速了解常用的非对称加密算法，再也不用担心面试官的刨根问底

### RSA算法

RSA算法利用了两个数论特性：

1. p1、p2为两个质数， n=p1 * p2。已知p1、p2求n简单，已知n求p1、p2很难。
2. (m^e) mod n=c，已知m、e、n求c简单，已知e、n、c求m很难。

import javax.crypto.Cipher;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RsaUtil {

private static final String RSA = "RSA";
private static final Charset CHARSET = StandardCharsets.UTF_8;

/**
* 加密
*
* @param input     明文
* @param publicKey 公钥
* @return 密文
* @throws GeneralSecurityException
*/
public static String encrypt(String input, String publicKey) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance(RSA);
PublicKey pubKey = KeyFactory.getInstance(RSA)
.generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey)));
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] data = cipher.doFinal(input.getBytes(CHARSET));
return Base64.getEncoder().encodeToString(data);
}

/**
* 解密
*
* @param input      密文
* @param privateKey 私钥
* @return 明文
* @throws GeneralSecurityException
*/
public static String decrypt(String input, String privateKey) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance(RSA);
PrivateKey priKey = KeyFactory.getInstance("RSA")
.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
cipher.init(Cipher.DECRYPT_MODE, priKey);
byte[] data = cipher.doFinal(Base64.getDecoder().decode(input));
return new String(data, CHARSET);
}

public static void main(String[] args) throws GeneralSecurityException {
// 生成公钥／私钥对:
KeyPairGenerator kpGen = KeyPairGenerator.getInstance(RSA);
kpGen.initialize(1024);
KeyPair keyPair = kpGen.generateKeyPair();
String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
System.out.println("公钥：" + publicKey);
System.out.println("私钥：" + privateKey);

String msg = "我喜欢你，可以做我女朋友吗？";
System.out.println("加密前：" + msg);
String pwd = RsaUtil.encrypt(msg, publicKey);
System.out.println("加密后：" + pwd);
System.out.println("解密后：" + RsaUtil.decrypt(pwd, privateKey));
}
}

RSA算法解决了对称算法的安全性依赖于同一个密钥的缺点。不过，RSA算法在计算上相当复杂，性能欠佳、远远不如对称加密算法。因此，在一般实际情况下，往往通过非对称加密算法来随机创建临时的对称密钥，然后通过对称加密来传输大量、主体的数据。

### DSA

DSA（Digital Signature Algorithm，数字签名算法）是 Schnorr 和 ElGamal 签名算法的变种，基于模算数和离散对数的复杂度。

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class DsaUtil {

private static final String DSA = "DSA";
private static final String SHA1withDSA = "SHA1withDSA";
private static final Charset CHARSET = StandardCharsets.UTF_8;

/**
* 签名
*
* @param data       数据
* @param privateKey 私钥
* @return 签名
* @throws GeneralSecurityException
*/
public static String sign(String data, String privateKey) throws GeneralSecurityException {
PrivateKey priKey = KeyFactory.getInstance(DSA)
.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
Signature signature = Signature.getInstance(SHA1withDSA);
signature.initSign(priKey);
signature.update(data.getBytes(CHARSET));
return Base64.getEncoder().encodeToString(signature.sign());
}

/**
* 验证
*
* @param data      数据
* @param publicKey 公钥
* @param sign      签名
* @return 是否验证通过
*/
public static boolean verify(String data, String publicKey, String sign) throws GeneralSecurityException {
try {
PublicKey pubKey = KeyFactory.getInstance(DSA)
.generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey)));
Signature signature = Signature.getInstance(SHA1withDSA);
signature.initVerify(pubKey);
signature.update(data.getBytes(CHARSET));
return signature.verify(Base64.getDecoder().decode(sign));
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public static void main(String[] args) throws GeneralSecurityException {
// 生成公钥／私钥对:
KeyPairGenerator kpGen = KeyPairGenerator.getInstance(DSA);
kpGen.initialize(1024);
KeyPair keyPair = kpGen.generateKeyPair();
String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
System.out.println("公钥：" + publicKey);
System.out.println("私钥：" + privateKey);

String msg = "我喜欢你，可以做我女朋友吗？";
System.out.println("数据：" + msg);
String sign = DsaUtil.sign(msg, privateKey);
System.out.println("签名：" + sign);
System.out.println("验证是否通过：" + DsaUtil.verify(msg, publicKey, sign));
}

}

### 总结

posted @ 2022-03-03 11:29  万猫学社  阅读(1763)  评论(0编辑  收藏  举报