-
-
Save beginor/0d0acd7304c0e1d98d89e687aa8322e1 to your computer and use it in GitHub Desktop.
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Security.Cryptography; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace CMCloud.SaaS | |
{ | |
public class RSACryptoService | |
{ | |
private RSACryptoServiceProvider _privateKeyRsaProvider; | |
private RSACryptoServiceProvider _publicKeyRsaProvider; | |
/// <summary> | |
/// RSA解密 | |
/// </summary> | |
/// <param name="cipherText"></param> | |
/// <returns></returns> | |
public string Decrypt(string cipherText) | |
{ | |
if (_privateKeyRsaProvider == null) | |
{ | |
throw new Exception("_privateKeyRsaProvider is null"); | |
} | |
return Decrypt2(cipherText); | |
} | |
/// <summary> | |
/// RSA加密 | |
/// </summary> | |
/// <param name="text"></param> | |
/// <returns></returns> | |
public string Encrypt(string text) | |
{ | |
if (_publicKeyRsaProvider == null) | |
{ | |
throw new Exception("_publicKeyRsaProvider is null"); | |
} | |
return Encrypt2(text); | |
//return Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(Encoding.UTF8.GetBytes(text), false)); | |
} | |
private string Encrypt2(string text) | |
{ | |
Byte[] PlaintextData = Encoding.UTF8.GetBytes(text); | |
int MaxBlockSize = _publicKeyRsaProvider.KeySize / 8 - 11;//加密块最大长度限制 | |
if (PlaintextData.Length <= MaxBlockSize) | |
{ | |
return Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(PlaintextData, false)); | |
} | |
else | |
{ | |
using (MemoryStream PlaiStream = new MemoryStream(PlaintextData)) | |
using (MemoryStream CrypStream = new MemoryStream()) | |
{ | |
Byte[] Buffer = new Byte[MaxBlockSize]; | |
int BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize); | |
while (BlockSize > 0) | |
{ | |
Byte[] ToEncrypt = new Byte[BlockSize]; | |
Array.Copy(Buffer, 0, ToEncrypt, 0, BlockSize); | |
Byte[] Cryptograph = _publicKeyRsaProvider.Encrypt(ToEncrypt, false); | |
CrypStream.Write(Cryptograph, 0, Cryptograph.Length); | |
BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize); | |
} | |
return Convert.ToBase64String(CrypStream.ToArray(), Base64FormattingOptions.None); | |
} | |
} | |
} | |
private string Decrypt2(string ciphertext) | |
{ | |
Byte[] CiphertextData = Convert.FromBase64String(ciphertext); | |
int MaxBlockSize = _privateKeyRsaProvider.KeySize / 8; //解密块最大长度限制 | |
if (CiphertextData.Length <= MaxBlockSize) | |
return System.Text.Encoding.UTF8.GetString(_privateKeyRsaProvider.Decrypt(CiphertextData, false)); | |
using (MemoryStream CrypStream = new MemoryStream(CiphertextData)) | |
using (MemoryStream PlaiStream = new MemoryStream()) | |
{ | |
Byte[] Buffer = new Byte[MaxBlockSize]; | |
int BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize); | |
while (BlockSize > 0) | |
{ | |
Byte[] ToDecrypt = new Byte[BlockSize]; | |
Array.Copy(Buffer, 0, ToDecrypt, 0, BlockSize); | |
Byte[] Plaintext = _privateKeyRsaProvider.Decrypt(ToDecrypt, false); | |
PlaiStream.Write(Plaintext, 0, Plaintext.Length); | |
BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize); | |
} | |
return System.Text.Encoding.UTF8.GetString(PlaiStream.ToArray()); | |
} | |
} | |
public RSACryptoService(string privateKey, string publicKey = null) | |
{ | |
if (!string.IsNullOrEmpty(privateKey)) | |
{ | |
_privateKeyRsaProvider = CreateRsaProviderFromPrivateKey(privateKey); | |
} | |
if (!string.IsNullOrEmpty(publicKey)) | |
{ | |
_publicKeyRsaProvider = CreateRsaProviderFromPublicKey(publicKey); | |
} | |
} | |
private RSACryptoServiceProvider CreateRsaProviderFromPrivateKey(string privateKey) | |
{ | |
var privateKeyBits = System.Convert.FromBase64String(privateKey); | |
var RSA = new RSACryptoServiceProvider(); | |
var RSAparams = new RSAParameters(); | |
using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits))) | |
{ | |
byte bt = 0; | |
ushort twobytes = 0; | |
twobytes = binr.ReadUInt16(); | |
if (twobytes == 0x8130) | |
binr.ReadByte(); | |
else if (twobytes == 0x8230) | |
binr.ReadInt16(); | |
else | |
throw new Exception("Unexpected value read binr.ReadUInt16()"); | |
twobytes = binr.ReadUInt16(); | |
if (twobytes != 0x0102) | |
throw new Exception("Unexpected version"); | |
bt = binr.ReadByte(); | |
if (bt != 0x00) | |
throw new Exception("Unexpected value read binr.ReadByte()"); | |
RSAparams.Modulus = binr.ReadBytes(GetIntegerSize(binr)); | |
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; | |
} | |
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; | |
} | |
} | |
} |
Getting error: Timeouts are not supported on this stream. ???
If you have any problems, please provide more information about:
- the runtime version you are using (.net or mono, or .net core)
- how did you generate the key with openssl
- how did you use with the code above
(1) .net framework 4.6.1 (VS 2017)
(2) The key is provided by customer
(3) use the above code for signdata with SHA256
My problem is to Import RSA private key RSA.ImportParameters(RSAparams), try it many times but doesn't work.
Any help would be appreciate.
How did your customer generate the key, and make sure it's a vaid rsa key
RSAparams.Modulus = binr.ReadBytes(GetIntegerSize(binr));
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));
Why all these parameters get byte[0] or null values while running your code? I am confused.
While running the following statement:
MemoryStream mem = new MemoryStream(privkey);
Get the below error:
-
ReadTimeout 'mem.ReadTimeout' threw an exception of type 'System.InvalidOperationException' int {System.InvalidOperationException}
-
WriteTimeout 'mem.WriteTimeout' threw an exception of type 'System.InvalidOperationException' int {System.InvalidOperationException}
Therefore the mem variable doesn't get any value.
Could you please help? Thank you.
Getting error: Timeouts are not supported on this stream. ???