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; }
浙公网安备 33010602011771号