网上的文档很多,但是不够全面,最重要有些代码不能用!!!
参考文档:
java实现(RSA非对称加密) SHA1WithRSA加签验签 及openssl生成公私钥 感谢博主!!
使用 openssl 生成证书(含openssl详解)
一、数字签名流程
本地发送请求时(本地已对请求根据私钥进行加签) 接收方平台根据公钥进行验签 判断是否合法 接收来自平台的响应时(平台已根据私钥进行加签) 需要根据本地公钥对响应进行验签 判断是否合法 |
二、生成公钥和私钥
1、在Linxu上输入命令: openssl
2、输入命令:genrsa -out rsa_oo_private_key.pem 2048
3、私钥转换成PKCS8格式再做签名使用,输入命令:pkcs8 -topk8 -inform PEM -in rsa_oo_private_key.pem -outform PEM -nocrypt
注意:私钥就是输入pkcs8 -topk8 -inform PEM -in rsa_oo_private_key.pem -outform PEM -nocrypt打印出来的这块内容:
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCqrpUHZx/NSRsK
jQc9i/gCGzU9Q3qRf44pm0lML9FfJf+m9mo9qdAEsMl3N0Y/nVcdGWb8VBry+dyl
mKNR4VPfFNGQKWW8OtvUlT9l3I9/MTd/ZsoVt2dQdBvOp7+9hrClS+rmw/HFz81l
RCFcku8HIIIcFxPQylRgSxHI8PMVJEodBsQSRvOzGtzWTfhTfG0Y0sgZPt75hKjd
J1rTo4264AG3YzlxHlmqrrQxxmYEKEnNplmNVga2bXvPICZ2VPbl9w/52mlSobg3
6VPKMzdlhTUgFsADPMaG2Pf3GqOa2GTSupzgTyz/54LyF6gCbXcAknRFgH5eyAv5
tPqV9CsrAgMBAAECggEAAXIHCxABgfCLjRRSql/EEuh+E+29XPwSjSGmhkGlaUPe
HWDa13jXrSJ+IkdSjflcIn/zklF4BPS+vJxFTc01s57ug2UGWoi5EdzNs6Qhhvc4
vBh3v6VU96Z0EdTz17wLROsWqyufoYg3+hKQocMQySOqVmiPn2YHPuWD2grIVDZ9
68mC1FykGEcv9De0m6yVEsfZDXNUxm3cz1758iBqakvyOVxGsI+V+e7/iSxJiwIB
6f3NSGQVtEsqwyhnl6dZRYDtnq5iUiwUOshl5Z2CYBfBcyTpMKC2RuHp3u9THHpc
3TFE4I1Li5HkiFy+ai6QKl2M85ce3GCXmjyw7n2vmQKBgQDTHihNX6uu6YlVFcRa
XhhGigyLrIP8LbLd4r/dKMXuGa8XqkLPlDtXelh2n565Lo5DPGlpANi3Jp495Hzn
bL+YnHJs7boVOGtORB0XHUbiMaTlT85snpvVjwFngHvY/ZxtXclpsnX563AvzCyl
amrKEhV17BFZbRQOTEL1UNp57QKBgQDO98AyfVgs1tCdtLOsFSFiWrAsJJimBS7b
ec+W/UPGDAl3hFzQzJ2SUvF4EneatYVOEDdHLUzVnT7XXeA/eMZL56N8BTSffh8q
XK0E21K8tW4hRbze6CIjbsJ1x7ZLZaoM4Ub2YAvkulF0PcasX0kWl+bv/DnkI09x
/n3vgbO2dwKBgQCoAnj6UmeztEDJiKARdo6FHHmtciY7Ozb8Y+Zin38c5C22fJXc
0k+DZ2cdSBwtrQIkOeB9YuIUp1QJV1ubZKz5S4+4ZlvPZW3oBEbOTUtK2U0r/J3/
TR4hD0SD1Pk6j2G8m4Wdaxt+P8KxFyB0p8LCey++/5Yy/56VXlVvGuAzZQKBgQCU
VfcXeMTIplGwpkGcFSzvLCZWDQim/NH/lYdWJUD84cWrNl+7ett4cyADueClLnJT
Z8Xmqq4F8ASJIQxHEY21+1gt3CFCKoe1ueR7taHQBIzhJfVfIarOEGUpOzEJSt0d
DBzrGh2MGomksV4CTuy4V7i5yeHIBBK9lfO2xBQEswKBgQCIzYO53kTFl6YGjmWO
qUJsT+5WegR4GdxtqYpQGPC1RmU7ig1TZzen+X3xB+lIHqgA1HvTr6M+tPkmnMwU
iARPOgjXY0zmsStXaHQYKruT3EjZRs2GnmVpVOAj1asqi+/2t0NgLgB5gPLYMXS+
BGf01OehvUt5Ge+OChDBXSW5Bw==
4、生成公钥,输入命令:rsa -in rsa_oo_private_key.pem -pubout -out rsa_public_key.pem
接下来输入命令:cd ~/.ssh/,more rsa_public_key.pem ,得到公钥
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqq6VB2cfzUkbCo0HPYv4
Ahs1PUN6kX+OKZtJTC/RXyX/pvZqPanQBLDJdzdGP51XHRlm/FQa8vncpZijUeFT
3xTRkCllvDrb1JU/ZdyPfzE3f2bKFbdnUHQbzqe/vYawpUvq5sPxxc/NZUQhXJLv
ByCCHBcT0MpUYEsRyPDzFSRKHQbEEkbzsxrc1k34U3xtGNLIGT7e+YSo3Sda06ON
uuABt2M5cR5Zqq60McZmBChJzaZZjVYGtm17zyAmdlT25fcP+dppUqG4N+lTyjM3
ZYU1IBbAAzzGhtj39xqjmthk0rqc4E8s/+eC8heoAm13AJJ0RYB+XsgL+bT6lfQr
KwIDAQAB
三、代码实现
1、引入依赖
commons-codec
commons-codec
1.11
2、具体代码
package com.cn.dl;
import org.apache.commons.codec.binary.Base64;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* SHA1WithRSA-数字签名
* Created by yanshao on 2018/12/12.
*/
// TODO: 2018/12/12 数字签名就发现这个能用
// TODO: 2018/12/12 原文地址:https://blog.csdn.net/qq_23974323/article/details/77678491
public class RSATest2 {
//加密算法
public static final String SIGN_ALGORITHMS = "SHA1WithRSA";
//私钥
private static final String privateKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCqrpUHZx/NSRsK" +
"jQc9i/gCGzU9Q3qRf44pm0lML9FfJf+m9mo9qdAEsMl3N0Y/nVcdGWb8VBry+dyl" +
"mKNR4VPfFNGQKWW8OtvUlT9l3I9/MTd/ZsoVt2dQdBvOp7+9hrClS+rmw/HFz81l" +
"RCFcku8HIIIcFxPQylRgSxHI8PMVJEodBsQSRvOzGtzWTfhTfG0Y0sgZPt75hKjd" +
"J1rTo4264AG3YzlxHlmqrrQxxmYEKEnNplmNVga2bXvPICZ2VPbl9w/52mlSobg3" +
"6VPKMzdlhTUgFsADPMaG2Pf3GqOa2GTSupzgTyz/54LyF6gCbXcAknRFgH5eyAv5" +
"tPqV9CsrAgMBAAECggEAAXIHCxABgfCLjRRSql/EEuh+E+29XPwSjSGmhkGlaUPe" +
"HWDa13jXrSJ+IkdSjflcIn/zklF4BPS+vJxFTc01s57ug2UGWoi5EdzNs6Qhhvc4" +
"vBh3v6VU96Z0EdTz17wLROsWqyufoYg3+hKQocMQySOqVmiPn2YHPuWD2grIVDZ9" +
"68mC1FykGEcv9De0m6yVEsfZDXNUxm3cz1758iBqakvyOVxGsI+V+e7/iSxJiwIB" +
"6f3NSGQVtEsqwyhnl6dZRYDtnq5iUiwUOshl5Z2CYBfBcyTpMKC2RuHp3u9THHpc" +
"3TFE4I1Li5HkiFy+ai6QKl2M85ce3GCXmjyw7n2vmQKBgQDTHihNX6uu6YlVFcRa" +
"XhhGigyLrIP8LbLd4r/dKMXuGa8XqkLPlDtXelh2n565Lo5DPGlpANi3Jp495Hzn" +
"bL+YnHJs7boVOGtORB0XHUbiMaTlT85snpvVjwFngHvY/ZxtXclpsnX563AvzCyl" +
"amrKEhV17BFZbRQOTEL1UNp57QKBgQDO98AyfVgs1tCdtLOsFSFiWrAsJJimBS7b" +
"ec+W/UPGDAl3hFzQzJ2SUvF4EneatYVOEDdHLUzVnT7XXeA/eMZL56N8BTSffh8q" +
"XK0E21K8tW4hRbze6CIjbsJ1x7ZLZaoM4Ub2YAvkulF0PcasX0kWl+bv/DnkI09x" +
"/n3vgbO2dwKBgQCoAnj6UmeztEDJiKARdo6FHHmtciY7Ozb8Y+Zin38c5C22fJXc" +
"0k+DZ2cdSBwtrQIkOeB9YuIUp1QJV1ubZKz5S4+4ZlvPZW3oBEbOTUtK2U0r/J3/" +
"TR4hD0SD1Pk6j2G8m4Wdaxt+P8KxFyB0p8LCey++/5Yy/56VXlVvGuAzZQKBgQCU" +
"VfcXeMTIplGwpkGcFSzvLCZWDQim/NH/lYdWJUD84cWrNl+7ett4cyADueClLnJT" +
"Z8Xmqq4F8ASJIQxHEY21+1gt3CFCKoe1ueR7taHQBIzhJfVfIarOEGUpOzEJSt0d" +
"DBzrGh2MGomksV4CTuy4V7i5yeHIBBK9lfO2xBQEswKBgQCIzYO53kTFl6YGjmWO" +
"qUJsT+5WegR4GdxtqYpQGPC1RmU7ig1TZzen+X3xB+lIHqgA1HvTr6M+tPkmnMwU" +
"iARPOgjXY0zmsStXaHQYKruT3EjZRs2GnmVpVOAj1asqi+/2t0NgLgB5gPLYMXS+" +
"BGf01OehvUt5Ge+OChDBXSW5Bw==";
//公钥
private static final String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqq6VB2cfzUkbCo0HPYv4" +
"Ahs1PUN6kX+OKZtJTC/RXyX/pvZqPanQBLDJdzdGP51XHRlm/FQa8vncpZijUeFT" +
"3xTRkCllvDrb1JU/ZdyPfzE3f2bKFbdnUHQbzqe/vYawpUvq5sPxxc/NZUQhXJLv" +
"ByCCHBcT0MpUYEsRyPDzFSRKHQbEEkbzsxrc1k34U3xtGNLIGT7e+YSo3Sda06ON" +
"uuABt2M5cR5Zqq60McZmBChJzaZZjVYGtm17zyAmdlT25fcP+dppUqG4N+lTyjM3" +
"ZYU1IBbAAzzGhtj39xqjmthk0rqc4E8s/+eC8heoAm13AJJ0RYB+XsgL+bT6lfQr" +
"KwIDAQAB";
/**
* 使用私钥给入参签名
* @param privateKey 私钥
* @param param 签名的数据
* @return 返回入参签名16进制字符串
* */
public static String sign(String privateKey, String param) {
try {
//获取privatekey
byte[] privateKeyByte = new Base64().decode(privateKey);
KeyFactory keyfactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec encoderule = new PKCS8EncodedKeySpec(privateKeyByte);
PrivateKey key = keyfactory.generatePrivate(encoderule);
//用私钥给入参加签
Signature sign = Signature.getInstance(SIGN_ALGORITHMS);
sign.initSign(key);
sign.update(param.getBytes());
byte[] signature = sign.sign();
//将签名的入参转换成16进制字符串
return bytesToHexStr(signature);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 用公钥验证签名
* @param param 入参
* @param signature 使用私钥签名的入参字符串
* @param publicKey 公钥
* @return 返回验证结果
* */
public static boolean verifyRes(String param,String signature,String publicKey){
try {
//获取公钥
KeyFactory keyFactory=KeyFactory.getInstance("RSA");
byte[] publicKeyByte= new Base64().decode(publicKey);
X509EncodedKeySpec encodeRule=new X509EncodedKeySpec(publicKeyByte);
PublicKey key= keyFactory.generatePublic(encodeRule);
//用获取到的公钥对 入参中未加签参数param 与 入参中的加签之后的参数signature 进行验签
Signature sign=Signature.getInstance(SIGN_ALGORITHMS);
sign.initVerify(key);
sign.update(param.getBytes());
//将16进制码转成字符数组
byte[] hexByte = hexStrToBytes(signature);
//验证签名
return sign.verify(hexByte);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* byte数组转换成十六进制字符串
* @param bytes byte数组
* @return 返回十六进制字符串
*/
private static String bytesToHexStr(byte[] bytes) {
StringBuffer stringBuffer = new StringBuffer("");
for (int i = 0; i < bytes.length; ++i) {
stringBuffer.append(Integer.toHexString(0x0100 + (bytes[i] & 0x00FF)).substring(1).toUpperCase());
}
return stringBuffer.toString();
}
/**
* 十六进制字符串转成byte数组
* @param hexStr 十六进制字符串
* @return 返回byte数组
* */
private static byte[] hexStrToBytes(String hexStr) {
byte[] bytes = new byte[hexStr.length() / 2];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) Integer.parseInt(hexStr.substring(2 * i, 2 * i + 2), 16);
}
return bytes;
}
public static void main(String[] args) {
String param = "yanshao";
String sign = sign(privateKey,param);
System.out.println("签名后的参数>>>"+sign);
System.out.println("验证结果>>>"+verifyRes(param,sign,publicKey));
}
}
3、运行结果
签名后的参数>>>27D167B2B5C0DB4ABBCA38ADBAB56648C372E4306DAF0D815AFD2092CD8F354D280D0F5C9E9FFAD0643C6833255B0FDDFCD366246744ECB079A26046215EEA887836E403A4DC7604F6B1EFE0A2131E2741CFB14DCE1E8BEB40F28D369B1AF19D20295D520620196F3822F2DBA94DFCFC6A7282F74A6B65DB56DFD522894C0C0E1C138CE3BC4EDCD0E47B62E81F857E881045F7EA62D9B9E10678C36183F9350E35BE2221F982AA4ABB4133137827080C35373DC563C0E08190433F012F575979627F91F45EA0A3244DA034A87931042F33EDB60CF7903D595D5C9A1C03B6FCE63A37B26C17EE319E5870EF4E6EFA44CFAA0E6E98CCC9158E0826BE87B4CFC6E1
验证结果>>>true