various enhancements to PSRSAEncryptionProvider (#10914)

This commit is contained in:
William Cheng
2021-11-21 14:28:37 +08:00
committed by GitHub
parent 606db36c77
commit 37a4429024
2 changed files with 209 additions and 52 deletions

View File

@@ -1,3 +1,11 @@
/*
* OpenAPI Petstore
*
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
* Generated by: https://github.com/openapitools/openapi-generator.git
*/
using System;
using System.Collections.Generic;
using System.IO;
@@ -9,8 +17,17 @@ using System.Text;
namespace RSAEncryption
{
/// <summary>
/// A RSA enccryption provider.
/// </summary>
public class RSAEncryptionProvider
{
/// <summary>
/// Get the RSA provider from the PEM file.
/// </summary>
/// <param name="pemfile">PEM file.</param>
/// <param name="keyPassPhrase">Key pass phrase.</param>
/// <returns>Get an instance of RSACryptoServiceProvider.</returns>
public static RSACryptoServiceProvider GetRSAProviderFromPemFile(String pemfile,SecureString keyPassPhrase = null)
{
const String pempubheader = "-----BEGIN PUBLIC KEY-----";
@@ -41,6 +58,12 @@ namespace RSAEncryption
return null ;
}
/// <summary>
/// Convert the private key to bytes.
/// </summary>
/// <param name="instr">Private key.</param>
/// <param name="keyPassPhrase">Key pass phrase.</param>
/// <returns>The private key in the form of bytes.</returns>
static byte[] ConvertPrivateKeyToBytes(String instr, SecureString keyPassPhrase = null)
{
const String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----";
@@ -69,16 +92,24 @@ namespace RSAEncryption
//-------- read PEM encryption info. lines and extract salt -----
if (!str.ReadLine().StartsWith("Proc-Type: 4,ENCRYPTED"))
{
return null;
}
String saltline = str.ReadLine();
if (!saltline.StartsWith("DEK-Info: DES-EDE3-CBC,"))
{
return null;
}
String saltstr = saltline.Substring(saltline.IndexOf(",") + 1).Trim();
byte[] salt = new byte[saltstr.Length / 2];
for (int i = 0; i < salt.Length; i++)
{
salt[i] = Convert.ToByte(saltstr.Substring(i * 2, 2), 16);
if (!(str.ReadLine() == ""))
}
if (str.ReadLine() != "")
{
return null;
}
//------ remaining b64 data is encrypted RSA key ----
String encryptedstr = str.ReadToEnd();
@@ -94,7 +125,9 @@ namespace RSAEncryption
byte[] deskey = GetEncryptedKey(salt, keyPassPhrase, 1, 2); // count=1 (for OpenSSL implementation); 2 iterations to get at least 24 bytes
if (deskey == null)
{
return null;
}
//------ Decrypt the encrypted 3des-encrypted RSA private key ------
byte[] rsakey = DecryptKey(binkey, deskey, salt); //OpenSSL uses salt value in PEM header also as 3DES IV
@@ -102,9 +135,14 @@ namespace RSAEncryption
}
}
/// <summary>
/// Decode the RSA private key.
/// </summary>
/// <param name="privkey">Private key.</param>
/// <returns>An instance of RSACryptoServiceProvider.</returns>
public static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
{
byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
byte[] bytesModules, bytesE, bytesD, bytesP, bytesQ, bytesDp, bytesDq, bytesIq;
// --------- Set up stream to decode the asn.1 encoded RSA private key ------
MemoryStream mem = new MemoryStream(privkey);
@@ -116,63 +154,76 @@ namespace RSAEncryption
{
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();
if (twobytes != 0x0102) //version number
{
return null;
}
bt = binr.ReadByte();
if (bt != 0x00)
{
return null;
}
//------ all private key components are Integer sequences ----
elems = GetIntegerSize(binr);
MODULUS = binr.ReadBytes(elems);
bytesModules = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
E = binr.ReadBytes(elems);
bytesE = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
D = binr.ReadBytes(elems);
bytesD = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
P = binr.ReadBytes(elems);
bytesP = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
Q = binr.ReadBytes(elems);
bytesQ = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
DP = binr.ReadBytes(elems);
bytesDp = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
DQ = binr.ReadBytes(elems);
bytesDq = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
IQ = binr.ReadBytes(elems);
bytesIq = binr.ReadBytes(elems);
// ------- create RSACryptoServiceProvider instance and initialize with public key -----
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
RSAParameters RSAparams = new RSAParameters();
RSAparams.Modulus = MODULUS;
RSAparams.Exponent = E;
RSAparams.D = D;
RSAparams.P = P;
RSAparams.Q = Q;
RSAparams.DP = DP;
RSAparams.DQ = DQ;
RSAparams.InverseQ = IQ;
RSA.ImportParameters(RSAparams);
return RSA;
RSAparams.Modulus = bytesModules;
RSAparams.Exponent = bytesE;
RSAparams.D = bytesD;
RSAparams.P = bytesP;
RSAparams.Q = bytesQ;
RSAparams.DP = bytesDp;
RSAparams.DQ = bytesDq;
RSAparams.InverseQ = bytesIq;
rsa.ImportParameters(RSAparams);
return rsa;
}
catch (Exception)
{
return null;
}
finally { binr.Close(); }
finally
{
binr.Close();
}
}
private static int GetIntegerSize(BinaryReader binr)
@@ -183,13 +234,16 @@ namespace RSAEncryption
int count = 0;
bt = binr.ReadByte();
if (bt != 0x02) //expect integer
{
return 0;
}
bt = binr.ReadByte();
if (bt == 0x81)
{
count = binr.ReadByte(); // data size in next byte
else
if (bt == 0x82)
}
else if (bt == 0x82)
{
highbyte = binr.ReadByte(); // data size in next 2 bytes
lowbyte = binr.ReadByte();
@@ -209,10 +263,18 @@ namespace RSAEncryption
return count;
}
/// <summary>
/// Get the encrypted key.
/// </summary>
/// <param name="salt">Random bytes to be added.</param>
/// <param name="secpswd">Password.</param>
/// <param name="count">Count.</param>
/// <param name="miter">Miter.</param>
/// <returns>Decrypted key.</returns>
static byte[] GetEncryptedKey(byte[] salt, SecureString secpswd, int count, int miter)
{
IntPtr unmanagedPswd = IntPtr.Zero;
int HASHLENGTH = 16; //MD5 bytes
const int HASHLENGTH = 16; //MD5 bytes
byte[] keymaterial = new byte[HASHLENGTH * miter]; //to store concatenated Mi hashed results
byte[] psbytes = new byte[secpswd.Length];
@@ -234,7 +296,9 @@ namespace RSAEncryption
{
// ---- Now hash consecutively for count times ------
if (j == 0)
{
result = data00; //initialize
}
else
{
Array.Copy(result, hashtarget, result.Length);
@@ -243,7 +307,9 @@ namespace RSAEncryption
}
for (int i = 0; i < count; i++)
{
result = md5.ComputeHash(result);
}
Array.Copy(result, 0, keymaterial, j * HASHLENGTH, result.Length); //concatenate to keymaterial
}
byte[] deskey = new byte[24];
@@ -257,6 +323,13 @@ namespace RSAEncryption
return deskey;
}
/// <summary>
/// Decrypt the key.
/// </summary>
/// <param name="chipherData">Cipher data.</param>
/// <param name="desKey">Key to decrypt.</param>
/// <param name="IV">Initialization vector.</param>
/// <returns>Decrypted key.</returns>
static byte[] DecryptKey(byte[] cipherData, byte[] desKey, byte[] IV)
{
MemoryStream memst = new MemoryStream();
@@ -269,7 +342,8 @@ namespace RSAEncryption
cs.Write(cipherData, 0, cipherData.Length);
cs.Close();
}
catch (Exception){
catch (Exception)
{
return null;
}
byte[] decryptedData = memst.ToArray();