上文中了解到SHA和RSA,工作中恰好用到扩展应用:SHA256WithRSA,本文总结下学习过程,备忘の

再提供另外一种方法,实现Java版pem密钥和.Net版xml密钥相互转换的方法

密钥转换

准备:引入BouncyCastle.Crypto.dll

  • RSA密钥:Pem --> XML
public static string RSAKeyPemToXml(string pemKey, bool isPrivateKey)
{
string rsaKey = string.Empty;
object pemObject = null;
RSAParameters rsaPara = new RSAParameters();
using (var sReader = new StringReader(pemKey)) {
var pemReader = new Org.BouncyCastle.OpenSsl.PemReader(sReader);
pemObject = pemReader.ReadObject();//(AsymmetricCipherKeyPair)
} if (isPrivateKey)//RSA私钥
{
RsaPrivateCrtKeyParameters key = (RsaPrivateCrtKeyParameters)((AsymmetricCipherKeyPair)pemObject).Private;
rsaPara = new RSAParameters {
Modulus = key.Modulus.ToByteArrayUnsigned(),
Exponent = key.PublicExponent.ToByteArrayUnsigned(),
D = key.Exponent.ToByteArrayUnsigned(),
P = key.P.ToByteArrayUnsigned(),
Q = key.Q.ToByteArrayUnsigned(),
DP = key.DP.ToByteArrayUnsigned(),
DQ = key.DQ.ToByteArrayUnsigned(),
InverseQ = key.QInv.ToByteArrayUnsigned(), };
}
else//RSA公钥
{
RsaKeyParameters key = (RsaKeyParameters)pemObject;
rsaPara = new RSAParameters {
Modulus = key.Modulus.ToByteArrayUnsigned(),
Exponent = key.Exponent.ToByteArrayUnsigned(), };
} RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaPara);
using (StringWriter sw = new StringWriter()) {
sw.Write(rsa.ToXmlString(isPrivateKey ? true : false));
rsaKey = sw.ToString();
}
return rsaKey;
}
  • RSA密钥:XML --> Pem
public static string RSAKeyXmlToPem(string RSAKeyXml, bool isPrivateKey, bool replacefix)
{
string pemKey = string.Empty;
var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(RSAKeyXml); RSAParameters rsaPara = new RSAParameters();
RsaKeyParameters key = null;
//RSA私钥
if (isPrivateKey) {
rsaPara = rsa.ExportParameters(true);
key = new RsaPrivateCrtKeyParameters(
new BigInteger(1, rsaPara.Modulus), new BigInteger(1, rsaPara.Exponent), new BigInteger(1, rsaPara.D),
new BigInteger(1, rsaPara.P), new BigInteger(1, rsaPara.Q), new BigInteger(1, rsaPara.DP), new BigInteger(1, rsaPara.DQ),
new BigInteger(1, rsaPara.InverseQ));
}
//RSA公钥
else {
rsaPara = rsa.ExportParameters(false);
key = new RsaKeyParameters(false,
new BigInteger(1, rsaPara.Modulus), new BigInteger(1, rsaPara.Exponent));
} using (TextWriter sw = new StringWriter()) {
var pemWriter = new Org.BouncyCastle.OpenSsl.PemWriter(sw);
pemWriter.WriteObject(key);
pemWriter.Writer.Flush();
pemKey = sw.ToString();
} if (replacefix) {
//去掉证书的头部和尾部
pemKey = isPrivateKey ? pemKey.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "") :
pemKey.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "");
return pemKey.Replace("\n", "").Replace("\r", "");
}
else { return pemKey; }
}

注意,调用RSAKeyPemToXml()方法时,pemKey必须格式正确(带前后缀且换行),否则调用报错。

-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----

此外,调用RSAKeyXmlToPem()方法做私钥转换时,结果与原Pem密钥不一致,慎用。

密钥转换(java)

  • 公钥:X.509 pem,Java:X509EncodedKeySpec
  • 私钥:PKCS#8 pem,Java:PKCS8EncodedKeySpec
/**
* C#私钥转换成java私钥
*/
public static String privateKeyFromXml(String privateKeyXml) {
privateKeyXml = privateKeyXml.replaceAll("\r", "").replaceAll("\n", ""); KeyFactory keyFactory;
try {
String modulusXml = privateKeyXml.substring(privateKeyXml.indexOf("<Modulus>") + 9, privateKeyXml.indexOf("</Modulus>"));
BigInteger modulus = new BigInteger(1, Base64.getDecoder().decode(modulusXml)); String publicExponentXml = privateKeyXml.substring(privateKeyXml.indexOf("<Exponent>") + 10, privateKeyXml.indexOf("</Exponent>"));
BigInteger publicExponent = new BigInteger(1, Base64.getDecoder().decode(publicExponentXml)); String privateExponentXml = privateKeyXml.substring(privateKeyXml.indexOf("<D>") + 3, privateKeyXml.indexOf("</D>"));
BigInteger privateExponent = new BigInteger(1, Base64.getDecoder().decode(privateExponentXml)); String primePXml = privateKeyXml.substring(privateKeyXml.indexOf("<P>") + 3, privateKeyXml.indexOf("</P>"));
BigInteger primeP = new BigInteger(1, Base64.getDecoder().decode(primePXml)); String primeQXml = privateKeyXml.substring(privateKeyXml.indexOf("<Q>") + 3, privateKeyXml.indexOf("</Q>"));
BigInteger primeQ = new BigInteger(1, Base64.getDecoder().decode(primeQXml)); String primeExponentPXml = privateKeyXml.substring(privateKeyXml.indexOf("<DP>") + 4, privateKeyXml.indexOf("</DP>"));
BigInteger primeExponentP = new BigInteger(1, Base64.getDecoder().decode(primeExponentPXml)); String primeExponentQXml = privateKeyXml.substring(privateKeyXml.indexOf("<DQ>") + 4, privateKeyXml.indexOf("</DQ>"));
BigInteger primeExponentQ = new BigInteger(1, Base64.getDecoder().decode(primeExponentQXml)); String crtCoefficientXml = privateKeyXml.substring(privateKeyXml.indexOf("<InverseQ>") + 10, privateKeyXml.indexOf("</InverseQ>"));
BigInteger crtCoefficient = new BigInteger(1, Base64.getDecoder().decode(crtCoefficientXml)); RSAPrivateCrtKeySpec rsaPriKey = new RSAPrivateCrtKeySpec(modulus, publicExponent, privateExponent, primeP, primeQ, primeExponentP, primeExponentQ, crtCoefficient); keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(rsaPriKey);
byte[] bytes = Base64.getEncoder().encode(privateKey.getEncoded());
return new String(bytes, Charset.forName("utf-8"));
} catch (Exception e) {
System.err.println(e.toString());
}
return null;
} /**
* C#公钥转换成java公钥
*/
public static String publicKeyFromXml(String publicKeyXml) {
KeyFactory keyFactory;
publicKeyXml = publicKeyXml.replaceAll("\r", "").replaceAll("\n", "");
try {
String modulusXml = publicKeyXml.substring(publicKeyXml.indexOf("<Modulus>") + 9, publicKeyXml.indexOf("</Modulus>"));
BigInteger modulus = new BigInteger(1, Base64.getDecoder().decode(modulusXml)); String exponentXml = publicKeyXml.substring(publicKeyXml.indexOf("<Exponent>") + 10, publicKeyXml.indexOf("</Exponent>"));
BigInteger publicExponent = new BigInteger(1, Base64.getDecoder().decode(exponentXml)); RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, publicExponent);
keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(rsaPubKey);
byte[] bytes = Base64.getEncoder().encode(publicKey.getEncoded());
return new String(bytes, Charset.forName("utf-8"));
} catch (Exception e) {
System.err.println(e.toString());
return null;
}
} /**
* java私钥转换成C#私钥
*/
public static String privateKeyToXml(RSAPrivateCrtKey privateKey) { String modulusBase64 = Base64.getEncoder().encodeToString(privateKey.getModulus().toByteArray());
String modulus = modulusBase64.replace("\r", "").replace("\n", ""); String exponentBase64 = Base64.getEncoder().encodeToString(privateKey.getPublicExponent().toByteArray());
String exponent = exponentBase64.replace("\r", "").replace("\n", ""); String pBase64 = Base64.getEncoder().encodeToString(privateKey.getPrimeP().toByteArray());
String p = pBase64.replace("\r", "").replace("\n", ""); String qBase64 = Base64.getEncoder().encodeToString(privateKey.getPrimeQ().toByteArray());
String q = qBase64.replace("\r", "").replace("\n", ""); String dpBase64 = Base64.getEncoder().encodeToString(privateKey.getPrimeExponentP().toByteArray());
String dp = dpBase64.replace("\r", "").replace("\n", ""); String dqBase64 = Base64.getEncoder().encodeToString(privateKey.getPrimeExponentQ().toByteArray());
String dq = dqBase64.replace("\r", "").replace("\n", ""); String dBase64 = Base64.getEncoder().encodeToString(privateKey.getPrivateExponent().toByteArray());
String d = dBase64.replace("\r", "").replace("\n", ""); String inverseQBase64 = Base64.getEncoder().encodeToString(privateKey.getCrtCoefficient().toByteArray());
String inverseQ = inverseQBase64.replace("\r", "").replace("\n", ""); StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<RSAKeyValue>\n");
stringBuilder.append("<Modulus>").append(modulus).append("</Modulus>\n");
stringBuilder.append("<Exponent>").append(exponent).append("</Exponent>\n");
stringBuilder.append("<P>").append(p).append("</P>\n");
stringBuilder.append("<Q>").append(q).append("</Q>\n");
stringBuilder.append("<DP>").append(dp).append("</DP>\n");
stringBuilder.append("<DQ>").append(dq).append("</DQ>\n");
stringBuilder.append("<InverseQ>").append(inverseQ).append("</InverseQ>\n");
stringBuilder.append("<D>").append(d).append("</D>\n");
stringBuilder.append("</RSAKeyValue>");
return stringBuilder.toString();
} /**
* java公钥转换成C#公钥
*/
public static String publicKeyToXml(RSAPublicKey publicKey) {
String modulusBase64 = Base64.getEncoder().encodeToString(publicKey.getModulus().toByteArray());
String modulus = modulusBase64.replace("\r", "").replace("\n", ""); String exponentBase64 = Base64.getEncoder().encodeToString(publicKey.getPublicExponent().toByteArray());
String exponent = exponentBase64.replace("\r", "").replace("\n", ""); StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<RSAKeyValue>\n");
stringBuilder.append("<Modulus>").append(modulus).append("</Modulus>\n");
stringBuilder.append("<Exponent>").append(exponent).append("</Exponent>\n");
stringBuilder.append("</RSAKeyValue>");
return stringBuilder.toString();
}

详见:C#-Java密钥转换

pfx证书

  • PFX证书:由Public Key Cryptography Standards #12,PKCS#12标准定义,包含公钥和私钥的二进制格式的证书形式,以pfx作为证书文件后缀名
  • CER证书:证书中没有私钥,DER编码二进制格式的证书文件/BASE64编码格式的证书文件,以cer作为证书文件后缀名

综上所述:pfx证书文件中比cer文件中多了私钥。

通过pfx证书实现数据签名和验签

public static string Sign(string dataForSign, string priKeyFile, string keyPwd)
{
var rsa = GetPrivateKey(priKeyFile, keyPwd); // Create a new RSACryptoServiceProvider
var rsaClear = new RSACryptoServiceProvider();
// Export RSA parameters from 'rsa' and import them into 'rsaClear'
var paras = rsa.ExportParameters(true);
rsaClear.ImportParameters(paras); using (var sha256 = new SHA256CryptoServiceProvider()) {
var signData = rsaClear.SignData(Encoding.UTF8.GetBytes(dataForSign), sha256);
return BytesToHex(signData);
}
}
public bool VerifySign(string dataForSign, string signedData, string pubKeyFile)
{
var rsa = GetPublicKey(pubKeyFile);
using (var sha256 = new SHA256CryptoServiceProvider()) {
return rsa.VerifyData(Encoding.UTF8.GetBytes(dataForSign), sha256, HexToBytes(signedData));
}
}

其中,从.pfx证书中提取公钥和私钥的方法

private static RSACryptoServiceProvider GetPrivateKey(string priKeyFile, string keyPwd) {
var pc = new X509Certificate2(priKeyFile, keyPwd,
X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
return (RSACryptoServiceProvider)pc.PrivateKey; //return cert.PrivateKey.ToXmlString(true);
} private static RSACryptoServiceProvider GetPublicKey(string pubKeyFile) {
var pc = new X509Certificate2(pubKeyFile);
return (RSACryptoServiceProvider)pc.PublicKey.Key; //return cert.PublicKey.Key.ToXmlString(false);
}

具体参见:.NET版SHA256WithRSA签名验签,java版本参见:java版SHA256withRSA

关于如何生成数字证书,仅供参考:方法1方法2

该文C#创建数字证书并导出为pfx,并使用pfx进行非对称加解密有时间可以研究下。

SHA256WithRSA的更多相关文章

  1. SHA256withRSA证书签名,私钥签名/公钥验签

    证书签名 package test; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundE ...

  2. Delphi支付宝支付【支持SHA1WithRSA(RSA)和SHA256WithRSA(RSA2)签名与验签】

    作者QQ:(648437169) 点击下载➨Delphi支付宝支付             支付宝支付api文档 [Delphi支付宝支付]支持条码支付.扫码支付.交易查询.交易退款.退款查询.交易撤 ...

  3. Delphi RSA签名与验签【支持SHA1WithRSA(RSA1)、SHA256WithRSA(RSA2)和MD5WithRSA签名与验签】

    作者QQ:(648437169) 点击下载➨ RSA签名与验签 [delphi RSA签名与验签]支持3种方式签名与验签(SHA1WithRSA(RSA1).SHA256WithRSA(RSA2)和M ...

  4. Java 签名(SHA1WithRSA、SHA256WithRSA、SHA256withECDSA)

    RSA1.RSA256 签名 public static String MakeSign(String Data) { try { byte[] data = Data.getBytes(); byt ...

  5. Postman实现SHA256withRSA签名

    @ 目录 获取pmlib 引入依赖bundle.js,有以下两种方式: 使用Pre-request Script对请求进行加签(具体加签字段请看自己项目) 获取pmlib 引入依赖bundle.js, ...

  6. 使用SHA256WithRSA来签名和验签(.NET/C#)

    RSACryptoServiceProvider does work with SHA2-based signatures, but you have to invest some effort in ...

  7. C#实现SHA256WithRSA加密用于Java的秘钥私钥

    首先要把Java秘钥进行转换,然后再进行加密 转制秘钥的方法 public static string RSAPrivateKeyJava2DotNet(string privateKey) { Rs ...

  8. Gradle 实现 Android 多渠道定制化打包

    Gradle 实现 Android 多渠道定制化打包 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近在项目中遇到需要实现 Apk 多渠道.定制化打包, Google .百度查找了一些资料, ...

  9. spring boot启用tomcat ssl

    首先要生成一个keystore证书.参考:Tomcat创建HTTPS访问,java访问https,ssl证书生成:cer&jks文件生成摘录,spring-boot 这里复现一下完整过程: 安 ...

随机推荐

  1. swift 日历的制作

    制作日历步骤 1.日期数据的处理,这个可以 添加 extension 解决 extension NSDate{ /*几年几月 这个月的多少天*/ class func getDaysInMonth( ...

  2. 进程间通信之pipe

    实现数据传递 两个进程之间通信 多个进程之间通信,会导致数据不安全,需要加锁,示例 分类 无名管道:父子间进程通信 有名管道:父子间进程通信:任意两个进程之间通信 创建管道方法 os.mkfifo(p ...

  3. tcpreplay使用介绍

    安装 brew install tcpreplay yum install tcpreplay tcpreplay 回放 tcpreplay is a tool for replaying netwo ...

  4. http响应时长分析

    curl -o /dev/null -s -w "time_namelookup:%{time_namelookup}::time_connect:%{time_connect}::time ...

  5. python解包

    概念 python的解包可以这样来理解:把元素给拆分并把其赋值给自己所需要的变量,因此元素应该是一个可迭代对象. 形式 简单版本 下面展示的是解包的基本形式,根据长度赋值给对应多的变量. name_l ...

  6. 一文带你全面了解RxJava

    工作需要,刚好在学习 RxJava网络请求框架,网上搜了一些 关于RxJava 的教程,但都并不是很好理解,所幸最后找到了几篇有助于初学者了解 RxJava 的文章,于是结合自己的理解,重新整理成一篇 ...

  7. 微信小程序之一:动态添加view(view包含picker,input)

    <view wx:for="{{array}}" wx:key="this" class="borderContainer"> ...

  8. 好用的idea插件

    [Alibaba Java Coding Guidelines alibaba]阿里巴巴 代码规约扫描插件. [jRebel]可以热部署Java项目而不用重启. [http://139.199.89. ...

  9. [转帖]ORM框架的前世今生

    ORM框架的前世今生 https://www.cnblogs.com/7tiny/p/9551754.html 目录 一.ORM简介二.ORM的工作原理三.ORM的优缺点四.常见的ORM框架 一.OR ...

  10. 面向对象分析与设计—OOA部分

    第二部分 面向对象分析 2.1 面向对象分析(OOA)的定义? OOA——面向对象的分析,就是运用面向对象方法进行系统分析,对问题域(问题所涉及的范围)和系统责任(所开发的系统应具备的职能)进行分析与 ...