Well I managed to get something working without using the usual mega big 3rd party solutions if anyone is interested
that works in C# using an extension class that wraps dot.nets RSACryptoServiceProvider
Sample usage tested and shown belewstring secret = "My secret message";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512); // Key bits length
byte[] secretData = Encoding.UTF8.GetBytes(secret);
//Microsoft RSA byt default will encode with public key and decode with the private key
byte[] encPublic = rsa.PublicEncryption(secretData);
byte[] decPublic = rsa.PublicDecryption(encPublic);
//Now we can also encode with public key and decode with the private keys needed for signatures
byte[] encPrivate = rsa.PrivateEncryption(secretData);
byte[] decPrivate = rsa.PrivateDecryption(encPrivate);
//Just test we got the original data back
string MsgPublic = Encoding.UTF8.GetString(decPublic);
string MsgPrivate = Encoding.UTF8.GetString(decPrivate);
Complete listing shown below so just add a class to your project and drop this code in the file and you
should be good to go with most of the credit going to Dudi Bedner
//All credits go to Dudi Bedner at https://www.codeproject.com/Articles/38739/RSA-Private-Key-Encryption
//This is an extension class and extends RSACryptoServiceProvider so that it will encryt/decrypt using both public and private keys
using System;
using System.Text;
using System.Security.Cryptography;
using System.Numerics;
namespace RSAExtensions
{
public static class RSAPrivateEncryption
{
public static byte[] PublicEncryption(this RSACryptoServiceProvider rsa, byte[] data)
{
//rsa.FromXmlString(key);
byte[] encryptedData = rsa.Encrypt(data, false);
string base64Encrypted = Convert.ToBase64String(encryptedData);
return UTF8Encoding.UTF8.GetBytes(base64Encrypted);
}
public static byte[] PublicDecryption(this RSACryptoServiceProvider rsa, byte[] cipherData)
{
//var resultBytes = Convert.FromBase64String(EncryptedStr);
string Data = UTF8Encoding.UTF8.GetString(cipherData);
var resultBytes = Convert.FromBase64String(Data);
var decryptedBytes =rsa.Decrypt(resultBytes, false);
string decryptedData = Encoding.UTF8.GetString(decryptedBytes);
return UTF8Encoding.UTF8.GetBytes(decryptedData);
}
public static byte[] PrivateEncryption(this RSACryptoServiceProvider rsa, byte[] data)
{
if (data == null)
throw new ArgumentNullException("data");
if (rsa.PublicOnly)
throw new InvalidOperationException("Private key is not loaded");
int maxDataLength = (rsa.KeySize / 8) - 6;
if (data.Length > maxDataLength)
throw new ArgumentOutOfRangeException("data", string.Format(
"Maximum data length for the current key size ({0} bits) is {1} bytes (current length: {2} bytes)",
rsa.KeySize, maxDataLength, data.Length));
// Add 4 byte padding to the data, and convert to BigInteger struct
BigInteger numData = GetBig(AddPadding(data));
RSAParameters rsaParams = rsa.ExportParameters(true);
BigInteger D = GetBig(rsaParams.D);
BigInteger Modulus = GetBig(rsaParams.Modulus);
BigInteger encData = BigInteger.ModPow(numData, D, Modulus);
return encData.ToByteArray();
}
public static byte[] PrivateDecryption(this RSACryptoServiceProvider rsa, byte[] cipherData)
{
if (cipherData == null)
throw new ArgumentNullException("cipherData");
BigInteger numEncData = new BigInteger(cipherData);
RSAParameters rsaParams = rsa.ExportParameters(false);
BigInteger Exponent = GetBig(rsaParams.Exponent);
BigInteger Modulus = GetBig(rsaParams.Modulus);
BigInteger decData = BigInteger.ModPow(numEncData, Exponent, Modulus);
byte[] data = decData.ToByteArray();
byte[] result = new byte[data.Length - 1];
Array.Copy(data, result, result.Length);
result = RemovePadding(result);
Array.Reverse(result);
return result;
}
private static BigInteger GetBig(byte[] data)
{
byte[] inArr = (byte[])data.Clone();
Array.Reverse(inArr); // Reverse the byte order
byte[] final = new byte[inArr.Length + 1]; // Add an empty byte at the end, to simulate unsigned BigInteger (no negatives!)
Array.Copy(inArr, final, inArr.Length);
return new BigInteger(final);
}
// Add 4 byte random padding, first bit *Always On*
private static byte[] AddPadding(byte[] data)
{
Random rnd = new Random();
byte[] paddings = new byte[4];
rnd.NextBytes(paddings);
paddings[0] = (byte)(paddings[0] | 128);
byte[] results = new byte[data.Length + 4];
Array.Copy(paddings, results, 4);
Array.Copy(data, 0, results, 4, data.Length);
return results;
}
private static byte[] RemovePadding(byte[] data)
{
byte[] results = new byte[data.Length - 4];
Array.Copy(data, results, results.Length);
return results;
}
}
}