using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Numerics;
namespace BotFramework.Core.Auth
{
public static class RSAManager
{
private const string _RSAPublicKey =
"MIIBUzANBgkqhkiG9w0BAQEFAAOCAUAAMIIBOwKCATIAq8EYkkGCUg86Bf2CHaM1z1Q2ahQgVXkx49I0igwTVCIqG86jsgNb22na1DThZ+IP7DfyBszIecVSP8nwbYPbx6Z7dwq4pnMVx/lx5lyMZUO1n/HGEkw1S06AlfXzSg58ci5DL9RJ9ZIa1oMDKtrZiNYA5C3L+7NSCVp/2H/yypWkDjzkFan65+TNRExo/2O3+MytJtQ/BXVkbYD58+iiZegddNTNGvz8WlPz2cZvPQt4x1TN+KOgJRKZH5imNAxCtRg6l1OLVxfwwUjKFgM4uAsto8vJv5DUFZQMO1Sh9gMpmzeMwXIF4fDD4O1TNiVmu3ABybt2Y4EdaQhs/ponC0SNcWbrY0stYbX+Wpk9/Hcxmo3zoduf1ZAdGM01E1g3IjQMd0gOP4v1KQtBjoHim2MCAwEAAQ==";
public static byte[] Encrypt(List<byte> key, string Salt, string UserName, string Password)
{
RSACryptoServiceProvider RSA = GetRSA();
string NewSalt = GetSalt(Salt);
byte[] DecryptedData = PublicDecrypt(key.ToArray(), RSA.ExportParameters(false));
RSACryptoServiceProvider newRSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = newRSA.ExportParameters(false);
RSAKeyInfo.Modulus = DecryptedData;
newRSA.ImportParameters(RSAKeyInfo);
List<byte> Credentials = new List<byte>();
Credentials.AddRange(Encoding.UTF8.GetBytes(NewSalt));
Credentials.Add((byte)UserName.Length);
Credentials.AddRange(Encoding.UTF8.GetBytes(UserName));
Credentials.AddRange(Encoding.UTF8.GetBytes(Password));
byte[] Encrypted = newRSA.Encrypt(Credentials.ToArray(), false);
System.Diagnostics.Debug.WriteLine("Encrypted = " + Convert.ToBase64String(Encrypted) + " - Taille : " + Encrypted.Length + "\r\n");
return Encrypted;
}
private static RSACryptoServiceProvider GetRSA()
{
RSACryptoServiceProvider RSA = DecodeX509PublicKey(Convert.FromBase64String(_RSAPublicKey));
return RSA;
}
private static string GetSalt(string Salt)
{
if (Salt.Length < 32)
{
while (Salt.Length < 32)
{
Salt += " ";
}
}
return Salt;
}
private static byte[] PublicDecrypt(byte[] Data, RSAParameters RSAParameters)
{
BigInteger Exponent = new BigInteger(RSAParameters.Exponent.Reverse().Concat(new byte[] { 0 }).ToArray());
BigInteger Modulus = new BigInteger(RSAParameters.Modulus.Reverse().Concat(new byte[] { 0 }).ToArray());
BigInteger PreparedData = new BigInteger(Data // Our data block
.Reverse() // BigInteger has another byte order
.Concat(new byte[] { 0 }) // Append 0 so we are always handling positive numbers
.ToArray() // Constructor wants an array
);
byte[] DecryptedData = BigInteger.ModPow(PreparedData, Exponent, Modulus) // The RSA operation itself
.ToByteArray() // Make bytes from BigInteger
.Reverse() // Back to "normal" byte order
.ToArray(); // Return as byte array
return DecryptedData.SkipWhile(x => x != 0).Skip(1).ToArray(); // PKCS#1 padding
}
private static RSACryptoServiceProvider DecodeX509PublicKey(byte[] X509Key)
{
// 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[] Seq = new byte[15];
// --------- Set up stream to read the ASN.1 encoded SubjectPublicKeyInfo blob ------
MemoryStream MemoryStream = new MemoryStream(X509Key);
BinaryReader BinaryReader = new BinaryReader(MemoryStream); // Wrap Memory Stream with BinaryReader for easy reading
byte Byte = 0;
ushort TwoBytes = 0;
try
{
TwoBytes = BinaryReader.ReadUInt16();
if (TwoBytes == 0x8130) // Data read as little endian order (actual data order for Sequence is 30 81)
BinaryReader.ReadByte(); // Advance 1 byte
else if (TwoBytes == 0x8230)
BinaryReader.ReadInt16(); // Advance 2 bytes
else
return null;
Seq = BinaryReader.ReadBytes(15); // Read the Sequence OID
if (!CompareByteArrays(Seq, SeqOID)) // Make sure Sequence for OID is correct
return null;
TwoBytes = BinaryReader.ReadUInt16();
if (TwoBytes == 0x8103) // Data read as little endian order (actual data order for Bit String is 03 81)
BinaryReader.ReadByte(); // Advance 1 byte
else if (TwoBytes == 0x8203)
BinaryReader.ReadInt16(); // Advance 2 bytes
else
return null;
Byte = BinaryReader.ReadByte();
if (Byte != 0x00) // Expect null byte next
return null;
TwoBytes = BinaryReader.ReadUInt16();
if (TwoBytes == 0x8130) // Data read as little endian order (actual data order for Sequence is 30 81)
BinaryReader.ReadByte(); // Advance 1 byte
else if (TwoBytes == 0x8230)
BinaryReader.ReadInt16(); // Advance 2 bytes
else
return null;
TwoBytes = BinaryReader.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 = BinaryReader.ReadByte(); // Read next bytes which is bytes in modulus
}
else if (TwoBytes == 0x8202)
{
HighByte = BinaryReader.ReadByte(); // Advance 2 bytes
LowByte = BinaryReader.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);
byte FirstByte = BinaryReader.ReadByte();
BinaryReader.BaseStream.Seek(-1, SeekOrigin.Current);
if (FirstByte == 0x00) // If first byte (highest order) of modulus is zero, don't include it
{
BinaryReader.ReadByte(); // Skip this null byte
ModSize -= 1; // Reduce modulus buffer size by 1
}
byte[] Modulus = BinaryReader.ReadBytes(ModSize); // Read the modulus bytes
if (BinaryReader.ReadByte() != 0x02) // Expect an Integer for the exponent data
return null;
int ExponentBytes = (int)BinaryReader.ReadByte(); // Should only need one byte for actual exponent data (for all useful values)
byte[] Exponent = BinaryReader.ReadBytes(ExponentBytes);
// ------- Create RSACryptoServiceProvider instance and initialize with public key -----
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = new RSAParameters()
{
Modulus = Modulus,
Exponent = Exponent
};
RSA.ImportParameters(RSAKeyInfo);
return RSA;
}
catch (Exception)
{
return null;
}
finally
{
BinaryReader.Close();
}
}
private static bool CompareByteArrays(byte[] FirstArray, byte[] SecondArray)
{
if (FirstArray.Length != SecondArray.Length)
return false;
int i = 0;
foreach (byte Byte in FirstArray)
{
if (Byte != SecondArray)
return false;
i++;
}
return true;
}
}
}