C#.NET RSA 私钥签名 公钥验证签名 公钥验签

1.待签名字符串转为byte数组时,一般使用UTF8。

2.将私钥字符串(PKCS8或PKCS1格式)转为C#.NET的RSACryptoServiceProvider对象。

3.使用RSACryptoServiceProvider对象的SignData方法算出签名值,结果为byte数组。

4.签名值是byte数组,不便于传输,一般是转为BASE64字符串来传输。

5.RSACryptoServiceProvider对象+SHA256算法,对标JAVA的SHA256withRSA。

6.openssl生成的私钥默认是PKCS1的,示例中是转成了PKCS8格式,在解决方案的“公私钥”文件夹,用记事本打开,填入程序即可。

私钥签名:

private void btnSign_Click(object sender, EventArgs e)
{
try
{
if (string.IsNullOrWhiteSpace(txtPrivateKey.Text) || string.IsNullOrWhiteSpace(txtToSignStr.Text))
{
MessageBox.Show("私钥和字符串不能为空");
return;
} //SHA256withRSA
string fnstr = txtToSignStr.Text;//待签名字符串
//1。转换私钥字符串为RSACryptoServiceProvider对象
RSACryptoServiceProvider rsaP = RsaUtil.LoadPrivateKey(txtPrivateKey.Text, "PKCS8");
byte[] data = Encoding.UTF8.GetBytes(fnstr);//待签名字符串转成byte数组,UTF8
byte[] byteSign = rsaP.SignData(data, "SHA256");//对应JAVA的RSAwithSHA256
string sign = Convert.ToBase64String(byteSign);//签名byte数组转为BASE64字符串 txtSign.Text = sign;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

公钥验证签名:

private void button1_Click(object sender, EventArgs e)
{
try
{
if (string.IsNullOrWhiteSpace(txtPubKey.Text) || string.IsNullOrWhiteSpace(txtToSignStr.Text) || string.IsNullOrWhiteSpace(txtSign.Text))
{
MessageBox.Show("公钥,签名字符串,签名 不能为空");
return;
}
byte[] signature = Convert.FromBase64String(txtSign.Text);//签名值转为byte数组
//SHA256withRSA
string fnstr = txtToSignStr.Text;
//1。转换私钥字符串为RSACryptoServiceProvider对象
RSACryptoServiceProvider rsaP = RsaUtil.LoadPublicKey(txtPubKey.Text );
byte[] data = Encoding.UTF8.GetBytes(fnstr);//待签名字符串转成byte数组,UTF8
bool validSign = rsaP.VerifyData(data, "SHA256", signature);//对应JAVA的RSAwithSHA256 if(validSign)
lblValidRst.Text = "验证签名通过:"+DateTime.Now.ToString();
else
lblValidRst.Text = "验证签名 不通过:" + DateTime.Now.ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

工具类:

using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks; namespace CommonUtils
{
public static class RsaUtil
{
#region 加载私钥 /// <summary>
/// 转换私钥字符串为RSACryptoServiceProvider
/// </summary>
/// <param name="privateKeyStr">私钥字符串</param>
/// <param name="keyFormat">PKCS8,PKCS1</param>
/// <param name="signType">RSA 私钥长度1024 ,RSA2 私钥长度2048</param>
/// <returns></returns>
public static RSACryptoServiceProvider LoadPrivateKey(string privateKeyStr, string keyFormat)
{
string signType = "RSA";
if (privateKeyStr.Length > 1024)
{
signType = "RSA2";
}
//PKCS8,PKCS1
if (keyFormat == "PKCS1")
{
return LoadPrivateKeyPKCS1(privateKeyStr, signType);
}
else
{
return LoadPrivateKeyPKCS8(privateKeyStr);
}
} /// <summary>
/// PKCS1 格式私钥转 RSACryptoServiceProvider 对象
/// </summary>
/// <param name="strKey">pcsk1 私钥的文本内容</param>
/// <param name="signType">RSA 私钥长度1024 ,RSA2 私钥长度2048 </param>
/// <returns></returns>
public static RSACryptoServiceProvider LoadPrivateKeyPKCS1(string privateKeyPemPkcs1, string signType)
{
try
{
privateKeyPemPkcs1 = privateKeyPemPkcs1.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();
privateKeyPemPkcs1 = privateKeyPemPkcs1.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim(); byte[] data = null;
//读取带 data = Convert.FromBase64String(privateKeyPemPkcs1); RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(data, signType);
return rsa;
}
catch (Exception ex)
{
throw ex;
}
return null;
} private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey, string signType)
{
byte[] MODULUS, E, D, P, Q, DP, DQ, IQ; // --------- Set up stream to decode the asn.1 encoded RSA private key ------
MemoryStream mem = new MemoryStream(privkey);
BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
byte bt = 0;
ushort twobytes = 0;
int elems = 0;
try
{
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8230)
binr.ReadInt16(); //advance 2 bytes
else
return null; twobytes = binr.ReadUInt16();
if (twobytes != 0x0102) //version number
return null;
bt = binr.ReadByte();
if (bt != 0x00)
return null; //------ all private key components are Integer sequences ----
elems = GetIntegerSize(binr);
MODULUS = binr.ReadBytes(elems); elems = GetIntegerSize(binr);
E = binr.ReadBytes(elems); elems = GetIntegerSize(binr);
D = binr.ReadBytes(elems); elems = GetIntegerSize(binr);
P = binr.ReadBytes(elems); elems = GetIntegerSize(binr);
Q = binr.ReadBytes(elems); elems = GetIntegerSize(binr);
DP = binr.ReadBytes(elems); elems = GetIntegerSize(binr);
DQ = binr.ReadBytes(elems); elems = GetIntegerSize(binr);
IQ = binr.ReadBytes(elems); // ------- create RSACryptoServiceProvider instance and initialize with public key -----
CspParameters CspParameters = new CspParameters();
CspParameters.Flags = CspProviderFlags.UseMachineKeyStore; int bitLen = 1024;
if ("RSA2".Equals(signType))
{
bitLen = 2048;
} RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(bitLen, CspParameters);
//RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); RSAParameters RSAparams = new RSAParameters();
RSAparams.Modulus = MODULUS;
RSAparams.Exponent = E;
RSAparams.D = D;
RSAparams.P = P;
RSAparams.Q = Q;
RSAparams.DP = DP;
RSAparams.DQ = DQ;
RSAparams.InverseQ = IQ;
RSA.ImportParameters(RSAparams);
return RSA;
}
catch (Exception ex)
{
throw ex;
// return null;
}
finally
{
binr.Close();
}
} private static int GetIntegerSize(BinaryReader binr)
{
byte bt = 0;
byte lowbyte = 0x00;
byte highbyte = 0x00;
int count = 0;
bt = binr.ReadByte();
if (bt != 0x02) //expect integer
return 0;
bt = binr.ReadByte(); if (bt == 0x81)
count = binr.ReadByte(); // data size in next byte
else
if (bt == 0x82)
{
highbyte = binr.ReadByte(); // data size in next 2 bytes
lowbyte = binr.ReadByte();
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
count = BitConverter.ToInt32(modint, 0);
}
else
{
count = bt; // we already have the data size
} while (binr.ReadByte() == 0x00)
{ //remove high order zeros in data
count -= 1;
}
binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte
return count;
} /// <summary>
/// PKCS8 文本转RSACryptoServiceProvider 对象
/// </summary>
/// <param name="privateKeyPemPkcs8"></param>
/// <returns></returns>
public static RSACryptoServiceProvider LoadPrivateKeyPKCS8(string privateKeyPemPkcs8)
{ try
{
//PKCS8是“BEGIN PRIVATE KEY”
privateKeyPemPkcs8 = privateKeyPemPkcs8.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();
privateKeyPemPkcs8 = privateKeyPemPkcs8.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim(); //pkcs8 文本先转为 .NET XML 私钥字符串
string privateKeyXml = RSAPrivateKeyJava2DotNet(privateKeyPemPkcs8); RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
publicRsa.FromXmlString(privateKeyXml);
return publicRsa;
}
catch (Exception ex)
{
throw ex;
}
} /// <summary>
/// PKCS8 私钥文本 转 .NET XML 私钥文本
/// </summary>
/// <param name="privateKeyPemPkcs8"></param>
/// <returns></returns>
public static string RSAPrivateKeyJava2DotNet(string privateKeyPemPkcs8)
{
RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKeyPemPkcs8));
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
} #endregion /// <summary>
/// 加载公钥证书
/// </summary>
/// <param name="publicKeyCert">公钥证书文本内容</param>
/// <returns></returns>
public static RSACryptoServiceProvider LoadPublicCert(string publicKeyCert)
{ publicKeyCert = publicKeyCert.Replace("-----BEGIN CERTIFICATE-----", "").Replace("-----END CERTIFICATE-----", "").Replace("\r", "").Replace("\n", "").Trim(); byte[] bytesCerContent = Convert.FromBase64String(publicKeyCert);
X509Certificate2 x509 = new X509Certificate2(bytesCerContent);
RSACryptoServiceProvider rsaPub = (RSACryptoServiceProvider)x509.PublicKey.Key;
return rsaPub; } /// <summary>
/// pem 公钥文本 转 .NET RSACryptoServiceProvider。
/// </summary>
/// <param name="publicKeyPem"></param>
/// <returns></returns>
public static RSACryptoServiceProvider LoadPublicKey(string publicKeyPem)
{ publicKeyPem = publicKeyPem.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("\r", "").Replace("\n", "").Trim(); //pem 公钥文本 转 .NET XML 公钥文本。
string publicKeyXml = RSAPublicKeyJava2DotNet(publicKeyPem); RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
publicRsa.FromXmlString(publicKeyXml);
return publicRsa; } /// <summary>
/// pem 公钥文本 转 .NET XML 公钥文本。
/// </summary>
/// <param name="publicKey"></param>
/// <returns></returns>
private static string RSAPublicKeyJava2DotNet(string publicKey)
{
RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
} }
}

-源码:https://gitee.com/runliuv/mypub/tree/master/donetproj

C#.NET RSA 私钥签名 公钥验证签名的更多相关文章

  1. iOS使用Security.framework进行RSA 加密解密签名和验证签名

    iOS 上 Security.framework为我们提供了安全方面相关的api: Security框架提供的RSA在iOS上使用的一些小结 支持的RSA keySize 大小有:512,768,10 ...

  2. openssl生成签名与验证签名

    继上一篇RSA对传输信息进行加密解密,再写个生成签名和验证签名. 一般,安全考虑,比如接入支付平台时,请求方和接收方要互相验证是否是你,就用签名来看. 签名方式一般两种,对称加密和非对称加密.对称加密 ...

  3. 求求你们不要再用 RSA 私钥加密公钥解密了,这非常不安全!

    最近经常在网上看到有人说巨硬的 CNG(Cryptography Next Generation 即下一代加密技术) 只提供 RSA 公钥加密私钥解密,没有提供 RSA 私钥加密公钥解密,他们要自己封 ...

  4. RSA私钥和公钥文件格式 (pkcs#1, pkcs#8, pkcs#12, pem)

    RSA私钥和公钥文件格式 (pkcs#1, pkcs#8, pkcs#12, pem) 2018年03月07日 11:57:22 阅读数:674 Format Name Description PKC ...

  5. openssl mac中使用终端生成RSA私钥和公钥文件

    RSA密钥生成命令生成RSA私钥openssl>genrsa -out rsa_private_key.pem 1024生成RSA公钥openssl>rsa -in rsa_private ...

  6. 银联手机支付(.Net Csharp),3DES加密解密,RSA加密解密,RSA私钥加密公钥解密,.Net RSA 3DES C#

    前段时间做的银联支付,折腾了好久,拼凑的一些代码,有需要的朋友可以参考,本人.Net新手,不保证准确性! 这个银联手机支付没有SDK提供,技术支持也没有.Net的,真心不好搞! RSA加解密,这里有个 ...

  7. php生成签名及验证签名

    <?php /** * 根据原文生成签名内容 * * @param string $data 原文内容 * * @return string * @author confu */ functio ...

  8. mac中使用终端生成RSA私钥和公钥文件

    1.打开终端输入:cd Desktop/   //进入桌面 2.OpenSSL   //打开 OpenSSL 3.生成私钥pem,  执行命令   genrsa -out rsa_private_ke ...

  9. OpenSSL-Win32,rsa,私钥,公钥,1024,2048

    默认是rsa_private_key1024.pem , PEM格式私钥,C# ,PHP 用. 再生成 pkcs8 格式私钥, JAVA 用. 公钥无格式区分. 1024 的: openssl.exe ...

随机推荐

  1. fiddler选项卡-Composer(构建请求)

    Composer Composer支持手动构建http.https和ftp请求.点到composer选项卡界面,我们可以看到下面有一串英文. use this page to compose a Re ...

  2. 【Java面试真题】剑指Offer53.2——0~n-1中缺失的数字(异或、二分两种解法)

    [Java实现]剑指Offer53.2--0~n-1中缺失的数字:面试真题,两种思路分享 前面有另一道面试题[Java实现]剑指offer53.1--在排序数组中查找数字(LeetCode34:在排序 ...

  3. 2021年Wordpress博客搭建

    2021年WordPress博客搭建教程 这是一篇关于2021最新版的WP个人博客搭建教程.整篇文章会事无巨细的一步步讲述搭建博客的每一步. 0.前言 随着互联网和移动互联网的飞速发展,博客这一功能恍 ...

  4. 【NX二次开发】Block UI 文本颜色/字体/宽度

    属性说明 常规     类型 描述     BlockID     String 控件ID     Enable     Logical 是否可操作     Group     Logical 是否分 ...

  5. 「10.10」神炎皇(欧拉函数)·降雷皇(线段树,DP)·幻魔皇

    A. 神炎皇 很好的一道题,可能第一次在考场上遇到欧拉函数 题意:对于一个整数对 $(a,b)$,若满足 $a\times b\leq n$且$a+b$是$a\times b$的因子, 则称为神奇的数 ...

  6. NOIP模拟测试20「周·任·飞」

    liu_runda出的题再次$\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%$ 任 题解 题目中为什么反复强调简单路径,没有环 没有环的图中点数-边数=联通块数 前缀和维护边 ...

  7. 前端 JavaScript 复制粘贴的奥义——Clipboard 对象概述

    前言 作为一名资深搬砖工,你要问我用得最熟练的技能是什么,那我敢肯定且自豪的告诉你:是 Ctrl+C !是 Ctrl+V! 不信?你来看看我键盘上的 Ctrl.C 和 V 键,那油光发亮的包浆程度,不 ...

  8. 『心善渊』Selenium3.0基础 — 4、Selenium基础元素定位详解

    目录 1.什么是元素定位 2.Selenium元素定位常用API (1)By_id 定位 (2)by_name 定位 (3)by_class_name 定位 (4)by_tag_name 定位 (5) ...

  9. vscode中html和vue没有自动补全,需要怎么配置

    先安装HTML Snippets插件 点击 文件-首选项-设置,然后根据以下操作 然后在setting.json中加入以下代码 然后就有提示了

  10. C、C++、python、Java、php、C#六种编程语言大PK 哪个好学习?

    作为程序员吃饭的工具,编程语言之间也形成了某种鄙视链,各大论坛里弥漫着剑拔弩张的气氛,众口难调.也难怪有很多初学者会有疑惑,为什么会有这么多编程语言,我到底应该学什么语言? 其实各种语言都各有千秋.接 ...