C#.NET RSA 私钥签名 公钥验证签名
阅读原文时间:2021年07月29日阅读:1

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