I need to implement a new, or already existing, encryption algorithm that encrypt and decrypt a string using another string as key. The problem is that this algorithm have to work independently from a computer on which it is used.
So the methods signature are:
public static string Encrypt(this string source, string key);
public static string Decrypt(this string source, string key);
I tried these algorithms, but they don't work the way I want:
public static string Encrypt(this string source, string key)
{
if (String.IsNullOrEmpty(source) || String.IsNullOrEmpty(key))
throw new ArgumentException();
CspParameters cspp = new CspParameters { KeyContainerName = key };
using (var rsa = new RSACryptoServiceProvider(cspp) { PersistKeyInCsp = true })
return BitConverter.ToString(rsa.Encrypt(UTF8Encoding.UTF8.GetBytes(source), true));
}
public static string Decrypt(this string source, string key)
{
if (String.IsNullOrEmpty(source) || String.IsNullOrEmpty(key))
throw new ArgumentException();
try
{
CspParameters cspp = new CspParameters { KeyContainerName = key };
using (var rsa = new RSACryptoServiceProvider(cspp) { PersistKeyInCsp = true })
{
string[] decryptArray = source.Split(new char[] { '-' }, StringSplitOptions.None);
byte[] bytes = Array.ConvertAll<string, byte>(decryptArray, (s => Convert.ToByte(Byte.Parse(s, NumberStyles.HexNumber))));
return UTF8Encoding.UTF8.GetString(rsa.Decrypt(bytes, true));
}
}
catch
{ return null; }
}
How can I do?
The KeyContainerName is NOT the key. In your example above, by passing the key as the store name, you'll create a NEW RSA keypair on each machine with a store name of the key you passed in (rather than a storename of something like "MyRSAKeyPair" or whatever). This will mean both the public and private keys will be completely different and your routines won't seem to work.
ALSO: You're using asymmetric encryption, this has a maximum block size limit of the key length. This means you'll either need to create a chunking mechanism (slow as asymmetric encryption is expensive) OR use something symmetric like AES with the AES key being sent using asymmetric encryption (such as RSA) on a per conversation basis.
You need to export the RSA public key and then import it into the remote machine's keystore. Easier still is generating an X509 certificate (you can self sign if you're just going between a couple of machines, exporting the public part of it into a .CER file, then you can use the X509 Certificate Store API to get the RSA Provider, meaning you have a nice transportable key.
public static RSACryptoServiceProvider GetRsaProviderFromCertificate()
{
X509Store store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection certCollection = (X509Certificate2Collection)store.Certificates;
foreach(X509Certificate2 cert in certCollection)
{
if (cert.SubjectName.Name.IndexOf("TheCertIWantToUse") > 0)
{
return cert.PrivateKey as RSACryptoServiceProvider;
}
}
I hope that's explicit enough...
If you want to do it without certs
// Export public key (on the encrypting end)
publicKey = rsaProvider.ToXmlString(false);
// Write public key to file
publicKeyFile = File.CreateText(publicKeyFileName);
publicKeyFile.Write(publicKey);
Then on the other machine
// Select target CSP
cspParams = new CspParameters();
cspParams.ProviderType = 1; // PROV_RSA_FULL
rsaProvider = new RSACryptoServiceProvider(cspParams);
// Read public key from file
publicKeyFile = File.OpenText(publicKeyFileName);
publicKeyText = publicKeyFile.ReadToEnd();
// Import public key
rsaProvider.FromXmlString(publicKeyText);
Related
I need to generate the RSA certificate(self signed certificate) with help of C# code. I have used the below code to create the certificate.
public bool CreateRSACertificate()
{
RSA rsaKey = RSA.Create();
CertificateRequest certRequest = new CertificateRequest("cn=MyApplication", rsaKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
certRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true));
certRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(certRequest.PublicKey, false));
X509Certificate2 certificate = certRequest.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5));
byte[] certData = certificate.Export(X509ContentType.Pfx, "TestPassword");
X509Certificate2 cert = new X509Certificate2(certData, "TestPassword", X509KeyStorageFlags.Exportable);
File.WriteAllBytes("MyCertificate.pfx", cert.Export(X509ContentType.Pfx, "TestPassword"));
return true;
}
And, after that I try to encrypt the data using the the certificate file which I created using the below code.
public bool EncryptAndDecryptFile()
{
string data = "{data: 'mydate123#gmail.com'}";
X509Certificate2 certificate = new X509Certificate2("MyCertificate.pfx", "TestPassword", X509KeyStorageFlags.Exportable);
if (certificate.HasPrivateKey) {
Console.WriteLine("Private key available "); // It's says like the private key was available
}
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(certificate.PublicKey.Key.ToXmlString(false));
byte[] bytes = Encoding.ASCII.GetBytes(data);
var encryptedData = rsa.Encrypt(bytes, false); //It seems the data encrypted. I'm not sure.But, I can able to see some encrypted data.
using (certificate.GetRSAPrivateKey()) {
RSACryptoServiceProvider drsa = new RSACryptoServiceProvider();
drsa.FromXmlString(certificate.PrivateKey.ToXmlString(false));
var decdata = drsa.Decrypt(encryptedData, false); // Here, I see some exception.
someString = Encoding.ASCII.GetString(decdata);
}
Console.WriteLine("someString someString ::: " + someString);
return true;
}
While, running the above code I see the below error.
Unhandled exception. Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Key not valid for use in specified state.
at Internal.NativeCrypto.CapiHelper.ExportKeyBlob(Boolean includePrivateParameters, SafeKeyHandle safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.ExportParameters(Boolean includePrivateParameters)
at ConfigUtility.X509Certificate.ReadRSACertificate()
To verify the certificate I have the below command,
certutil -dump MyCertificate.pfx
So, the above utility gave me the below output,
================ Certificate 0 ================
================ Begin Nesting Level 1 ================
Element 0:
Serial Number: 054834637a713ecf
Issuer: CN=MyApplication
NotBefore: 29-05-2020 13:49
NotAfter: 29-05-2025 13:49
Subject: CN=MyApplication
Signature matches Public Key
Root Certificate: Subject matches Issuer
Cert Hash(sha1): 16e83e8a92a38b948adad03a86768e27115851d4
---------------- End Nesting Level 1 ----------------
Provider = Microsoft Software Key Storage Provider
Private key is NOT plain text exportable
Encryption test passed
CertUtil: -dump command completed successfully.
In fact, you get exception in this line:
drsa.FromXmlString(certificate.PrivateKey.ToXmlString(false));
the whole encryption and decryption code pieces are incorrect, you are messing things with old an deprecated RSACryptoServiceProvider and doing unnecessary operations. Here is how the method should look like:
public bool EncryptAndDecryptFile() {
string data = "{data: 'mydate123#gmail.com'}";
X509Certificate2 certificate = new X509Certificate2("MyCertificate.pfx", "TestPassword", X509KeyStorageFlags.Exportable);
if (certificate.HasPrivateKey) {
Console.WriteLine("Private key available "); // It's says like the private key was available
}
Byte[] encryptedData = new Byte[0];
using (RSA pubKey = certificate.GetRSAPublicKey()) {
byte[] bytes = Encoding.ASCII.GetBytes(data);
encryptedData = rsa.Encrypt(bytes, RSAEncryptionPadding.OaepSHA256);
}
// assuming, encryptedData is not null
String someString = String.Empty;
using (RSA prKey = certificate.GetRSAPrivateKey()) {
Byte[] decdata = prKey.Decrypt(encryptedData, RSAEncryptionPadding.OaepSHA256);
someString = Encoding.ASCII.GetString(decdata);
}
return data.Equals(someString);
}
I am trying to perform a Diffie-Hellman key exchange using 2 ECDSA x509 certificates.
Here is the method where I extract the keys from the certificates for computation of the derived key.
private byte[] GetDerivedKey(X509Certificate2 publicCertificate, X509Certificate2 privateCertificate)
{
byte[] derivedKey;
using (var privateKey = privateCertificate.GetECDsaPrivateKey())
using (var publicKey = publicCertificate.GetECDsaPublicKey())
{
var privateParams = privateKey.ExportParameters(true); //This line is failing
var publicParams = publicKey.ExportParameters(false);
using (var privateCng = ECDiffieHellmanCng.Create(privateParams))
using (var publicCng = ECDiffieHellmanCng.Create(publicParams))
{
derivedKey = privateCng.DeriveKeyMaterial(publicCng.PublicKey);
}
}
return derivedKey;
}
I've commented on the line that is failing privateKey.ExportParameters(true) with the error:
System.Security.Cryptography.CryptographicException : The requested operation is not supported.
at System.Security.Cryptography.NCryptNative.ExportKey(SafeNCryptKeyHandle key, String format)
at System.Security.Cryptography.CngKey.Export(CngKeyBlobFormat format)
at System.Security.Cryptography.ECCng.ExportParameters(CngKey key, Boolean includePrivateParameters, ECParameters& ecparams)
at System.Security.Cryptography.ECDsaCng.ExportParameters(Boolean includePrivateParameters)
Because this is a self signed certificate that I am generating, I assume I am doing something wrong.
I first create a root CA certificate and pass in the private key to sign my certificate.
private X509Certificate2 CreateECSDACertificate(string certificateName,
string issuerCertificateName,
TimeSpan lifetime,
AsymmetricKeyParameter issuerPrivateKey,
string certificateFriendlyName = null)
{
// Generating Random Numbers
var randomGenerator = new CryptoApiRandomGenerator();
var random = new SecureRandom(randomGenerator);
var signatureFactory = new Asn1SignatureFactory("SHA256WithECDSA", issuerPrivateKey, random);
// The Certificate Generator
var certificateGenerator = new X509V3CertificateGenerator();
// Serial Number
var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
certificateGenerator.SetSerialNumber(serialNumber);
// Issuer and Subject Name
var subjectDistinguishedName = new X509Name($"CN={certificateName}");
var issuerDistinguishedName = new X509Name($"CN={issuerCertificateName}");
certificateGenerator.SetSubjectDN(subjectDistinguishedName);
certificateGenerator.SetIssuerDN(issuerDistinguishedName);
// Valid For
var notBefore = DateTime.UtcNow.Date;
var notAfter = notBefore.Add(lifetime);
certificateGenerator.SetNotBefore(notBefore);
certificateGenerator.SetNotAfter(notAfter);
//key generation
var keyGenerationParameters = new KeyGenerationParameters(random, _keyStrength);
var keyPairGenerator = new ECKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
var subjectKeyPair = keyPairGenerator.GenerateKeyPair();
certificateGenerator.SetPublicKey(subjectKeyPair.Public);
var certificate = certificateGenerator.Generate(signatureFactory);
var store = new Pkcs12Store();
var certificateEntry = new X509CertificateEntry(certificate);
store.SetCertificateEntry(certificateName, certificateEntry);
store.SetKeyEntry(certificateName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] { certificateEntry });
X509Certificate2 x509;
using (var pfxStream = new MemoryStream())
{
store.Save(pfxStream, null, new SecureRandom());
pfxStream.Seek(0, SeekOrigin.Begin);
x509 = new X509Certificate2(pfxStream.ToArray());
}
x509.FriendlyName = certificateFriendlyName;
return x509;
}
The .HasPrivateKey() method returns true, which I've read can return a false positive.
When I add my certificates to the store, I can verify the cert chain.
[Test]
public void CreateSelfSignedCertificate_AfterAddingToStore_CanBuildChain()
{
var result = _target.CreateSelfSignedCertificate(_subject, _issuer, TimeSpan.FromDays(356), _certificateFriendlyName, _issuerFriendlyName);
_store.TryAddCertificateToStore(result.CertificateAuthority, _caStoreName, _location);
_store.TryAddCertificateToStore(result.Certificate, _certStoreName, _location);
var chain = new X509Chain
{
ChainPolicy =
{
RevocationMode = X509RevocationMode.NoCheck
}
};
var chainBuilt = chain.Build(result.Certificate);
if (!chainBuilt)
{
foreach (var status in chain.ChainStatus)
{
Assert.Warn(string.Format("Chain error: {0} {1}", status.Status, status.StatusInformation));
}
}
Assert.IsTrue(chainBuilt, "Chain");
}
I thought at first that maybe the private cert had to come from the cert store, so I imported it and then pulled it back out, but I get the same error, which is another reason I believe I'm not doing something quite right.
EDIT:
I have another class generating RSA x509's using the same code for putting the private key into the certificate. It allows me to export the RSA private key.
The variable _keyStrength is 384 and my signature factory is using "SHA256withECDSA". I have also tried using "SHA384withECDSA" but I get the same error.
OK. It's a blind shot but after looking at your code I noticed two things:
When you create PFX you set null password. But when you load the PFX into X509Certificate2 class you are using wrong constructor. You should use one with a password parameter and give a null into it
When you load PFX into X509Certificate2 class you do not specify, if the private key should be exportable. I think that this is the reason why privateKey.ExportParameters(true) gives you an exception. You should use this constructor and specify null as password
Made it working
I thought it was a bug. It's possible that it is. We clearly stated in X509Constructor that the private key should be exportable. I used X509KeyStorageFlags.EphemeralKeySet | X509KeyStorageFlags.Exportable flags too. But when I looked at the CngKey it had ExportPolicy set to AllowExport but not AllowPlaintextExport.
It was exportable in some way. privateKey.Key.Export(CngKeyBlobFormat.OpaqueTransportBlob) worked. But privateKey.ExportParameters(true) did not.
I've searched for a solution how to change ExportPolicy of CngKey. I found this SO question that helped me to change it. After that the ExportParameters worked.
The fixed version of your GetDerivedKey method is
private byte[] GetDerivedKey(X509Certificate2 publicCertificate, X509Certificate2 privateCertificate)
{
byte[] derivedKey;
using (var privateKey = privateCertificate.GetECDsaPrivateKey())
using (var publicKey = privateCertificate.GetECDsaPublicKey())
{
var myPrivateKeyToMessWith = privateKey as ECDsaCng;
// start - taken from https://stackoverflow.com/q/48542233/3245057
// make private key exportable:
byte[] bytes = BitConverter.GetBytes((int)(CngExportPolicies.AllowExport | CngExportPolicies.AllowPlaintextExport));
CngProperty pty = new CngProperty(NCryptExportPolicyProperty, bytes, CngPropertyOptions.Persist);
myPrivateKeyToMessWith.Key.SetProperty(pty);
// end - taken from https://stackoverflow.com/q/48542233/3245057
var privateParams = myPrivateKeyToMessWith.ExportParameters(true); //This line is NOT failing anymore
var publicParams = publicKey.ExportParameters(false);
using (var privateCng = ECDiffieHellmanCng.Create(privateParams))
using (var publicCng = ECDiffieHellmanCng.Create(publicParams))
{
derivedKey = privateCng.DeriveKeyMaterial(publicCng.PublicKey);
}
}
return derivedKey;
}
I started using the solution #pepo posted which lead me to discover 'GetECDsaPrivateKey' does not return an ECDsa object but an ECDsaCng. I simplified the key derivation to this.
byte[] derivedKey;
using (var privateKey = (ECDsaCng)certificate.GetECDsaPrivateKey())
using (var publicKey = (ECDsaCng)certificate.GetECDsaPublicKey())
{
var publicParams = publicKey.ExportParameters(false);
using (var publicCng = ECDiffieHellmanCng.Create(publicParams))
using (var diffieHellman = new ECDiffieHellmanCng(privateKey.Key))
{
derivedKey = diffieHellman.DeriveKeyMaterial(publicCng.PublicKey);
}
}
return derivedKey;
I have setup Azure Key Vault to retrieve RSA Keys for encryption. Azure send me an object of type KeyBundle. This object contains a JsonWebKey of type RSA of size 2048. Looking at my RSA Key, it has 2 methods called Encrypt(byte[] data, RSAEncryptionPadding padding) and Decrypt(byte[] data, RSAEncryptionPadding padding). Now I am trying to encrypt and decrypt a simple string like this:
public EncryptionManager(KeyBundle encryptionKey)
{
string test = "Hello World!";
var key = encryptionKey.Key.ToRSA();
var encryptedString = key.Encrypt(Encoding.UTF8.GetBytes(test), RSAEncryptionPadding.OaepSHA256);
var decryptedString = key.Decrypt(encryptedString, RSAEncryptionPadding.OaepSHA256);
}
Encryption works, but decryption throws an exception with message:
Key does not exist.
Here is the StackTrace
at System.Security.Cryptography.RSAImplementation.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle
key, ReadOnlySpan`1 input, AsymmetricPaddingMode paddingMode, Void*
paddingInfo, Boolean encrypt) at
System.Security.Cryptography.RSAImplementation.RSACng.EncryptOrDecrypt(Byte[]
data, RSAEncryptionPadding padding, Boolean encrypt) at
System.Security.Cryptography.RSAImplementation.RSACng.Decrypt(Byte[]
data, RSAEncryptionPadding padding) at
NxtUtils.Security.EncryptionManager..ctor(KeyBundle encryptionKey) in
C:\Repos\Enigma\EnigmaPrototype\SharedLibaries\NxtUtils\Security\EncryptionManager.cs:line
26
I am really not familiar with cryptographic algorithms. My question is: How can I encrypt and decrypt a simple strig using this RSA Key provided by Azure?
Thanks!
I got the same issue, what I did is here although I searched from internet and got this from the Microsoft docs
so this is my working code below
public static class KeyVaultEncryptorDecryptor
{
public static string KeyDecryptText(this string textToDecrypt , KeyVaultClient keyVaultClient, string keyidentifier)
{
var kv = keyVaultClient;
try
{
var key = kv.GetKeyAsync(keyidentifier).Result;
var publicKey = Convert.ToBase64String(key.Key.N);
using var rsa = new RSACryptoServiceProvider();
var p = new RSAParameters() {
Modulus = key.Key.N, Exponent = key.Key.E
};
rsa.ImportParameters(p);
var encryptedTextNew = Convert.FromBase64String(textToDecrypt);
var decryptedData = kv.DecryptAsync(key.KeyIdentifier.Identifier.ToString(), JsonWebKeyEncryptionAlgorithm.RSAOAEP, encryptedTextNew).GetAwaiter().GetResult();
var decryptedText = Encoding.Unicode.GetString(decryptedData.Result);
return decryptedText;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return default;
}
}
public static string KeyEncryptText(this string textToEncrypt , KeyVaultClient keyVaultClient, string keyidentifier)
{
var kv = keyVaultClient;
try
{
var key = kv.GetKeyAsync(keyidentifier).GetAwaiter().GetResult();
var publicKey = Convert.ToBase64String(key.Key.N);
using var rsa = new RSACryptoServiceProvider();
var p = new RSAParameters() {
Modulus = key.Key.N, Exponent = key.Key.E
};
rsa.ImportParameters(p);
var byteData = Encoding.Unicode.GetBytes(textToEncrypt);
var encryptedText = rsa.Encrypt(byteData, true);
string encText = Convert.ToBase64String(encryptedText);
return encText;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return default;
}
}
}
ToRSA has a default boolean parameter indicating if the private key should be available, or not.
Since you didn't explicitly say true it is implicitly false, therefore your key object is public-only. With a public RSA key you can encrypt data or verify a signature, but you cannot sign or decrypt.
I need to use RSA encryption in my wp8 app and send it to the server. But the trouble I am facing is that I know the public key of the server and I need to encrypt the data in app side using the key. But as far I infer from all the posting here, RSACryptoservice provider class doesn't support a key from another source(Am I wrong?). Is there any way to use the class in such a scenario? Or can this be done by using third party library only?
I tried the following function but still no use. What am I doing wrong here?
public static string RSAEncrypt(string data)
{
try
{
//initialze the byte arrays to the public key information.
string pk = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0cNKUgLdLMpW5BWB+PAlIIIiqhSXk66PQVemUnRs3nowRcBETfUkMIfDcPDM1FXhh+/2FqsnFLveCYl980bylZlBghkjUleknV4dGLfQPuLE7oxk4tbQF6Zk9Fmc9ynxvZ7XDuLmdn/4mdxW7BmcSomLIxkkGHynKkkXk5QcKQIDAQAB";
byte[] PublicKey = Convert.FromBase64String(pk);
//byte[] Exponent = { 1, 0, 1 };
UnicodeEncoding pi = new UnicodeEncoding();
//Values to store encrypted symmetric keys.
byte[] dataBytes = pi.GetBytes(data);
//Create a new instance of RSACryptoServiceProvider.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
//Create a new instance of RSAParameters.
RSAParameters RSAKeyInfow = new RSAParameters();
//Set RSAKeyInfo to the public key values.
RSAKeyInfow.Modulus = PublicKey;
// RSAKeyInfow.Exponent = Exponent;
//Import key parameters into RSA.
RSA.ImportParameters(RSAKeyInfow);
var rslt = RSA.Encrypt(dataBytes, false);
System.Diagnostics.Debug.WriteLine(rslt);
return Convert.ToBase64String(rslt);
}
catch
{
return null;
}
}
Am calling this function in another page as:
private void Button_Click(object sender, RoutedEventArgs e)
{
var myString = "this is my string data";
var x = Class1.RSAEncrypt(myString);
MessageBox.Show(x);
}
The error I get is "Value cannot be null.
Parameter name: messageBoxText"
I think the problem here is not passing the exponent, but I don't know how.
I've been searching but I can't seem to find a simple way of decrypting using RSA.
I have generated a public and private key, they are stored in two separate files and are in the XML format. I have no problem associating the public key to the RSACryptoServiceProvider object using FromXmlString, and then encrypting a string. My confusion comes when trying to decrypt an encrypted string. I'm not sure how I associate the private key data with the RSACryptoServiceProvider so that I can use the Decrypt function.
Any help would be appreciated.
EDIT:
The format of the public and private key is XML generated by the RSACryptoServiceProvider object, which I just put into a file:
<RSAKeyValue><Modulus>vS7Y5up+6kHMx7hQjKA6sKlIVASaw ... etc ...
I load the public key using this code:
StreamReader sr = new StreamReader(HttpContext.Current.Server.MapPath("public.key"));
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(sr.ReadToEnd().ToString());
I currently haven't tried anything with the private key yet, since I'm not sure where to start.
I don't know your situation but I would suggest that you store you key information in a KeyContainer. If you do this you can access the keyContainer by name and can do something like this.
// retrieves the maximum number of characters that can be decrypted at once
private int getMaxBlockSize(int keySize){
int max = ((int)(keysize/8/3) )* 4
if (keySize / 8 mod 3 != 0){
max += 4
}
return max;
}
public string decrypt(string msg, string containerName){
CspParameters params = new CspParameters();
params.KeyContainerName = containerName;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(params);
StringBuilder decryptedMsg = new StringBuilder();
int maxDecryptSize = getMaxBlockSize(rsa.KeySize);
int iterationCount = Math.Floor(msg.length / maxDecryptSize)
for(int i=0; i<iterationCount; i++){
int start = i * maxDecryptSize;
int blkSize = Math.min(start + maxDecryptSize, msg.Length);
Byte[] msgBytes = System.Convert.FromBase64String(msg.Substring(start, blkSize));
decryptedMsg.Append(System.Text.Encoding.Unicode.GetString(RSAProvider.Decrypt(msgBytes, false));
}
return decryptedMsg.ToString();
}
I haven't tested this out so there might be a bug in here but the you get the idea.
if you have private key in text format
like given below
-----BEGIN RSA PRIVATE KEY-----
text....
-----END RSA PRIVATE KEY-----
public string RsaDecryptWithPrivate(string base64Input, string privateKey)
{
var bytesToDecrypt = Convert.FromBase64String(base64Input);
AsymmetricCipherKeyPair keyPair;
var decryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(privateKey))
{
keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();//fetch key pair from text file
decryptEngine.Init(false, keyPair.Private);
}
var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
return decrypted;
}