SHA256WithRSA
在上文中了解到SHA和RSA,工作中恰好用到扩展应用:SHA256WithRSA,本文总结下学习过程,备忘の
再提供另外一种方法,实现Java版pem密钥和.Net版xml密钥相互转换的方法
密钥转换
- 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的更多相关文章
- SHA256withRSA证书签名,私钥签名/公钥验签
		
证书签名 package test; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundE ...
 - Delphi支付宝支付【支持SHA1WithRSA(RSA)和SHA256WithRSA(RSA2)签名与验签】
		
作者QQ:(648437169) 点击下载➨Delphi支付宝支付 支付宝支付api文档 [Delphi支付宝支付]支持条码支付.扫码支付.交易查询.交易退款.退款查询.交易撤 ...
 - Delphi RSA签名与验签【支持SHA1WithRSA(RSA1)、SHA256WithRSA(RSA2)和MD5WithRSA签名与验签】
		
作者QQ:(648437169) 点击下载➨ RSA签名与验签 [delphi RSA签名与验签]支持3种方式签名与验签(SHA1WithRSA(RSA1).SHA256WithRSA(RSA2)和M ...
 - Java 签名(SHA1WithRSA、SHA256WithRSA、SHA256withECDSA)
		
RSA1.RSA256 签名 public static String MakeSign(String Data) { try { byte[] data = Data.getBytes(); byt ...
 - Postman实现SHA256withRSA签名
		
@ 目录 获取pmlib 引入依赖bundle.js,有以下两种方式: 使用Pre-request Script对请求进行加签(具体加签字段请看自己项目) 获取pmlib 引入依赖bundle.js, ...
 - 使用SHA256WithRSA来签名和验签(.NET/C#)
		
RSACryptoServiceProvider does work with SHA2-based signatures, but you have to invest some effort in ...
 - C#实现SHA256WithRSA加密用于Java的秘钥私钥
		
首先要把Java秘钥进行转换,然后再进行加密 转制秘钥的方法 public static string RSAPrivateKeyJava2DotNet(string privateKey) { Rs ...
 - Gradle 实现 Android 多渠道定制化打包
		
Gradle 实现 Android 多渠道定制化打包 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近在项目中遇到需要实现 Apk 多渠道.定制化打包, Google .百度查找了一些资料, ...
 - spring boot启用tomcat ssl
		
首先要生成一个keystore证书.参考:Tomcat创建HTTPS访问,java访问https,ssl证书生成:cer&jks文件生成摘录,spring-boot 这里复现一下完整过程: 安 ...
 
随机推荐
- Qt编写气体安全管理系统13-短信告警
			
一.前言 短信告警这个模块在很多项目中都用上了,比如之前做过的安防系统,温湿度报警系统等,主要的流程就是收到数据判断属于某种报警后,组织短信字符串内容,发送到指定的多个手机号码上面,使用的是短信猫硬件 ...
 - build doris 0.11.5 on centos 7/ubuntu
			
doris has envolved many thirdparty components since v0.9. so the build progress has changed a lot si ...
 - 正确删除k8s版本jenkins的pod
			
1.kubectl delete -f jenkins-deployment.yaml 或者先删除pod,再删除对应的depllyment 这两步都要执行否则删除pod不管用 2.删除数据目录下的数据 ...
 - Given a family tree, find out if two people are blood related
			
Given a family tree for a few generations for the entire population and two people write a routine t ...
 - 导入数据到数据库表,报错[Err] [Row1] [Imp] 1153 - Got a packet bigger than 'max_allowed_packet' bytes
			
# 在数据库新增查询,执行如下命令即可: show VARIABLES like '%max_allowed_packet%'; set global max_allowed_packet = 2*1 ...
 - 路由(Routing)
			
路由(Routing) ASP.NET Core MVC 路由是建立在ASP.NET Core 路由的,一项强大的URL映射组件,它可以构建具有理解和搜索网址的应用程序.这使得我们可以自定义应用程序 ...
 - HTTP权威指南-概述
			
URI 统一资源标识符 类似于邮件地址,邮箱. URL 统一资源定位符 URN 统一资源名 HTTP方法 get post put delete post head 状态码 200 OK 302 重定 ...
 - Python——raise引发异常
			
程序出现错误,会自动引发异常,Python也允许使用raise语句自行引发异常. 一.使用raise引发异常 单独一个raise引发异常,默认引发RuntimeError异常,例: try: prin ...
 - PAT(B) 1059 C语言竞赛(C)
			
题目链接:1059 C语言竞赛 (20 point(s)) 题目描述 C 语言竞赛是浙江大学计算机学院主持的一个欢乐的竞赛.既然竞赛主旨是为了好玩,颁奖规则也就制定得很滑稽: 冠军将赢得一份" ...
 - AVR单片机教程——开发板介绍
			
本教程使用EasyElectronics开发板: EasyElectronics是一款基于AVR单片机的开发板.AVR单片机是基于改进的哈佛架构.8~32位的一系列RISC微控制器,最初由Atmel公 ...