RSA算法加密解密与签名验签
rsa有一对公钥和私钥,具体生成过程可以造网上找
1.加密解密:加密使用公钥加密,私钥解密
2.签名验签:使用私钥签名,公钥验签
举例说明:
A向B发消息,A有一对公钥和私钥,B也有一对公钥和私钥,各自保留自己的私钥,把公钥交给对方。
加密解密:A用B的公钥把信息加密发给B,B用自己的私钥解密信息。但是这其中存在一个问题,B的公钥是公开的,假如被C知道了,C假冒A给B发消息,这个时候B是不能区分的,此时就有了签名
签名验签:A先按照一定的规则对信息提取摘要,然后用A的私钥加密摘要,再将信息与摘要一起用B的公钥加密发送给B。B再接收到A的消息后,先用自己的私钥解密A发过来的密文,拿出信息,用和A同样的规则提取摘要,再用A的公钥解密A发过来的摘要,再和自己提取出来的摘要对比,如果一样说明此消息是从A发过来的,验签通过。
生成秘钥对
```java
package com.toonyoo.tool;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Base64;
/**
* @ClassName GeneratorRSAKey
* @Description
* @Author Administrator
* @Date 2020-06-03 10:41
**/
public class GeneratorRSAKey {
private static final String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCazYW17+RwTJlXVxd8vBfPO+ORVKp3nl2UNV+C1MCJP5oXBmcarQ6yqkbgfs72GFuRekdgQQzbtmCj+E9BLWJ7Lsc/SjZ6zHo6e0XfAJySJAstuO27H33dU0jeFQk8bt+GhSjIECSmruLoZVqYe2vV/oRkSa16s9HagI2LMhMXbwIDAQAB";
private static final String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJrNhbXv5HBMmVdXF3y8F88745FUqneeXZQ1X4LUwIk/mhcGZxqtDrKqRuB+zvYYW5F6R2BBDNu2YKP4T0EtYnsuxz9KNnrMejp7Rd8AnJIkCy247bsffd1TSN4VCTxu34aFKMgQJKau4uhlWph7a9X+hGRJrXqz0dqAjYsyExdvAgMBAAECgYEAiKXhYR/Y29SSC4oifoYe0l0AXdqJ+7t8yYZvwDKDnuPY5nhNbTvUXJx4olTt5kjME9gHx4zEh/Iuzq8zbspcQg5GkCifyMxplUBhSBSePGbfq6gOwY3BZ55SYk5Ib0FX2Wq//4WCf2+aCJNrGRiG/c+rHfdpQI47bqd8quMcqOkCQQD5M1T2lFGqpyH0Fh3WZgy8f7v1qP3rS1TefH1rRHiv94gtTjQKodossdESUkNMyW7AZ38l7gXtvwlGo2Eydm1LAkEAnwbSUuPoaKpRxsu+bjsQz1GfdUub0FSeTxQJLwHGwFtycYf8XVUlC/eSc9QwVMG7YBOIdg4OVoPnHQoCohsb7QJAECUpPgiB+gJ2CrBcIoXeEWBdNx9JxDLPPtLl9UssXoo1AmpsqLuvvPGQUBWQUqtCR6js7fIr5ClaWn8/TtupXQJAAsajtT61N96BPu8fi90MFhJerjV7qs9PVCINZvyo84KlJMYy6Y4q72KK8+qoTVJ0auDsaOMl7OywhBlAooPGoQJAJpWA1vwsSO6F5ZhO1ATgTmAEaW8cYAeO0ZvyjrN+l9NM3D9EONUq7OuEnc58pKcW71dzYirjA4UPOuNl4r/x1A==";
// public static void main(String[] args) {
// jdkRSA();
// }
public static void jdkRSA() {
GeneratorRSAKey generatorKey = new GeneratorRSAKey();
try {
// 初始化密钥,产生公钥私钥对
Object[] keyPairArr = generatorKey.initSecretkey();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPairArr[0];
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPairArr[1];
System.out.println("------------------PublicKey------------------");
System.out.println(Base64.getEncoder().encodeToString(rsaPublicKey.getEncoded()));
System.out.println("\n------------------PrivateKey------------------");
System.out.println(Base64.getEncoder().encodeToString(rsaPrivateKey.getEncoded()));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 初始化密钥,生成公钥私钥对
*
* @return Object[]
* @throws NoSuchAlgorithmException NoSuchAlgorithmException
*/
private Object[] initSecretkey() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
Object[] keyPairArr = new Object[2];
keyPairArr[0] = rsaPublicKey;
keyPairArr[1] = rsaPrivateKey;
return keyPairArr;
}
}
提取信息摘要并且对其加密
public void sender(CheckCodeDTO checkCodeDTO){
Map condition = new HashMap();
condition.put("configType","0");
condition.put("configKey",checkCodeDTO.getShopId());
condition.put("configStatus",1);
Config config = configService.queryConfig(condition);
if(config == null || StringUtils.isBlank(config.getConfigValue())){
log.error("新电子码核销时调用第三方接口失败:未查询对应门店映射关系.shopId:>>>>>>>>>>>>>>>>>>>>>>>>>>",checkCodeDTO.getShopId());
return;
}
Map<String, Object> body = new HashMap<>();
body.put("source",1);//核销来源 (0线上,1线下)
body.put("code",checkCodeDTO.getCode());
body.put("outerType",1);//外部券码类型(1:外部导入券码, 2:微信代金券)
body.put("storeId",config.getConfigValue());//门店ID
body.put("orderNo",UUID.randomUUID().toString());//批次号(渠道唯一,限长40
Map<String, Object> headerParam = new HashMap<>();
headerParam.put("appId",appId);
headerParam.put("timestamp",String.valueOf(new Date().getTime()));
headerParam.put("bizContent",JSONUtil.toStr(body));
StringBuilder sb = new StringBuilder();
headerParam.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).forEach(entry ->
sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&")
);
String paramStr = sb.toString().substring(0, sb.length() - 1);
// 使用私钥生成签名字符串
String sign = JdkSignatureUtil.executeSignature(privateKey, paramStr);
if(sign == null){
log.error("加签后sign为null");
return;
}
// 请求参数中需带上签名字符串
headerParam.put("sign", sign);
headerParam.remove("bizContent");
// 发送请求
postJson(thirdPartUrl, headerParam,body);
}
私钥加签
package com.toonyoo.tool;
import lombok.extern.slf4j.Slf4j;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
/**
* @author 01
* @program demo
* @description RSA签名工具类
* @create 2018-12-15 21:26
* @since 1.0
**/
@Slf4j
public class JdkSignatureUtil {
private final static String RSA = "RSA";
private final static String SHA1_With_RSA = "SHA1WithRSA";
/**
* 执行签名
*
* @param rsaPrivateKey 私钥
* @param src 参数内容
* @return 签名后的内容,base64后的字符串
*/
public static String executeSignature(String rsaPrivateKey, String src) {
// base64解码私钥
byte[] decodePrivateKey = Base64.getDecoder().decode(rsaPrivateKey.replace("\r\n", ""));
String content = null;
try {
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decodePrivateKey);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance(SHA1_With_RSA);
signature.initSign(privateKey);
signature.update(src.getBytes());
// 生成签名并base64编码签名为字符串
content = Base64.getEncoder().encodeToString(signature.sign());
} catch (Exception e) {
log.error("新电子码对接万达小程序加签失败",e);
}
return content;
}
/**
* 验证签名
*
* @param rsaPublicKey 公钥
* @param sign 签名
* @param src 参数内容
* @return 验证结果
* @throws NoSuchAlgorithmException NoSuchAlgorithmException
* @throws InvalidKeySpecException InvalidKeySpecException
* @throws InvalidKeyException InvalidKeyException
* @throws SignatureException SignatureException
*/
public static boolean verifySignature(String rsaPublicKey, String sign, String src) throws NoSuchAlgorithmException,
InvalidKeySpecException, InvalidKeyException, SignatureException {
// base64解码公钥
byte[] decodePublicKey = Base64.getDecoder().decode(rsaPublicKey.replace("\r\n", ""));
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(decodePublicKey);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Signature signature = Signature.getInstance(SHA1_With_RSA);
signature.initVerify(publicKey);
signature.update(src.getBytes());
// base64解码签名为字节数组
byte[] decodeSign = Base64.getDecoder().decode(sign);
// 验证签名
return signature.verify(decodeSign);
}
}