RSA 加密 解密 数字签名验证

 

在日常工作中,有很多文件需要领导审阅、签名和盖章,由于公司业务开展,跨地域、跨国业务也日益普遍,领导签名盖章变得很麻烦,开始的时候人们通过邮寄、传真等方式来解决,但是耗费时间、人力、物力。在网络化日益深入的今天,需要领导审批、签字盖章的东西越来越多,时间也越来越紧迫,数字签名的出现,很好了解决了这一问题。推动了互联网及跨国集团的发展。

数字签名

数字签名基于哈希算法和公钥加密算法,对明文报文先用哈希算法计算摘要,然后用私钥对摘要进行加密,得到的值就是原文的数字签名。

数字签名(又称公钥数字签名、电子签章)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。

一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。

流程图如下:

private void testDigitalSignature_Click(object sender, EventArgs e)
        {
            string originalText = "原文内容,这是我的明文:明文1!";
            MessageBox.Show(originalText);

            //生成privatekey和publickey
           // RSAKey("D:\\Cosmo\\privatekey", "D:\\Cosmo\\publickey");

            string privateKey = "<RSAKeyValue><Modulus>uwQRGCdjnxvPR8mLg5ylC0Mgll2FJkt64rJoFUCofEntleqWmIr3OvwwH4ppbYnAiZyq2RWJVa15YupeuAY9Vm/00Ta54ihjlNvqFXtTvm6GLjIhWQsCgsFL7R6lKaNPIMp8GH0fJIAtAPUWHQXpg404p4L89CYcClanpHLUhgM=</Modulus><Exponent>AQAB</Exponent><P>9fTXSkmbdM3PcfgoDTzwpiTYhb4G3aD+mgi0xyhF9EuxUiwaXXo2/E654nHuVrkjUM35UXOsnfQnPpCIakN3DQ==</P><Q>wqcUAmE62VTJ2Cb8/GF8naQ2cq8vv6FuN2sX81d9dC9z2ahrIMkg4LCwfN4+bxF+T/gTNxKUm/Z+9C5A/wutTw==</Q><DP>miXzcFmllpUOuI0g/Pr+kAJzuY6ZWvn117AxLMiu3yc5YRjHBWL9ZzAoDCX/jFbILXKKGWR4AR7uIaYP+RmDWQ==</DP><DQ>j4crFeYjwoTmoF9/Q4mOnZ6sFzxd9OtPncV1z5S/iKBEyEWLWI11lLg0Kp6lYrh/bu/5Gy60LZxAWESS4Hz3uQ==</DQ><InverseQ>uQuPLbxa7R1KuuOiDGf18WhX76Fwyg2bLtWjkN9JRiTRJaKuyZu1hMEo3H2GR2fcz/GaPdvEP+XfW239cEdyLw==</InverseQ><D>qMUfxCNv1Nuc8NTikbBghUxb8TaOfaOqT0DfiyZhpmB1B1C//QOT32hM6XnYcODan5WB3QyBdo9ptyl4tyvyVyxrDnlugKzC7gSBFwIWthwStkY12Mggi+t5qKmX0q0ONsnTwmU66G7uKjIZghnrhMkEF/Yl/owGeq+paVorQ5k=</D></RSAKeyValue>";//ReadPrivateKey("D:\\Cosmo\\privatekey");
            string publicKey = "<RSAKeyValue><Modulus>uwQRGCdjnxvPR8mLg5ylC0Mgll2FJkt64rJoFUCofEntleqWmIr3OvwwH4ppbYnAiZyq2RWJVa15YupeuAY9Vm/00Ta54ihjlNvqFXtTvm6GLjIhWQsCgsFL7R6lKaNPIMp8GH0fJIAtAPUWHQXpg404p4L89CYcClanpHLUhgM=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";//ReadPublicKey("D:\\Cosmo\\publickey");

            /*
            //传进来的PrivateKey 根据私钥字符串导入到RSACryptoServiceProvider 返回RSA私钥字符串
            RSACryptoServiceProvider rsaPrivateProvider = CreateRsaProviderFromPrivateKey(@"MIICXQIBAAKBgQC7PyjMEuniN6BPn8oqzIZ6AO1NjSTO9R3adCCIwKfKIEoWXXM+
tHDpktdPKSaAsWJPTNAGvEvtxOfzXib/EMXKqD0eUy5MatfpRjRdf1hJVimmfrb0
9Qx2j7CsKLy7nD23m4xubdYBwvkjMwt/L3JxB5D6qryW1wei/j1c+/OCxQIDAQAB
AoGAT7vGYJgRNf4f6qgNS4pKHTu10RcwPFyOOM7IZ9M5380+HyXuBB6MEjowKwpH
1fcy+LepwaR+5KG7b5uBGY4H2ticMtdysBd9gLwnY4Eh4j7LCWE54HvELpeWXkWp
FQdb/NQhcqMAGwYsTnRPdBqkrUmJBTYqEGkIlqCQ5vUJOCECQQDhe0KGmbq1RWp6
TDvgpA2dUmlt2fdP8oNW8O7MvbDaQRduoZnVRTPYCDKfzFqpNXL1hAYgth1N0vzD
nv3VoLcpAkEA1JcY+rLv5js1g5Luv8LaI5/3uOg0CW7fmh/LfGuz8k/OxASN+cAO
UjPHrxtc5xn1zat4/bnV5GEdlOp/DhquPQJBAIV2Fsdi4M+AueiPjPWHRQO0jvDV
jfwFOFZSn5YSRUa6NmtmPY6tumUJXSWWqKb1GwlVTuc3xBqXYsNLLUWwLhkCQQDJ
UJCiD0LohhdGEqUuSKnj5H9kxddJO4pZXFSI7UEJbJQDwcBkyn+FTm2BH+tZGZdQ
fVnlA89OJr0poOpSg+eNAkAKY85SR9KASaTiDBoPpJ8N805XEhd0Kq+ghzSThxL3
fVtKUQLiCh7Yd8oMd/G5S3xWJHUXSioATT8uPRH2bOb/
");
            privateKey = rsaPrivateProvider.ToXmlString(true);//将RSA算法的私钥导出到字符串PrivateKey中,参数为true表示导出私钥
            MessageBox.Show(privateKey);
            //传进来的PublicKey 根据公钥字符串导入到RSACryptoServiceProvider 返回RSA公钥字符串
            RSACryptoServiceProvider rsaPulicProvider = CreateRsaProviderFromPublicKey(@"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7PyjMEuniN6BPn8oqzIZ6AO1N
jSTO9R3adCCIwKfKIEoWXXM+tHDpktdPKSaAsWJPTNAGvEvtxOfzXib/EMXKqD0e
Uy5MatfpRjRdf1hJVimmfrb09Qx2j7CsKLy7nD23m4xubdYBwvkjMwt/L3JxB5D6
qryW1wei/j1c+/OCxQIDAQAB
");
            publicKey = rsaPulicProvider.ToXmlString(false);
            MessageBox.Show(publicKey);
             */

            //加密明文
            string cipherText = EncryptByRSA(originalText, publicKey);
           //解密密文
            string plainText = DecryptByRSA(cipherText, privateKey);

            //1、生成签名,通过摘要算法
            string signedData = HashAndSignString(originalText, privateKey);
            MessageBox.Show(signedData);
            //2、验证签名
            bool verify = VerifySigned(originalText, signedData, publicKey);//originalText:原文;SignedData:签名;publicKey:公钥
            MessageBox.Show(verify.ToString());

        }
        ///  <summary>
        ///  创建公钥文件
        ///  </summary>
        ///  <param name="path"></param>
        ///  <param name="publickey"></param>
        public void CreatePublicKeyXML(string path, string publickey)
        {
            try
            {
                FileStream publickeyxml = new FileStream(path, FileMode.Create);
                StreamWriter sw = new StreamWriter(publickeyxml);
                sw.WriteLine(publickey);
                sw.Close();
                publickeyxml.Close();
            }
            catch
            {
                throw;
            }
        }

        ///  <summary>
        ///  读取公钥
        ///  </summary>
        ///  <param name="path"></param>
        ///  <returns></returns>
        public string ReadPublicKey(string path)
        {
            StreamReader reader = new StreamReader(path);
            string publickey = reader.ReadToEnd();
            reader.Close();
            return publickey;
        }

        ///  <summary>
        ///  创建私钥文件
        ///  </summary>
        ///  <param name="path"></param>
        ///  <param name="privatekey"></param>
        public void CreatePrivateKeyXML(string path, string privatekey)
        {
            try
            {
                FileStream privatekeyxml = new FileStream(path, FileMode.Create);
                StreamWriter sw = new StreamWriter(privatekeyxml);
                sw.WriteLine(privatekey);
                sw.Close();
                privatekeyxml.Close();
            }
            catch
            {
                throw;
            }
        }

        ///  <summary>
        ///  读取私钥
        ///  </summary>
        ///  <param name="path"></param>
        ///  <returns></returns>
        public string ReadPrivateKey(string path)
        {
            StreamReader reader = new StreamReader(path);
            string privatekey = reader.ReadToEnd();
            reader.Close();
            return privatekey;
        }

        /// <summary>
        /// 生成公私钥
        /// </summary>
        /// <param name="PrivateKeyPath"></param>
        /// <param name="PublicKeyPath"></param>
        public void RSAKey(string PrivateKeyPath, string PublicKeyPath)
        {
            try
            {
                RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
                this.CreatePrivateKeyXML(PrivateKeyPath, provider.ToXmlString(true));
                this.CreatePublicKeyXML(PublicKeyPath, provider.ToXmlString(false));
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }

        /// <summary>
        /// RSA加密
        /// </summary>
        /// <param name="plaintext">明文</param>
        /// <param name="publicKey">公钥</param>
        /// <returns>密文字符串</returns>
        public static string EncryptByRSA(string plaintext, string publicKey)
        {
            UnicodeEncoding ByteConverter = new UnicodeEncoding();
            byte[] dataToEncrypt = ByteConverter.GetBytes(plaintext);
            using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
            {
                RSA.FromXmlString(publicKey);
                byte[] encryptedData = RSA.Encrypt(dataToEncrypt, false);
                return Convert.ToBase64String(encryptedData);
            }
        }

        /// <summary>
        /// RSA解密
        /// </summary>
        /// <param name="ciphertext">密文</param>
        /// <param name="privateKey">私钥</param>
        /// <returns>明文字符串</returns>
        public static string DecryptByRSA(string ciphertext, string privateKey)
        {
            UnicodeEncoding byteConverter = new UnicodeEncoding();
            using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
            {
                RSA.FromXmlString(privateKey);
                byte[] encryptedData = Convert.FromBase64String(ciphertext);
                byte[] decryptedData = RSA.Decrypt(encryptedData, false);
                return byteConverter.GetString(decryptedData);
            }
        }
        /// <summary>
        /// 数字签名
        /// </summary>
        /// <param name="plaintext">原文</param>
        /// <param name="privateKey">私钥</param>
        /// <returns>签名</returns>
        private  string HashAndSignString(string plaintext, string privateKey)
        {
            UnicodeEncoding ByteConverter = new UnicodeEncoding();
            byte[] dataToEncrypt = ByteConverter.GetBytes(plaintext);

            using (RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider())
            {
                RSAalg.FromXmlString(privateKey);
                //使用SHA1进行摘要算法,生成签名
                byte[] encryptedData = RSAalg.SignData(dataToEncrypt, new SHA1CryptoServiceProvider());
                return Convert.ToBase64String(encryptedData);
            }
        }

        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="plaintext">原文</param>
        /// <param name="SignedData">签名</param>
        /// <param name="publicKey">公钥</param>
        /// <returns></returns>
        private bool VerifySigned(string plaintext, string SignedData, string publicKey)
        {
            using (RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider())
            {
                RSAalg.FromXmlString(publicKey);
                UnicodeEncoding ByteConverter = new UnicodeEncoding();
                byte[] dataToVerifyBytes = ByteConverter.GetBytes(plaintext);
                byte[] signedDataBytes = Convert.FromBase64String(SignedData);
                return RSAalg.VerifyData(dataToVerifyBytes, new SHA1CryptoServiceProvider(), signedDataBytes);
            }
        }

        /// <summary>
        /// 根据私钥字符串导入到RSACryptoServiceProvider
        /// </summary>
        /// <param name="privateKey">私钥字符串</param>
        /// <returns></returns>
        private RSACryptoServiceProvider CreateRsaProviderFromPrivateKey(string privateKey)
        {
            var privateKeyBits = System.Convert.FromBase64String(privateKey);

            var RSA = new RSACryptoServiceProvider();
            var RSAparams = new RSAParameters();
            // ---------  Set up stream to decode the asn.1 encoded RSA private key  ------
            using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits)))
            {
                byte bt = 0;
                ushort twobytes = 0;
                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
                    throw new Exception("Unexpected value read binr.ReadUInt16()");

                twobytes = binr.ReadUInt16();
                if (twobytes != 0x0102)//version number
                    throw new Exception("Unexpected version");

                bt = binr.ReadByte();
                if (bt != 0x00)
                    throw new Exception("Unexpected value read binr.ReadByte()");
                // ------- create RSACryptoServiceProvider instance and initialize with public key -----
                RSAparams.Modulus = binr.ReadBytes(GetIntegerSize(binr));// Integer sequences 
                RSAparams.Exponent = binr.ReadBytes(GetIntegerSize(binr));
                RSAparams.D = binr.ReadBytes(GetIntegerSize(binr));
                RSAparams.P = binr.ReadBytes(GetIntegerSize(binr));
                RSAparams.Q = binr.ReadBytes(GetIntegerSize(binr));
                RSAparams.DP = binr.ReadBytes(GetIntegerSize(binr));
                RSAparams.DQ = binr.ReadBytes(GetIntegerSize(binr));
                RSAparams.InverseQ = binr.ReadBytes(GetIntegerSize(binr));
            }

            RSA.ImportParameters(RSAparams);
            return RSA;
        }

        private int GetIntegerSize(BinaryReader binr)
        {
            byte bt = 0;
            byte lowbyte = 0x00;
            byte highbyte = 0x00;
            int count = 0;
            bt = binr.ReadByte();
            if (bt != 0x02)
                return 0;
            bt = binr.ReadByte();

            if (bt == 0x81)
                count = binr.ReadByte();
            else
                if (bt == 0x82)
                {
                    highbyte = binr.ReadByte();
                    lowbyte = binr.ReadByte();
                    byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
                    count = BitConverter.ToInt32(modint, 0);
                }
                else
                {
                    count = bt;
                }

            while (binr.ReadByte() == 0x00)
            {
                count -= 1;
            }
            binr.BaseStream.Seek(-1, SeekOrigin.Current);
            return count;
        }

        /// <summary>
        /// 根据公钥字符串导入到RSACryptoServiceProvider
        /// </summary>
        /// <param name="publicKeyString">公钥字符串</param>
        /// <returns></returns>
        private RSACryptoServiceProvider CreateRsaProviderFromPublicKey(string publicKeyString)
        {
            // encoded OID sequence for  PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
            byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
            byte[] x509key;
            byte[] seq = new byte[15];
            int x509size;

            x509key = Convert.FromBase64String(publicKeyString);
            x509size = x509key.Length;

            // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
            using (MemoryStream mem = new MemoryStream(x509key))
            {
                using (BinaryReader binr = new BinaryReader(mem))  //wrap Memory Stream with BinaryReader for easy reading
                {
                    byte bt = 0;
                    ushort twobytes = 0;

                    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;

                    seq = binr.ReadBytes(15);       //read the Sequence OID
                    if (!CompareBytearrays(seq, SeqOID))    //make sure Sequence for OID is correct
                        return null;

                    twobytes = binr.ReadUInt16();
                    if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
                        binr.ReadByte();    //advance 1 byte
                    else if (twobytes == 0x8203)
                        binr.ReadInt16();   //advance 2 bytes
                    else
                        return null;

                    bt = binr.ReadByte();
                    if (bt != 0x00)     //expect null byte next
                        return null;

                    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();
                    byte lowbyte = 0x00;
                    byte highbyte = 0x00;

                    if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
                        lowbyte = binr.ReadByte();  // read next bytes which is bytes in modulus
                    else if (twobytes == 0x8202)
                    {
                        highbyte = binr.ReadByte(); //advance 2 bytes
                        lowbyte = binr.ReadByte();
                    }
                    else
                        return null;
                    byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };   //reverse byte order since asn.1 key uses big endian order
                    int modsize = BitConverter.ToInt32(modint, 0);

                    int firstbyte = binr.PeekChar();
                    if (firstbyte == 0x00)
                    {   //if first byte (highest order) of modulus is zero, don't include it
                        binr.ReadByte();    //skip this null byte
                        modsize -= 1;   //reduce modulus buffer size by 1
                    }

                    byte[] modulus = binr.ReadBytes(modsize);   //read the modulus bytes

                    if (binr.ReadByte() != 0x02)            //expect an Integer for the exponent data
                        return null;
                    int expbytes = (int)binr.ReadByte();        // should only need one byte for actual exponent data (for all useful values)
                    byte[] exponent = binr.ReadBytes(expbytes);

                    // ------- create RSACryptoServiceProvider instance and initialize with public key -----
                    RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
                    RSAParameters RSAKeyInfo = new RSAParameters();
                    RSAKeyInfo.Modulus = modulus;
                    RSAKeyInfo.Exponent = exponent;
                    RSA.ImportParameters(RSAKeyInfo);

                    return RSA;
                }

            }
        }

        private bool CompareBytearrays(byte[] a, byte[] b)
        {
            if (a.Length != b.Length)
                return false;
            int i = 0;
            foreach (byte c in a)
            {
                if (c != b[i])
                    return false;
                i++;
            }
            return true;
        }
View Code

 

posted @ 2015-08-10 16:19  桃子陈  阅读(1812)  评论(0)    收藏  举报