一、简介:
rsa加密算法是最常用的非对称加密算法,cfca在证书服务中离不了它。rsa是第一个比较完善的公开密钥算法,它既能用于加密,也能用于数字签名。这个算法经受住了多年深入的密码分析,虽然密码分析者既不能证明也不能否定rsa的安全性,但这恰恰说明该算法有一定的可信性,目前它已经成为最流行的公开密钥算法。
二、rsa的公钥、私钥的组成,以及加密、解密的公式可见于下表
三、使用方式:
① 假设a、b机器进行通信,已a机器为主;
② a首先需要用自己的私钥为发送请求数据签名,并将公钥一同发送给b;
③ b收到数据后,需要用a发送的公钥进行验证,已确保收到的数据是未经篡改的;
④ b验签通过后,处理逻辑,并把处理结果返回,返回数据需要用a发送的公钥进行加密(公钥加密后,只能用配对的私钥解密);
⑤ a收到b返回的数据,使用私钥解密,至此,一次数据交互完成。
四、代码示例:
1、第一步获取私钥,为签名做准备。
/**
* 读取私钥 返回privatekey
* @param path 包含私钥的证书路径
* @param password 私钥证书密码
* @return 返回私钥privatekey
* @throws keystoreexception
* @throws nosuchalgorithmexception
* @throws certificateexception
* @throws ioexception
* @throws unrecoverablekeyexception
*/
private static privatekey getprivatekey(string path,string password)
throws keystoreexception, nosuchalgorithmexception, certificateexception,
ioexception, unrecoverablekeyexception {
keystore ks = keystore.getinstance("pkcs12");
fileinputstream fis = new fileinputstream(path);
char[] npassword = null;
if ((password == null) || password.trim().equals("")) {
npassword = null;
} else {
npassword = password.tochararray();
}
ks.load(fis, npassword);
fis.close();
enumeration<string> en = ks.aliases();
string keyalias = null;
if (en.hasmoreelements()) {
keyalias = (string) en.nextelement();
return (privatekey) ks.getkey(keyalias, npassword);
}
2、签名示例:通过第一步得到的私钥,进行签名操作,具体请看以下代码:
* 私钥签名: 签名方法如下:base64(rsa(md5(src),privatekey)),其中src为需要签名的字符串,
privatekey是商户的cfca证书私钥。
* @param plaintext 待签名字符串
* @param path 签名私钥路径
* @param password 签名私钥密码
* @return 返回签名后的字符串
* @throws exception
public static string sign(string plaintext,string path,string password)
throws exception {
/*
* md5加密
*/
messagedigest md5 = messagedigest.getinstance("md5");
md5.update(plaintext.getbytes("utf-8"));
byte[] digestbytes = md5.digest();
* 用私钥进行签名 rsa
cipher cipher = cipher.getinstance("rsa/ecb/pkcs1padding");
//encrypt_mode表示为加密模式
cipher.init(cipher.encrypt_mode, getprivatekey(path, password));
//加密
byte[] rsabytes = cipher.dofinal(digestbytes);
//base64编码
return base64.bytearraytobase64(rsabytes);
3、b收到数据后,需要使用a提供的公钥信息进行验签,此处使用公钥的n、e进行验签
首先通过公钥n、e得到公钥publickey,如下:
/**
* 根据公钥n、e生成公钥
* @param modulus 公钥n串
* @param publicexponent 公钥e串
* @return 返回公钥publickey
public static publickey getpublickkey(string modulus, string publicexponent)
throws exception {
keyspec publickeyspec = new rsapublickeyspec(
new biginteger(modulus, 16), new biginteger(publicexponent, 16));
keyfactory factory = keyfactory.getinstance("rsa");
publickey publickey = factory.generatepublic(publickeyspec);
return publickey;
得到公钥publickey后,再去验证签名,代码如下:
* 用公钥证书进行验签
* @param message 签名之前的原文
* @param ciphertext 签名
* @param pubkeyn 公钥n串
* @param pubkeye 公钥e串
* @return boolean 验签成功为true,失败为false
public static boolean verify(string message, string ciphertext,string pubkeyn,
string pubkeye) throws exception {
cipher c4 = cipher.getinstance("rsa/ecb/pkcs1padding");
// 根据密钥,对cipher对象进行初始化,decrypt_mode表示解密模式
c4.init(cipher.decrypt_mode, getpublickkey(pubkeyn,pubkeye));
// 解密
byte[] desdectextbytes = c4.dofinal(base64.base64tobytearray(ciphertext));
// 得到前置对原文进行的md5
string md5digest1 = base64.bytearraytobase64(desdectextbytes);
md5.update(message.getbytes("utf-8"));
// 得到商户对原文进行的md5
string md5digest2 = base64.bytearraytobase64(digestbytes);
// 验证签名
if (md5digest1.equals(md5digest2)) {
return true;
return false;
至此,签名验签已经完毕
4、提供一个从.cer文件读取公钥的方法:
* 读取公钥cer
* @param path .cer文件的路径 如:c:/abc.cer
* @return base64后的公钥串
public static string getpublickey(string path) throws ioexception,
certificateexception{
inputstream instream = new fileinputstream(path);
bytearrayoutputstream out = new bytearrayoutputstream();
int ch;
string res = "";
while ((ch = instream.read()) != -1) {
out.write(ch);
byte[] result = out.tobytearray();
res = base64.bytearraytobase64(result);
return res;
====================================分割线================================
最新内容请见作者的github页:http://qaseven.github.io/