123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- using System;
- using System.Text;
- using System.Security.Cryptography;
- using System.IO;
- namespace PaySharp.Alipay.Util.Asymmetric
- {
- /// <summary>
- /// RSA算法加密器
- /// 签名部分采用SHA1算法进行摘要计算
- /// </summary>
- public class RSAEncryptor : BaseAsymmetricEncryptor
- {
- /// <summary>
- /// RSA算法签名采用SHA1摘要算法
- /// </summary>
- /// <returns>摘要算法名称</returns>
- protected virtual string GetShaType()
- {
- return "SHA1";
- }
- protected override string GetAsymmetricType()
- {
- return "RSA";
- }
- protected override string DoDecrypt(string cipherTextBase64, string charset, string privateKey)
- {
- using (RSACryptoServiceProvider rsaService = BuildRSAServiceProvider(Convert.FromBase64String(privateKey)))
- {
- byte[] data = Convert.FromBase64String(cipherTextBase64);
- //解密块最大长度
- int maxBlockSize = rsaService.KeySize / 8;
- //如果密文长度小于等于单个解密块最大长度,直接单次调用解密接口完成解密
- if (data.Length <= maxBlockSize)
- {
- byte[] cipherbytes = rsaService.Decrypt(data, false);
- return Encoding.GetEncoding(charset).GetString(cipherbytes);
- }
- //如果密文长度大于单个解密块最大长度,在内存中循环调用解密接口完成解密
- using (MemoryStream plainStream = new MemoryStream())
- {
- using (MemoryStream cipherStream = new MemoryStream(data))
- {
- Byte[] buffer = new Byte[maxBlockSize];
- int readSize = cipherStream.Read(buffer, 0, maxBlockSize);
- while (readSize > 0)
- {
- Byte[] cipherBlock = new Byte[readSize];
- Array.Copy(buffer, 0, cipherBlock, 0, readSize);
- Byte[] plainBlock = rsaService.Decrypt(cipherBlock, false);
- plainStream.Write(plainBlock, 0, plainBlock.Length);
- readSize = cipherStream.Read(buffer, 0, maxBlockSize);
- }
- }
- return Encoding.GetEncoding(charset).GetString(plainStream.ToArray());
- }
- }
- }
- protected override string DoEncrypt(string plainText, string charset, string publicKey)
- {
- using (RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider())
- {
- rsaService.PersistKeyInCsp = false;
- rsaService.ImportParameters(ConvertFromPemPublicKey(publicKey));
- byte[] data = Encoding.GetEncoding(charset).GetBytes(plainText);
- //加密块最大长度
- int maxBlockSize = rsaService.KeySize / 8 - 11;
- //如果明文长度小于等于单个加密块最大长度,直接单次调用加密接口完成加密
- if (data.Length <= maxBlockSize)
- {
- byte[] cipherbytes = rsaService.Encrypt(data, false);
- return Convert.ToBase64String(cipherbytes);
- }
- //如果明文长度大于单个加密块最大长度,在内存中循环调用加密接口完成加密
- using (MemoryStream cipherStream = new MemoryStream())
- {
- using (MemoryStream plainStream = new MemoryStream(data))
- {
- Byte[] buffer = new Byte[maxBlockSize];
- int readSize = plainStream.Read(buffer, 0, maxBlockSize);
- while (readSize > 0)
- {
- Byte[] plainBlock = new Byte[readSize];
- Array.Copy(buffer, 0, plainBlock, 0, readSize);
- Byte[] cipherBlock = rsaService.Encrypt(plainBlock, false);
- cipherStream.Write(cipherBlock, 0, cipherBlock.Length);
- readSize = plainStream.Read(buffer, 0, maxBlockSize);
- }
- }
- return Convert.ToBase64String(cipherStream.ToArray(), Base64FormattingOptions.None);
- }
- }
- }
- protected override string DoSign(string content, string charset, string privateKey)
- {
- using (RSACryptoServiceProvider rsaService = BuildRSAServiceProvider(Convert.FromBase64String(privateKey)))
- {
- byte[] data = Encoding.GetEncoding(charset).GetBytes(content);
- byte[] sign = rsaService.SignData(data, GetShaType());
- return Convert.ToBase64String(sign);
- }
- }
- protected override bool DoVerify(string content, string charset, string publicKey, string sign)
- {
- using (RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider())
- {
- rsaService.PersistKeyInCsp = false;
- rsaService.ImportParameters(ConvertFromPemPublicKey(publicKey));
- return rsaService.VerifyData(Encoding.GetEncoding(charset).GetBytes(content),
- GetShaType(), Convert.FromBase64String(sign));
- }
- }
- private RSAParameters ConvertFromPemPublicKey(string pemPublickKey)
- {
- if (string.IsNullOrEmpty(pemPublickKey))
- {
- throw new Exception("PEM格式公钥不可为空。");
- }
- //移除干扰文本
- pemPublickKey = pemPublickKey.Replace("-----BEGIN PUBLIC KEY-----", "")
- .Replace("-----END PUBLIC KEY-----", "").Replace("\n", "").Replace("\r", "");
- byte[] keyData = Convert.FromBase64String(pemPublickKey);
- bool keySize1024 = (keyData.Length == 162);
- bool keySize2048 = (keyData.Length == 294);
- if (!(keySize1024 || keySize2048))
- {
- throw new Exception("公钥长度只支持1024和2048。");
- }
- byte[] pemModulus = (keySize1024 ? new byte[128] : new byte[256]);
- byte[] pemPublicExponent = new byte[3];
- Array.Copy(keyData, (keySize1024 ? 29 : 33), pemModulus, 0, (keySize1024 ? 128 : 256));
- Array.Copy(keyData, (keySize1024 ? 159 : 291), pemPublicExponent, 0, 3);
- RSAParameters para = new RSAParameters();
- para.Modulus = pemModulus;
- para.Exponent = pemPublicExponent;
- return para;
- }
- private static RSACryptoServiceProvider BuildRSAServiceProvider(byte[] privateKey)
- {
- byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
- byte bt = 0;
- ushort twobytes = 0;
- int elems = 0;
- //set up stream to decode the asn.1 encoded RSA private key
- //wrap Memory Stream with BinaryReader for easy reading
- using (BinaryReader binaryReader = new BinaryReader(new MemoryStream(privateKey)))
- {
- twobytes = binaryReader.ReadUInt16();
- //data read as little endian order (actual data order for Sequence is 30 81)
- if (twobytes == 0x8130)
- {
- //advance 1 byte
- binaryReader.ReadByte();
- }
- else if (twobytes == 0x8230)
- {
- //advance 2 bytes
- binaryReader.ReadInt16();
- }
- else
- {
- return null;
- }
- twobytes = binaryReader.ReadUInt16();
- //version number
- if (twobytes != 0x0102)
- {
- return null;
- }
- bt = binaryReader.ReadByte();
- if (bt != 0x00)
- {
- return null;
- }
- //all private key components are Integer sequences
- elems = GetIntegerSize(binaryReader);
- MODULUS = binaryReader.ReadBytes(elems);
- elems = GetIntegerSize(binaryReader);
- E = binaryReader.ReadBytes(elems);
- elems = GetIntegerSize(binaryReader);
- D = binaryReader.ReadBytes(elems);
- elems = GetIntegerSize(binaryReader);
- P = binaryReader.ReadBytes(elems);
- elems = GetIntegerSize(binaryReader);
- Q = binaryReader.ReadBytes(elems);
- elems = GetIntegerSize(binaryReader);
- DP = binaryReader.ReadBytes(elems);
- elems = GetIntegerSize(binaryReader);
- DQ = binaryReader.ReadBytes(elems);
- elems = GetIntegerSize(binaryReader);
- IQ = binaryReader.ReadBytes(elems);
- //create RSACryptoServiceProvider instance and initialize with public key
- RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider();
- RSAParameters rsaParams = new RSAParameters
- {
- Modulus = MODULUS,
- Exponent = E,
- D = D,
- P = P,
- Q = Q,
- DP = DP,
- DQ = DQ,
- InverseQ = IQ
- };
- rsaService.ImportParameters(rsaParams);
- return rsaService;
- }
- }
- private static int GetIntegerSize(BinaryReader binaryReader)
- {
- byte bt = 0;
- byte lowbyte = 0x00;
- byte highbyte = 0x00;
- int count = 0;
- bt = binaryReader.ReadByte();
- //expect integer
- if (bt != 0x02)
- {
- return 0;
- }
- bt = binaryReader.ReadByte();
- if (bt == 0x81)
- {
- //data size in next byte
- count = binaryReader.ReadByte();
- }
- else if (bt == 0x82)
- {
- //data size in next 2 bytes
- highbyte = binaryReader.ReadByte();
- lowbyte = binaryReader.ReadByte();
- byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
- count = BitConverter.ToInt32(modint, 0);
- }
- else
- {
- //we already have the data size
- count = bt;
- }
- while (binaryReader.ReadByte() == 0x00)
- { //remove high order zeros in data
- count -= 1;
- }
- //last ReadByte wasn't a removed zero, so back up a byte
- binaryReader.BaseStream.Seek(-1, SeekOrigin.Current);
- return count;
- }
- }
- }
|