RSA非对称加密算法在作加解密的时候用公钥加密,私钥解密;在作数字签名的时候用私钥签名,公钥验证签名。下面就写一个java数字签名的工具类
package cn.cjc.sign;
import org.apache.commons.codec.binary.Base64;
import org.junit.Test;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.*;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* java数字签名和验签工具类
*
* @author chenjc
* @since 2017-06-24
*/
public class SignAndVerifyUtil {
//生成的公钥
private String pubKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9ZdB9JvyoO8EiDPomoO23Bqb4uUxqNRYwIe+Yr6iNgAAznhVPzcZbeiAF6CFuvX4fZhJaaPoiuK6on6zRaa7YVzbzAxcHIRC+oshXYiBDH4qRRDh2IE4iUclP4p9uAPjrJGkmfKPO4ZCj/JeDSxBmPv7oCz3bWvBXn44/APbC9wIDAQAB";
//生成的私钥
private String priKeyStr = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAL1l0H0m/Kg7wSIM+iag7bcGpvi5TGo1FjAh75ivqI2AADOeFU/Nxlt6IAXoIW69fh9mElpo+iK4rqifrNFprthXNvMDFwchEL6iyFdiIEMfipFEOHYgTiJRyU/in24A+OskaSZ8o87hkKP8l4NLEGY+/ugLPdta8Fefjj8A9sL3AgMBAAECgYEAoqPJ048lK/qUMP9f2MgdGiyWOcQ1gIax1QdvTniZj1k50xmPR4Z3LZrD4Q6jlwsWQTRP0l+PXT2mjpr/tpzATQDDf5TH0ZOGzeadD57Pp0+lmEN/4OiTyhAz09ZsrDq39QVvzfAPLHuBAzduHU1eefiiyHYIz3yZ/I9I7+aAS1ECQQDjvEdGaQI80wWJEjwGFPDE/Tjfx1jo4ODd2ZumSbKM7PK7N3KG2vPsi4kkj1T6GXx9dNXIsqiAuIthALHGC+GDAkEA1OdzTYI4n8B+81w2JMwXmEtHOqfOvzBAsqNdeEb7Xgw1RKUcLL9vzSf5GThQQMWIqQ3UByqZ/I4X4HUxF1zifQJBAJWNqUjl4OBMvA/d96kOy2ax3E2ovgyA0WsfYoX7U9QULvsfWIiS9SjcIX3u2qE7Z3OD7HjWSq3tgyp6qEQkvT0CQHEIOFUML9fQsRWu/SfoGxbF0Jk5gjBLA+5TgUpcFRRHUviQ2DaBpG+9KyjSlvjsZrOqHcl4Oqy1G8QVM+z9aVkCQQDFxF26mh/H3I0ZMBZHLHL0/mBlkKEPcf0POwOFrw92579LkyLt0zX+gDmH6ANUewhEEutQf13KAIe4+8Yyu2QS";
//待签名数据
private String data = "你好,我是007!";
//已签名数据
private String signedData = "n%2F3uUg1Fah32d6f1vIKk3PlUPFPC2MhIeQ%2BmPEXL9jA9dWNsWqoYM6vlMkzztOkNDgPa0NhLJ7suJKeJuos%2FS9vMA0%2BQv6yx6Mxn1Iz4oLZUZfvoVbozbGcvp%2BB2fzFVeQNNcppt2QgFMpvMLJqyf%2FmqsVuqTgzcSW8ZFxiA3Zc%3D";
/**
* 生成公钥和私钥
*/
@Test
public void createKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
keygen.initialize(1024);
KeyPair keys = keygen.generateKeyPair();
PublicKey pubKey = keys.getPublic();
PrivateKey priKey = keys.getPrivate();
// 获取base64编码的公钥
System.out.println("pubKeyStr=" + Base64.encodeBase64String(pubKey.getEncoded()));
// 获取base64编码的私钥
System.out.println("priKeyStr=" + Base64.encodeBase64String(priKey.getEncoded()));
}
/**
* 私钥签名
*/
@Test
public void sign() throws Exception {
KeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(priKeyStr));
KeyFactory factory = KeyFactory.getInstance("RSA");
PrivateKey key = factory.generatePrivate(keySpec);
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(key);
signature.update(data.getBytes("utf-8"));//使用UTF-8编码
byte[] signed = signature.sign();//签名后的字节流数据
String base64Encode = Base64.encodeBase64String(signed);//将字节流数据编码成字符串,以方便传输
String urlEncode = URLEncoder.encode(base64Encode, "utf-8");//由于BASE64编码可能会产生“+”、“/”、“=”等符号,不利于HTTP传输,所以对BASE64编码再进行一次URL编码
System.out.println("signedData=" + urlEncode);
}
/**
* 公钥验签
*/
@Test
public void verify() throws Exception {
KeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(pubKeyStr));
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey key = factory.generatePublic(keySpec);
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initVerify(key);
signature.update(data.getBytes("utf-8"));//使用UTF-8编码
String urlDecode = URLDecoder.decode(signedData, "utf-8");
byte[] base64Decode = Base64.decodeBase64(urlDecode);
if (signature.verify(base64Decode)) {//验证签名
System.out.println("签名有效!");
} else {
System.out.println("签名无效!");
}
}
}
如果签名的一方是java应用,验签的一方是C#应用,则通过createKeyPair
方法产生的公钥不能直接给C#应用对接,对接前需要先把java公钥转换成c#格式的公钥。详见各种密钥转换工具方法
package cn.cjc.sign;
import org.apache.commons.codec.binary.Base64;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.*;
public class KeyConvertUtil {
/**
* JAVA字节流格式的公钥转换成C#兼容的xml格式
*
* @param encodedPublicKey java公钥
* @return c#公钥
* @throws Exception
*/
public static String publicKey2Xml(byte[] encodedPublicKey)
throws Exception {
KeySpec keySpec = new X509EncodedKeySpec(encodedPublicKey);
KeyFactory factory = KeyFactory.getInstance("RSA");
RSAPublicKey publicKey = (RSAPublicKey) factory.generatePublic(keySpec);
StringBuffer sb = new StringBuffer(1024);
sb.append("<RSAKeyValue>");
sb.append("<Modulus>"
+ Base64.encodeBase64String(removeMSZero(publicKey.getModulus()
.toByteArray())) + "</Modulus>");
sb.append("<Exponent>"
+ Base64.encodeBase64String(removeMSZero(publicKey.getPublicExponent()
.toByteArray())) + "</Exponent>");
sb.append("</RSAKeyValue>");
return sb.toString();
}
/**
* JAVA字节流格式的私钥转换成C#兼容的xml格式
*
* @param encodedPrivateKey java私钥
* @return c#私钥
* @throws Exception
*/
public static String privateKey2Xml(byte[] encodedPrivateKey) throws Exception {
KeySpec keySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
KeyFactory factory = KeyFactory.getInstance("RSA");
RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) factory.generatePrivate(keySpec);
StringBuffer sb = new StringBuffer(1024);
sb.append("<RSAKeyValue>");
sb.append("<Modulus>"
+ Base64.encodeBase64String(removeMSZero(privateKey.getModulus()
.toByteArray())) + "</Modulus>");
sb.append("<Exponent>"
+ Base64.encodeBase64String(removeMSZero(privateKey.getPublicExponent()
.toByteArray())) + "</Exponent>");
sb.append("<P>"
+ Base64.encodeBase64String(removeMSZero(privateKey.getPrimeP()
.toByteArray())) + "</P>");
sb.append("<Q>"
+ Base64.encodeBase64String(removeMSZero(privateKey.getPrimeQ()
.toByteArray())) + "</Q>");
sb.append("<DP>"
+ Base64.encodeBase64String(removeMSZero(privateKey.getPrimeExponentP()
.toByteArray())) + "</DP>");
sb.append("<DQ>"
+ Base64.encodeBase64String(removeMSZero(privateKey.getPrimeExponentQ()
.toByteArray())) + "</DQ>");
sb.append("<InverseQ>"
+ Base64.encodeBase64String(removeMSZero(privateKey.getCrtCoefficient()
.toByteArray())) + "</InverseQ>");
sb.append("<D>"
+ Base64.encodeBase64String(removeMSZero(privateKey
.getPrivateExponent().toByteArray())) + "</D>");
sb.append("</RSAKeyValue>");
return sb.toString();
}
private static byte[] removeMSZero(byte[] data) {
byte[] data1;
int len = data.length;
if (data[0] == 0) {
data1 = new byte[data.length - 1];
System.arraycopy(data, 1, data1, 0, len - 1);
} else
data1 = data;
return data1;
}
private static String getMiddleString(String source, String strHead,
String strTail) {
try {
int indexHead, indexTail;
if (strHead == null || strHead.isEmpty()) {
indexHead = 0;
} else {
indexHead = source.indexOf(strHead);
}
if (strTail == null || strTail.isEmpty()) {
indexTail = source.length();
} else {
indexTail = source.indexOf(strTail,
indexHead + strHead.length());
}
if (indexTail < 0) {
indexTail = source.length();
}
String rtnStr = "";
if ((indexHead >= 0) && (indexTail >= 0)) {
rtnStr = source.substring(indexHead + strHead.length(),
indexTail);
}
return rtnStr;
} catch (Exception ex) {
return "";
}
}
/**
* C#兼容的xml格式公钥转换成JAVA公钥
*
* @param publicKeyXml c#公钥
* @return java公钥
*/
public static PublicKey xml2PublicKey(String publicKeyXml) {
publicKeyXml = publicKeyXml.replaceAll("\r", "").replaceAll("\n", "");
BigInteger modulus = new BigInteger(1,
Base64.decodeBase64(getMiddleString(publicKeyXml, "<Modulus>",
"</Modulus>")));
BigInteger publicExponent = new BigInteger(1,
Base64.decodeBase64(getMiddleString(publicKeyXml, "<Exponent>",
"</Exponent>")));
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);
try {
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePublic(keySpec);
} catch (Exception e) {
return null;
}
}
/**
* C#兼容的xml格式私钥转换成JAVA私钥
*
* @param privateKeyXml c#私钥
* @return java私钥
*/
public static PrivateKey xml2PrivateKey(String privateKeyXml) {
privateKeyXml = privateKeyXml.replaceAll("\r", "").replaceAll("\n", "");
BigInteger modulus = new BigInteger(1,
Base64.decodeBase64(getMiddleString(privateKeyXml, "<Modulus>",
"</Modulus>")));
BigInteger publicExponent = new BigInteger(1,
Base64.decodeBase64(getMiddleString(privateKeyXml, "<Exponent>",
"</Exponent>")));
BigInteger privateExponent = new BigInteger(1,
Base64.decodeBase64(getMiddleString(privateKeyXml, "<D>", "</D>")));
BigInteger primeP = new BigInteger(1,
Base64.decodeBase64(getMiddleString(privateKeyXml, "<P>", "</P>")));
BigInteger primeQ = new BigInteger(1,
Base64.decodeBase64(getMiddleString(privateKeyXml, "<Q>", "</Q>")));
BigInteger primeExponentP = new BigInteger(1,
Base64.decodeBase64(getMiddleString(privateKeyXml, "<DP>",
"</DP>")));
BigInteger primeExponentQ = new BigInteger(1,
Base64.decodeBase64(getMiddleString(privateKeyXml, "<DQ>",
"</DQ>")));
BigInteger crtCoefficient = new BigInteger(1,
Base64.decodeBase64(getMiddleString(privateKeyXml, "<InverseQ>",
"</InverseQ>")));
RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(modulus,
publicExponent, privateExponent, primeP, primeQ,
primeExponentP, primeExponentQ, crtCoefficient);
try {
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePrivate(keySpec);
} catch (Exception e) {
return null;
}
}
}