nodejs和java通过RSA进行签名和验签的两种方式
2019-06-14 本文已影响0人
繁华落尽ing
前言
- 通常我们使用的是标准的PEM证书,PEM证书是OpenSSL的标准格式,详细信息可以百度。
- PEM格式信息最大的特点是会带头信息和尾信息。公钥:
-----BEGIN PUBLIC KEY-----
、-----END PUBLIC KEY-----
。私钥-----BEGIN PRIVATE KEY-----
、-----END PRIVATE KEY-----"
- 简述下利用openssl生成pem的过程:
- 1.生成RSA私钥 通常大于512,选择1024或者2048
openssl genrsa -out rsa_private_key.pem 1024
- 2.需要转换成RSA私钥转换成PKCS8格式
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem-outform PEM -nocrypt
- 3.生成RSA公钥
openssl rsa -in rsa_private_key.pem-pubout -out rsa_public_key.pem
通过PEM进行加密、解密、签名、验签
java端核心操作流程
1.Java通过RSA对数据进行加密、解密、签名、验签的流程。
1)私钥签名
a)获取私钥
//获取KeyFactory,指定RSA算法
KeyFactorykeyFactory = KeyFactory.getInstance("RSA");
//将BASE64编码的私钥字符串进行解码
BASE64Decoderdecoder = newBASE64Decoder();
byte[] encodeByte = decoder.decodeBuffer(priKey);
//将BASE64解码后的字节数组,构造成PKCS8EncodedKeySpec对象,生成私钥对象
PrivateKeyprivatekey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodeByte));
b)使用私钥,对数据进行签名
//获取Signature实例,指定签名算法(本例使用SHA1WithRSA)
Signaturesignature = Signature.getInstance("SHA1WithRSA");
//加载私钥
signature.initSign(privatekey);
//更新待签名的数据
signature.update(plain.getBytes("UTF-8"));
//进行签名
byte[] signed = signature.sign();
//将加密后的字节数组,转换成BASE64编码的字符串,作为最终的签名数据
BASE64Encoderencoder = newBASE64Encoder();
return encoder.encode(signed);
2)公钥验签
a)获取公钥
//获取KeyFactory,指定RSA算法
KeyFactorykeyFactory = KeyFactory.getInstance("RSA");
//将BASE64编码的公钥字符串进行解码
BASE64Decoderdecoder = newBASE64Decoder();
byte[] encodeByte = decoder.decodeBuffer(pubKey);
//将BASE64解码后的字节数组,构造成X509EncodedKeySpec对象,生成公钥对象
PublicKeypublicKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodeByte));
b)使用公钥,进行验签
//获取Signature实例,指定签名算法(与之前一致)
Signaturesignature = Signature.getInstance("SHA1WithRSA");
//加载公钥
signature.initVerify(publicKey);
//更新原数据
signature.update(plain.getBytes("UTF-8"));
//公钥验签(true-验签通过;false-验签失败)
BASE64Decoderdecoder = newBASE64Decoder();
return signature.verify(decoder.decodeBuffer(sign));
Nodejs通过RSA进行签名和验签
1.按照相关包
npm install node-rsa --save
2.首先生成key
使用的私钥是由java端生成的
require node-rsa包
const NodeRSA = require('node-rsa');
const key = new NodeRSA({
b: 1024
});
key.importKey(privateKey, 'pkcs8'); // privateKey 带头尾的格式化的字符串
key.setOptions({ signingScheme: 'sha256' });//指定加密格式
a)nodejs进行签名
key.sign(buffer, [encoding], [source_encoding]);
b)nodejs进行验签
key.verify(buffer, signature, [source_encoding], [signature_encoding]) //Return result of check, true or false.
划重点了
现实情况下,Java有自己的KeyPairGenerator类可以自己生成公钥和私钥,并不用借助openssl。导致其他语言比较nodejs和python统一不了私钥和公钥的格式。最大的区别是KeyPairGenerator生成的是字符串形式的KEY而不是PEM格式的。
Java生成公钥和私钥
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = null;
try {
keyPairGen = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(2048, new SecureRandom());
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
// 得到私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 得到公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 得到公钥字符串
String publicKeyString = Base64.encode(publicKey.getEncoded());
// 得到私钥字符串
String privateKeyString = Base64.encode(privateKey.getEncoded());
Java签名 同上
* RSA签名
*
* @param content 待签名数据
* @param privateKey 商户私钥
* @param encode 字符集编码
* @return 签名值
*/
public static String sign(String content, String privateKey, String encode) {
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decode(privateKey));
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
signature.initSign(priKey);
signature.update(content.getBytes(encode));
byte[] signed = signature.sign();
return Base64.encode(signed);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Java 验签
/**
* RSA验签名检查
*
* @param content 待签名数据
* @param sign 签名值
* @param publicKey 分配给开发商公钥
* @param encode 字符集编码
* @return 布尔值
*/
public static boolean doCheck(String content, String sign, String publicKey, String encode) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64.decode(publicKey);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
signature.initVerify(pubKey);
signature.update(content.getBytes(encode));
boolean bverify = signature.verify(Base64.decode(sign));
return bverify;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
node 的签名和验签
辅助工作
- 需要借助转换函数转换成PEM格式
function insertStr(str, insertStr, sn) {
var newstr = '';
for (var i = 0; i < str.length; i += sn) {
var tmp = str.substring(i, i + sn);
newstr += tmp + insertStr;
}
return newstr;
}
const getPrivateKey = function(key) {
const result = insertStr(key, '\n', 64);
return '-----BEGIN PRIVATE KEY-----\n' + result + '-----END PRIVATE KEY-----';
};
const getPublicKey = function(key) {
const result = insertStr(key, '\n', 64);
return '-----BEGIN PUBLIC KEY-----\n' + result + '-----END PUBLIC KEY-----';
};
2.签名
const key = new NodeRSA({
b: 2048 //可以知道位数
});
key.importKey(privateKey, 'pkcs8'); //根据java端模式
key.setOptions({ signingScheme: 'sha256' });//指定加密格式
// API key.sign(buffer, [encoding], [source_encoding]);
let sign = key.sign(noSign, 'base64', 'utf8');