-
-
Save ducksoupdev/fc2e576114adf010624a2ddef576f239 to your computer and use it in GitHub Desktop.
C# RSACryptoService with openssl rsa key
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment