上文中了解到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. RabbitMQ 入门教程(PHP版) 第二部分:工作队列(Work queues)

    工作队列 在第一篇教程中,我们已经写了一个从已知队列中发送和获取消息的程序.在这篇教程中,我们将创建一个工作队列(Work Queue),它会发送一些耗时的任务给多个工作者(Works ). 工作队列 ...

  2. 123457123456#0#-----com.ppGame.huaHua65--前拼后广--儿童填色-pp

    com.ppGame.huaHua65--前拼后广--儿童填色-pp

  3. Django Model 定义语法

    简单用法 from django.db import models class Person(models.Model): first_name = models.CharField(max_leng ...

  4. 基于Python中numpy数组的合并实例讲解

    基于Python中numpy数组的合并实例讲解 下面小编就为大家分享一篇基于Python中numpy数组的合并实例讲解,具有很好的参考价值,希望对大家有所帮助.一起跟随小编过来看看吧 Python中n ...

  5. POJ 3903 Stock Exchange 最长上升子序列入门题

    题目链接:http://poj.org/problem?id=3903 最长上升子序列入门题. 算法时间复杂度 O(n*logn) . 代码: #include <iostream> #i ...

  6. 看烦了VS2012的黑白调调了吗?换

    VS2012的默认深色主题的确让整个IDE看起来很有气场,而且深色的主题保护眼睛,还是蛮不错的.但是看久了也会烦啊.虽然说重要的不是IDE看起来怎么样,而是写出来的代码质量怎么样,但一个好的环境也是会 ...

  7. nlp算法

    人工智能算法大体上来说可以分类两类:基于统计的机器学习算法(Machine Learning)和深度学习算法(Deep Learning) 总的来说,在sklearn中机器学习算法大概的分类如下: 1 ...

  8. git实现码云的上传和下载

    上传步骤: 1.码云上新建一个项目 XXXX? ?(项目名) 2.本地创建一个文件夹E:/XXXX,然后使用git bash? ?? 3.cd 到本地文件夹中E:/XXXX? //如果是在创建的文件中 ...

  9. php实现映射

    目录 映射 实现 链表实现: 二叉树实现 复杂度分析 映射 映射,或者射影,在数学及相关的领域经常等同于函数.基于此,部分映射就相当于部分函数,而完全映射相当于完全函数. 映射(Map)是用于存取键值 ...

  10. MIT6.824食用过程

    MIT6.824食用过程 Lab1 MapReduce 一.介绍 本实验使用Go语言构建一个mapreduce库,以及一个容错的分布式系统.第一部分完成一个简单的mapreduce程序,第二部分写一个 ...