Encrypt string using public key as text in C# - c#

I have recieved a public keY in txt format. (BEGIN CERTIFICATE---END CERTIFICATE)
I want to encrypt my message using this key in C# and send it across.
Similarly I have my private key in text format. I have shared my public key with the third party, which they are using to encrypt the message. I want to decrypt the message using my private key in TEXT format.
How do i do that in C#?
Kindly help.

public class MyCrypto
{
public X509Certificate2 GetDecryptionCertificate(string certificateName)
{
var my = new X509Store(StoreName.My, StoreLocation.LocalMachine);
my.Open(OpenFlags.ReadOnly);
var collection = my.Certificates.Find(X509FindType.FindBySubjectName, certificateName, false);
if (collection.Count == 1)
{
return collection[0];
}
else if (collection.Count > 1)
{
throw new Exception(string.Format("More than one certificate with name '{0}' found in store LocalMachine/My.", certificateName));
}
else
{
throw new Exception(string.Format("Certificate '{0}' not found in store LocalMachine/My.", certificateName));
}
}
public X509Certificate2 GetEncryptionCertificate(string filePath)
{
var collection = new X509Certificate2Collection();
collection.Import(filePath);
return collection[0];
}
public string EncryptRsa(string input, X509Certificate2 x509Certificate2)
{
var output = string.Empty;
using (RSA csp = (RSA)x509Certificate2.PublicKey.Key)
{
byte[] bytesData = Encoding.UTF8.GetBytes(input);
byte[] bytesEncrypted = csp.Encrypt(bytesData, RSAEncryptionPadding.OaepSHA1);
output = Convert.ToBase64String(bytesEncrypted);
}
return output;
}
public string DecryptRsa(string encrypted, X509Certificate2 x509Certificate2)
{
var text = string.Empty;
using (RSA csp = (RSA)x509Certificate2.PrivateKey)
{
byte[] bytesEncrypted = Convert.FromBase64String(encrypted);
byte[] bytesDecrypted = csp.Decrypt(bytesEncrypted, RSAEncryptionPadding.OaepSHA1);
text = Encoding.UTF8.GetString(bytesDecrypted);
}
return text;
}
}

Related

Bouncy Castle Encrypt and Decrypt Password - Org.BouncyCastle.Crypto.InvalidCipherTextException: 'block incorrect'

NOTE: This is NOT for encrypting user passwords. Use a Hash to store user passwords. You can also throw some salt on those passwords similarly to salt bae.
I need to store one of my passwords to log into a program. I can encrypt the password but when I decrypt I get the error:
Org.BouncyCastle.Crypto.InvalidCipherTextException: 'block incorrect'
I am going to use a different private key so I'm not worried about posting this one here.
Program Class:
var input = "TestPassword123!";
Encryption EC = new Encryption();
var Key = "-----BEGIN RSA PRIVATE KEY-----MIICXAIBAAKBgQCr874y+f3cYtz8hOuxamwHYUK7WS03c3t7LHMuCpmiR9wOz1FHEbBk6ZdvhY74I9sE+lIs0bUZVh08nKIS/txeECZ/d3WYDm8gW+mFjg0xD7LgQ9Prchsvrb2Q9c6FK5Us8i0iqOhDmrZdCYO+/zhyrYnP/Wy1EZTWPvMrI/GVWwIDAQABAoGBAJW5Sg8HIKYKq5NxhezY1rHiXYHWV4nmE0ogXTZk4nusiI+Ys5PncimcQFFKAUBNsEL4WB9QhplGI3UIihNyOZx68waSB6NiAi+tz8i7edTxDfwWkM271roOJxD3RzUJuQkyc57ZxrD61UyodRatmRoJkPhLBlEvIr9/dCwYBl0pAkEA5ucK8CFdxr4DWIAutZLeeeQx9oe1tCi/iUvEpSDOHKAvaELLBiD4bIInN4nx/Gj1gwHqICg8L/gs0x23cQWz3QJBAL6kYaRQFvCmVajTaTJ3ef3gYwynPsmfT5Urx0DWW5rXtbtZQ7vScDKRU4YbmBb3tD5eT/Fl/dIakPGv+hxllpcCQA3o5TPKDsgmMjVmo2m0y0o0gP4E9uE/gypWMiZwb3ox/CkfvPNFkTGYNZyW5sj52bBmsR/2zIlnPewJ4j8gxNECQDOT/8LX1E0Jg5VolUaNIpk4UzQCL6+XBY4DSSZWmHQdNlLYxMWVGrvjq6hV4OEd5UsWcySJhpGIlHx/Mvjp10MCQAon0SLhRI8QNrWfp/dLuFdqTy4b4y64j3HvooOu6GDZwCLwjqvwML3rimxUi52EQspssIOlLjpQjvIJvYBKBys=-----END RSA PRIVATE KEY-----";
var encrypted = EC.RsaEncrypt(input, Key);
string password = EC.RsaDecrypt(encrypted, Key);
Encryption Class
using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.OpenSsl;
namespace TemarkNamespace
{
internal class Encryption
{
public string RsaEncrypt(string clearText, string Key)
{
var bytesToEncrypt = Encoding.UTF8.GetBytes(clearText);
var encryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(Key))
{
var keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
encryptEngine.Init(true, keyPair.Private);
}
var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length));
return encrypted;
}
// Decryption:
public string RsaDecrypt(string pass, string Key)
{
var bytesToDecrypt = Convert.FromBase64String(pass);
AsymmetricCipherKeyPair keyPair;
var decryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(Key))
{
keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
decryptEngine.Init(false, keyPair.Private);
}
var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
return decrypted;
}
}
}
I found this code and it seems to work fine
using System.Security.Cryptography;
public string Encrypt(string s)
{
if (String.IsNullOrEmpty(s))
{
return s;
}
else
{
var encoding = new UTF8Encoding();
byte[] plain = encoding.GetBytes(s);
byte[] secret = ProtectedData.Protect(plain, null, DataProtectionScope.CurrentUser);
return Convert.ToBase64String(secret);
}
}
public string Decrypt(string s)
{
if (String.IsNullOrEmpty(s))
{
return s;
}
else
{
byte[] secret = Convert.FromBase64String(s);
byte[] plain = ProtectedData.Unprotect(secret, null, DataProtectionScope.CurrentUser);
var encoding = new UTF8Encoding();
return encoding.GetString(plain);
}
}

C# RSA encrypt with pre generated string key [duplicate]

I've seen plenty of encryption/decryption tutorials and examples on the net in C# that use the System.Security.Cryptography.RSACryptoServiceProvider, but what I'm hoping to be able to do is:
Create an RSA public/private keypair
Transmit the public key (or for proof of concept, just move it in a string variable)
Create a new RSA crypto provider and encrypt a string with the public key
Transmit the encrypted string (or data) back to the original crypto provider and decrypt the string
Could anyone point me to a useful resource for this?
well there are really enough examples for this, but anyway, here you go
using System;
using System.Security.Cryptography;
namespace RsaCryptoExample
{
static class Program
{
static void Main()
{
//lets take a new CSP with a new 2048 bit rsa key pair
var csp = new RSACryptoServiceProvider(2048);
//how to get the private key
var privKey = csp.ExportParameters(true);
//and the public key ...
var pubKey = csp.ExportParameters(false);
//converting the public key into a string representation
string pubKeyString;
{
//we need some buffer
var sw = new System.IO.StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, pubKey);
//get the string from the stream
pubKeyString = sw.ToString();
}
//converting it back
{
//get a stream from the string
var sr = new System.IO.StringReader(pubKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
pubKey = (RSAParameters)xs.Deserialize(sr);
}
//conversion for the private key is no black magic either ... omitted
//we have a public key ... let's get a new csp and load that key
csp = new RSACryptoServiceProvider();
csp.ImportParameters(pubKey);
//we need some data to encrypt
var plainTextData = "foobar";
//for encryption, always handle bytes...
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(plainTextData);
//apply pkcs#1.5 padding and encrypt our data
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
//we might want a string representation of our cypher text... base64 will do
var cypherText = Convert.ToBase64String(bytesCypherText);
/*
* some transmission / storage / retrieval
*
* and we want to decrypt our cypherText
*/
//first, get our bytes back from the base64 string ...
bytesCypherText = Convert.FromBase64String(cypherText);
//we want to decrypt, therefore we need a csp and load our private key
csp = new RSACryptoServiceProvider();
csp.ImportParameters(privKey);
//decrypt and strip pkcs#1.5 padding
bytesPlainTextData = csp.Decrypt(bytesCypherText, false);
//get our original plainText back...
plainTextData = System.Text.Encoding.Unicode.GetString(bytesPlainTextData);
}
}
}
as a side note: the calls to Encrypt() and Decrypt() have a bool parameter that switches between OAEP and PKCS#1.5 padding ... you might want to choose OAEP if it's available in your situation
public static string Encryption(string strText)
{
var publicKey = "<RSAKeyValue><Modulus>21wEnTU+mcD2w0Lfo1Gv4rtcSWsQJQTNa6gio05AOkV/Er9w3Y13Ddo5wGtjJ19402S71HUeN0vbKILLJdRSES5MHSdJPSVrOqdrll/vLXxDxWs/U0UT1c8u6k/Ogx9hTtZxYwoeYqdhDblof3E75d9n2F0Zvf6iTb4cI7j6fMs=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
var testData = Encoding.UTF8.GetBytes(strText);
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
// client encrypting data with public key issued by server
rsa.FromXmlString(publicKey.ToString());
var encryptedData = rsa.Encrypt(testData, true);
var base64Encrypted = Convert.ToBase64String(encryptedData);
return base64Encrypted;
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
}
public static string Decryption(string strText)
{
var privateKey = "<RSAKeyValue><Modulus>21wEnTU+mcD2w0Lfo1Gv4rtcSWsQJQTNa6gio05AOkV/Er9w3Y13Ddo5wGtjJ19402S71HUeN0vbKILLJdRSES5MHSdJPSVrOqdrll/vLXxDxWs/U0UT1c8u6k/Ogx9hTtZxYwoeYqdhDblof3E75d9n2F0Zvf6iTb4cI7j6fMs=</Modulus><Exponent>AQAB</Exponent><P>/aULPE6jd5IkwtWXmReyMUhmI/nfwfkQSyl7tsg2PKdpcxk4mpPZUdEQhHQLvE84w2DhTyYkPHCtq/mMKE3MHw==</P><Q>3WV46X9Arg2l9cxb67KVlNVXyCqc/w+LWt/tbhLJvV2xCF/0rWKPsBJ9MC6cquaqNPxWWEav8RAVbmmGrJt51Q==</Q><DP>8TuZFgBMpBoQcGUoS2goB4st6aVq1FcG0hVgHhUI0GMAfYFNPmbDV3cY2IBt8Oj/uYJYhyhlaj5YTqmGTYbATQ==</DP><DQ>FIoVbZQgrAUYIHWVEYi/187zFd7eMct/Yi7kGBImJStMATrluDAspGkStCWe4zwDDmdam1XzfKnBUzz3AYxrAQ==</DQ><InverseQ>QPU3Tmt8nznSgYZ+5jUo9E0SfjiTu435ihANiHqqjasaUNvOHKumqzuBZ8NRtkUhS6dsOEb8A2ODvy7KswUxyA==</InverseQ><D>cgoRoAUpSVfHMdYXW9nA3dfX75dIamZnwPtFHq80ttagbIe4ToYYCcyUz5NElhiNQSESgS5uCgNWqWXt5PnPu4XmCXx6utco1UVH8HGLahzbAnSy6Cj3iUIQ7Gj+9gQ7PkC434HTtHazmxVgIR5l56ZjoQ8yGNCPZnsdYEmhJWk=</D></RSAKeyValue>";
var testData = Encoding.UTF8.GetBytes(strText);
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
var base64Encrypted = strText;
// server decrypting data with private key
rsa.FromXmlString(privateKey);
var resultBytes = Convert.FromBase64String(base64Encrypted);
var decryptedBytes = rsa.Decrypt(resultBytes, true);
var decryptedData = Encoding.UTF8.GetString(decryptedBytes);
return decryptedData.ToString();
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
}
Honestly, I have difficulty implementing it because there's barely any tutorials I've searched that displays writing the keys into the files. The accepted answer was "fine". But for me I had to improve it so that both keys gets saved into two separate files. I've written a helper class so y'all just gotta copy and paste it. Hope this helps lol.
using Microsoft.Win32;
using System;
using System.IO;
using System.Security.Cryptography;
namespace RsaCryptoExample
{
class RSAFileHelper
{
readonly string pubKeyPath = "public.key";//change as needed
readonly string priKeyPath = "private.key";//change as needed
public void MakeKey()
{
//lets take a new CSP with a new 2048 bit rsa key pair
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(2048);
//how to get the private key
RSAParameters privKey = csp.ExportParameters(true);
//and the public key ...
RSAParameters pubKey = csp.ExportParameters(false);
//converting the public key into a string representation
string pubKeyString;
{
//we need some buffer
var sw = new StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, pubKey);
//get the string from the stream
pubKeyString = sw.ToString();
File.WriteAllText(pubKeyPath, pubKeyString);
}
string privKeyString;
{
//we need some buffer
var sw = new StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, privKey);
//get the string from the stream
privKeyString = sw.ToString();
File.WriteAllText(priKeyPath, privKeyString);
}
}
public void EncryptFile(string filePath)
{
//converting the public key into a string representation
string pubKeyString;
{
using (StreamReader reader = new StreamReader(pubKeyPath)){pubKeyString = reader.ReadToEnd();}
}
//get a stream from the string
var sr = new StringReader(pubKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
csp.ImportParameters((RSAParameters)xs.Deserialize(sr));
byte[] bytesPlainTextData = File.ReadAllBytes(filePath);
//apply pkcs#1.5 padding and encrypt our data
var bytesCipherText = csp.Encrypt(bytesPlainTextData, false);
//we might want a string representation of our cypher text... base64 will do
string encryptedText = Convert.ToBase64String(bytesCipherText);
File.WriteAllText(filePath,encryptedText);
}
public void DecryptFile(string filePath)
{
//we want to decrypt, therefore we need a csp and load our private key
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
string privKeyString;
{
privKeyString = File.ReadAllText(priKeyPath);
//get a stream from the string
var sr = new StringReader(privKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
RSAParameters privKey = (RSAParameters)xs.Deserialize(sr);
csp.ImportParameters(privKey);
}
string encryptedText;
using (StreamReader reader = new StreamReader(filePath)) { encryptedText = reader.ReadToEnd(); }
byte[] bytesCipherText = Convert.FromBase64String(encryptedText);
//decrypt and strip pkcs#1.5 padding
byte[] bytesPlainTextData = csp.Decrypt(bytesCipherText, false);
//get our original plainText back...
File.WriteAllBytes(filePath, bytesPlainTextData);
}
}
}
I'll share my very simple code for sample purpose. Hope it will help someone like me searching for quick code reference.
My goal was to receive rsa signature from backend, then validate against input string using public key and store locally for future periodic verifications.
Here is main part used for signature verification:
...
var signature = Get(url); // base64_encoded signature received from server
var inputtext= "inputtext"; // this is main text signature was created for
bool result = VerifySignature(inputtext, signature);
...
private bool VerifySignature(string input, string signature)
{
var result = false;
using (var cps=new RSACryptoServiceProvider())
{
// converting input and signature to Bytes Arrays to pass to VerifyData rsa method to verify inputtext was signed using privatekey corresponding to public key we have below
byte[] inputtextBytes = Encoding.UTF8.GetBytes(input);
byte[] signatureBytes = Convert.FromBase64String(signature);
cps.FromXmlString("<RSAKeyValue><Modulus>....</Modulus><Exponent>....</Exponent></RSAKeyValue>"); // xml formatted publickey
result = cps.VerifyData(inputtextBytes , new SHA1CryptoServiceProvider(), signatureBytes );
}
return result;
}
for big data
public class RsaService : System.IDisposable
{
public delegate int TransformBlockCall(System.ReadOnlySpan<byte> data, System.Span<byte> destination);
private readonly RSA _encoder;
private readonly RSAEncryptionPadding _padding;
private readonly TransformBlockCall _encryptBlockCall;
private readonly TransformBlockCall _decryptBlockCall;
private int _encrypt_InputBlockSize;
private int _encrypt_OutputBlockSize;
private int _decrypt_InputBlockSize;
private int _decrypt_OutputBlockSize;
public RsaService(RSA encoder) {
if(encoder == null)
throw new System.ArgumentNullException(nameof(encoder));
_encoder = encoder;
_padding = RSAEncryptionPadding.Pkcs1;
_encryptBlockCall = new TransformBlockCall(EncryptBlock);
_decryptBlockCall = new TransformBlockCall(DecryptBlock);
OnEndSetParameters();
}
private void OnEndSetParameters() {
_encrypt_InputBlockSize = GetSizeOutputEncryptOfKeySize(_encoder.KeySize);
_encrypt_OutputBlockSize = _encoder.KeySize / 8;
_decrypt_InputBlockSize = _encrypt_OutputBlockSize;
_decrypt_OutputBlockSize = _encrypt_OutputBlockSize;
}
public void ImportParameters(RSAParameters parameters) {
_encoder.ImportParameters(parameters);
OnEndSetParameters();
}
public byte[] Encrypt(byte[] data) {
if(data == null) throw new System.ArgumentNullException(nameof(data));
if(data.Length == 0) return data;
int outputLength = GetEncryptOutputMaxByteCount(data.Length);
byte[] outputData = new byte[outputLength];
Encrypt(data, outputData);
return outputData;
}
public byte[] Decrypt(byte[] data) {
if(data == null) throw new System.ArgumentNullException(nameof(data));
if(data.Length == 0) return data;
int maxOutputLength = GetDecryptOutputMaxByteCount(data.Length);
byte[] outputData = new byte[maxOutputLength];
int actual_OutputLength = Decrypt(data, outputData);
if(maxOutputLength > actual_OutputLength)
System.Array.Resize(ref outputData, actual_OutputLength);
return outputData;
}
public int Encrypt(System.ReadOnlySpan<byte> data, System.Span<byte> destination) {
#if DEBUG
int inputBlockSize = _encrypt_InputBlockSize;
int outputBlockSize = _encoder.KeySize / 8;
int blockCount = (data.Length / inputBlockSize);
if(data.Length % inputBlockSize != 0)
blockCount++;
System.Diagnostics.Debug.Assert((blockCount * outputBlockSize) <= destination.Length);
#endif
if(data.Length > _encrypt_InputBlockSize)
return TransformFinal(_encryptBlockCall, data, destination, _encrypt_InputBlockSize);
else
return _encryptBlockCall(data, destination);
}
public int Decrypt(System.ReadOnlySpan<byte> data, System.Span<byte> destination) {
if(data.Length > _decrypt_InputBlockSize)
return TransformFinal(_decryptBlockCall, data, destination, _decrypt_InputBlockSize);
else
return _decryptBlockCall(data, destination);
}
private int EncryptBlock(System.ReadOnlySpan<byte> data, System.Span<byte> destination) => _encoder.Encrypt(data, destination, _padding);
private int DecryptBlock(System.ReadOnlySpan<byte> data, System.Span<byte> destination) => _encoder.Decrypt(data, destination, _padding);
public int GetEncryptOutputMaxByteCount(int inputCount) => GetBlockCount(inputCount, _encrypt_InputBlockSize) * _encrypt_OutputBlockSize;
public int GetDecryptOutputMaxByteCount(int inputCount) => GetBlockCount(inputCount, _decrypt_InputBlockSize) * _decrypt_OutputBlockSize;
public void Dispose() {
_encoder.Dispose();
System.GC.SuppressFinalize(this);
}
#region Methods_Helper
public static RsaService Create(RSAParameters parameters) => new RsaService(RSA.Create(parameters));
public static RsaService Create() => new RsaService(RSA.Create());
// [keySize] ÷ 8 - [11 bytes for padding] = Result
// Exsimple: [2048 key size] ÷ 8 - [11 bytes for padding] = 245
public static int GetSizeOutputEncryptOfKeySize(int keySize) => (keySize / 8) - 11;
private static int GetBlockCount(int dataLength,int inputBlockSize) {
int blockCount = (dataLength / inputBlockSize);
if(dataLength % inputBlockSize != 0)
blockCount++;
return blockCount;
}
public static int TransformFinal(TransformBlockCall transformBlockCall, System.ReadOnlySpan<byte> data, System.Span<byte> destination, int inputBlockSize) {
int blockCount = GetBlockCount(data.Length, inputBlockSize);
int data_writtenCount = 0;
int destination_writtenCount = 0;
while(blockCount-- > 0) {
if(blockCount == 0) {
inputBlockSize = data.Length - data_writtenCount;
if(inputBlockSize == 0) break;
}
destination_writtenCount += transformBlockCall(data: data.Slice(data_writtenCount, inputBlockSize)
, destination: destination.Slice(destination_writtenCount));
data_writtenCount += inputBlockSize;
}
return destination_writtenCount;
}
public static (RSAParameters keyPublic, RSAParameters keyPrivate) GenerateKeyPair(int keySize = 2048) {
RSAParameters keyPriv;
RSAParameters keyPub;
using(var rsa = RSA.Create(keySize)) {
keyPriv = rsa.ExportParameters(true);
keyPub = rsa.ExportParameters(false);
}
return (keyPub, keyPriv);
}
#endregion Methods_Helper
}
public static class Program
{
static void Main() {
var (keyPublic, keyPrivate) = RsaService.GenerateKeyPair();
var encryptor = RsaService.Create(keyPublic);
var decryptor = RsaService.Create(keyPrivate);
string originalText = "";
for(int i = 0; i < 1000; i++) {
originalText += "ABC123456789";
}
byte[] inputData = Encoding.UTF8.GetBytes(originalText); // data random for test
System.Console.WriteLine("inputData.Length: {0}", inputData.Length);
var encryptedData = encryptor.Encrypt(inputData);
System.Console.WriteLine("encryptedData.Length: {0}", encryptedData.Length);
byte[] decryptedData = decryptor.Decrypt(encryptedData);
string decryptedText = Encoding.UTF8.GetString(decryptedData);
System.Console.WriteLine("status: {0}", decryptedText == originalText);
}
}

AesCng persisted key export/import: Import fails with CryptographicException: The supplied handle is invalid

I need to securely persist AES key(s) to be used by the .NET AesCng algorithm. The idea is to use the CngKey class to persist the key(s) and leverage its export/import functionality to maintain the same key(s) across multiple servers.
I can create the persisted AES key
public static bool CreateContainer(string name)
{
if (CngKey.Exists(name))
{
return false;
}
CngKeyCreationParameters keyCreationParameters = new CngKeyCreationParameters()
{
ExportPolicy = CngExportPolicies.AllowPlaintextExport,
KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey
};
CngKey cngKey = CngKey.Create(new CngAlgorithm("AES"), name, keyCreationParameters);
cngKey.Dispose();
return true;
}
and then use it to encrypt/decrypt
public static byte[] Encrypt(string keyContainerName, byte[] clearText, byte[] iv)
{
AesCng aesCng = null;
ICryptoTransform crypto = null;
byte[] cipher = null;
try
{
aesCng = new AesCng(keyContainerName);
aesCng.IV = (iv == null ? new byte[aesCng.IV.Length] : iv);
crypto = aesCng.CreateEncryptor();
cipher = crypto.TransformFinalBlock(clearText, 0, clearText.Length);
}
finally
{
if (crypto != null)
{
crypto.Dispose();
}
if (aesCng != null)
{
aesCng.Clear();
aesCng.Dispose();
}
}
return cipher;
}
public static byte[] Decrypt(string keyContainerName, byte[] cipher, byte[] iv)
{
AesCng aesCng = null;
ICryptoTransform crypto = null;
byte[] clearText = null;
try
{
aesCng = new AesCng(keyContainerName);
aesCng.IV = (iv == null ? new byte[aesCng.IV.Length] : iv);
crypto = aesCng.CreateDecryptor();
clearText = crypto.TransformFinalBlock(cipher, 0, cipher.Length);
}
finally
{
if (crypto != null)
{
crypto.Dispose();
}
if (aesCng != null)
{
aesCng.Clear();
aesCng.Dispose();
}
}
return clearText;
}
I am able to export the key
public static bool ExportKey(string name, out byte[] blob)
{
blob = null;
if (!CngKey.Exists(name))
{
return false;
}
CngKey cngKey = CngKey.Open(name);
blob = cngKey.Export(CngKeyBlobFormat.OpaqueTransportBlob);
cngKey.Dispose();
return true;
}
However, when I try to import the blob, I get a CryptographicException: The supplied handle is invalid.
public static void ImportKey(string name, byte[] blob)
{
CngKey cngKey = CngKey.Import(blob, CngKeyBlobFormat.OpaqueTransportBlob);
cngKey.Dispose();
}
I am at a loss to explain why the failure.
Can anyone shed some light on this?
Thanks.

Error occurred while decoding OAEP Padding C#

Below is my code and error is in the Title. I encrypted using private key but I decrypt using the same private key I ran into the error mentioned in the title, not really sure what is the underlying cause of the error. Any help in that regard will be highly appreciated.
Class Program
{
static void Main(string[] args)
{
string thumbPrint = "SomeValue";
EncryptUserName("Steve", thumbPrint, true, true);
}
public static void EncryptUserName(string textToEncript, string certificateThumbprint, bool searchLocalMachine, bool searchUser)
{
X509Certificate2 cert = FindCertificate(certificateThumbprint, searchLocalMachine, searchUser);
RSACryptoServiceProvider rsaEncryptor = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] cipherData = rsaEncryptor.Encrypt(Encoding.UTF8.GetBytes(textToEncript), true);
var encryptedString = Convert.ToBase64String(cipherData);
Console.WriteLine(encryptedString);
}
public static byte[] Decrypt(byte[] encryptedData, bool fOAEP, X509Certificate2 certificate)
{
if (encryptedData == null)
{
throw new ArgumentNullException("encryptedData");
}
if (certificate == null)
{
throw new ArgumentNullException("certificate");
}
if (certificate.PrivateKey == null)
{
throw new ApplicationException("Certificate provided has no private key");
}
Console.WriteLine(certificate.PrivateKey);
using (RSACryptoServiceProvider provider = (RSACryptoServiceProvider)certificate.PrivateKey)
{
return provider.Decrypt(encryptedData, fOAEP);
}
}
public static string CertificateDecrypt(string textToDecript, string certificateThumbprint, bool searchLocalMachine, bool searchUser)
{
X509Certificate2 certificate = FindCertificate(certificateThumbprint, searchLocalMachine, searchUser);
byte[] bytesArray = Convert.FromBase64String(textToDecript);
//Decrypt(bytesArray, true, certificate);
return Encoding.UTF8.GetString(Decrypt(bytesArray, true, certificate));
}
public static X509Certificate2 LoadCertificate(StoreName storeName, StoreLocation storeLocation, string thumbprint)
{
X509Store store = null;
X509Certificate2 certificate2;
try
{
store = new X509Store(storeName, storeLocation);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Enumerator enumerator = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false).GetEnumerator();
X509Certificate2 current = null;
while (enumerator.MoveNext())
{
current = enumerator.Current;
}
certificate2 = current;
}
finally
{
if (store != null)
{
store.Close();
}
}
return certificate2;
}
private static X509Certificate2 FindCertificate(string certificateThumbprint, bool searchLocalMachine, bool searchUser)
{
certificateThumbprint = certificateThumbprint.Replace(" ", "");
X509Certificate2 certificate = null;
if (searchUser)
{
certificate = LoadCertificate(StoreName.My, StoreLocation.CurrentUser, certificateThumbprint);
}
if (searchLocalMachine && (certificate == null))
{
certificate = LoadCertificate(StoreName.My, StoreLocation.LocalMachine, certificateThumbprint);
}
if (certificate == null)
{
throw new ApplicationException($"Certificate with thumbprint {certificateThumbprint} cannot be loaded (not found)");
}
return certificate;
}
}
Error occurred while decoding OAEP Padding happens when either the input string for the decrypt is not exactly the same as the output string of the encrypt, or because the public key used for encryption does not match the private key used for decryption.
In your case, you are not actually passing an encrypted string to the Decrypt method so it will absolutely always fail, essentially making the encryption and decryption key not match.

C# RSA encryption/decryption with transmission

I've seen plenty of encryption/decryption tutorials and examples on the net in C# that use the System.Security.Cryptography.RSACryptoServiceProvider, but what I'm hoping to be able to do is:
Create an RSA public/private keypair
Transmit the public key (or for proof of concept, just move it in a string variable)
Create a new RSA crypto provider and encrypt a string with the public key
Transmit the encrypted string (or data) back to the original crypto provider and decrypt the string
Could anyone point me to a useful resource for this?
well there are really enough examples for this, but anyway, here you go
using System;
using System.Security.Cryptography;
namespace RsaCryptoExample
{
static class Program
{
static void Main()
{
//lets take a new CSP with a new 2048 bit rsa key pair
var csp = new RSACryptoServiceProvider(2048);
//how to get the private key
var privKey = csp.ExportParameters(true);
//and the public key ...
var pubKey = csp.ExportParameters(false);
//converting the public key into a string representation
string pubKeyString;
{
//we need some buffer
var sw = new System.IO.StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, pubKey);
//get the string from the stream
pubKeyString = sw.ToString();
}
//converting it back
{
//get a stream from the string
var sr = new System.IO.StringReader(pubKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
pubKey = (RSAParameters)xs.Deserialize(sr);
}
//conversion for the private key is no black magic either ... omitted
//we have a public key ... let's get a new csp and load that key
csp = new RSACryptoServiceProvider();
csp.ImportParameters(pubKey);
//we need some data to encrypt
var plainTextData = "foobar";
//for encryption, always handle bytes...
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(plainTextData);
//apply pkcs#1.5 padding and encrypt our data
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
//we might want a string representation of our cypher text... base64 will do
var cypherText = Convert.ToBase64String(bytesCypherText);
/*
* some transmission / storage / retrieval
*
* and we want to decrypt our cypherText
*/
//first, get our bytes back from the base64 string ...
bytesCypherText = Convert.FromBase64String(cypherText);
//we want to decrypt, therefore we need a csp and load our private key
csp = new RSACryptoServiceProvider();
csp.ImportParameters(privKey);
//decrypt and strip pkcs#1.5 padding
bytesPlainTextData = csp.Decrypt(bytesCypherText, false);
//get our original plainText back...
plainTextData = System.Text.Encoding.Unicode.GetString(bytesPlainTextData);
}
}
}
as a side note: the calls to Encrypt() and Decrypt() have a bool parameter that switches between OAEP and PKCS#1.5 padding ... you might want to choose OAEP if it's available in your situation
public static string Encryption(string strText)
{
var publicKey = "<RSAKeyValue><Modulus>21wEnTU+mcD2w0Lfo1Gv4rtcSWsQJQTNa6gio05AOkV/Er9w3Y13Ddo5wGtjJ19402S71HUeN0vbKILLJdRSES5MHSdJPSVrOqdrll/vLXxDxWs/U0UT1c8u6k/Ogx9hTtZxYwoeYqdhDblof3E75d9n2F0Zvf6iTb4cI7j6fMs=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
var testData = Encoding.UTF8.GetBytes(strText);
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
// client encrypting data with public key issued by server
rsa.FromXmlString(publicKey.ToString());
var encryptedData = rsa.Encrypt(testData, true);
var base64Encrypted = Convert.ToBase64String(encryptedData);
return base64Encrypted;
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
}
public static string Decryption(string strText)
{
var privateKey = "<RSAKeyValue><Modulus>21wEnTU+mcD2w0Lfo1Gv4rtcSWsQJQTNa6gio05AOkV/Er9w3Y13Ddo5wGtjJ19402S71HUeN0vbKILLJdRSES5MHSdJPSVrOqdrll/vLXxDxWs/U0UT1c8u6k/Ogx9hTtZxYwoeYqdhDblof3E75d9n2F0Zvf6iTb4cI7j6fMs=</Modulus><Exponent>AQAB</Exponent><P>/aULPE6jd5IkwtWXmReyMUhmI/nfwfkQSyl7tsg2PKdpcxk4mpPZUdEQhHQLvE84w2DhTyYkPHCtq/mMKE3MHw==</P><Q>3WV46X9Arg2l9cxb67KVlNVXyCqc/w+LWt/tbhLJvV2xCF/0rWKPsBJ9MC6cquaqNPxWWEav8RAVbmmGrJt51Q==</Q><DP>8TuZFgBMpBoQcGUoS2goB4st6aVq1FcG0hVgHhUI0GMAfYFNPmbDV3cY2IBt8Oj/uYJYhyhlaj5YTqmGTYbATQ==</DP><DQ>FIoVbZQgrAUYIHWVEYi/187zFd7eMct/Yi7kGBImJStMATrluDAspGkStCWe4zwDDmdam1XzfKnBUzz3AYxrAQ==</DQ><InverseQ>QPU3Tmt8nznSgYZ+5jUo9E0SfjiTu435ihANiHqqjasaUNvOHKumqzuBZ8NRtkUhS6dsOEb8A2ODvy7KswUxyA==</InverseQ><D>cgoRoAUpSVfHMdYXW9nA3dfX75dIamZnwPtFHq80ttagbIe4ToYYCcyUz5NElhiNQSESgS5uCgNWqWXt5PnPu4XmCXx6utco1UVH8HGLahzbAnSy6Cj3iUIQ7Gj+9gQ7PkC434HTtHazmxVgIR5l56ZjoQ8yGNCPZnsdYEmhJWk=</D></RSAKeyValue>";
var testData = Encoding.UTF8.GetBytes(strText);
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
var base64Encrypted = strText;
// server decrypting data with private key
rsa.FromXmlString(privateKey);
var resultBytes = Convert.FromBase64String(base64Encrypted);
var decryptedBytes = rsa.Decrypt(resultBytes, true);
var decryptedData = Encoding.UTF8.GetString(decryptedBytes);
return decryptedData.ToString();
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
}
Honestly, I have difficulty implementing it because there's barely any tutorials I've searched that displays writing the keys into the files. The accepted answer was "fine". But for me I had to improve it so that both keys gets saved into two separate files. I've written a helper class so y'all just gotta copy and paste it. Hope this helps lol.
using Microsoft.Win32;
using System;
using System.IO;
using System.Security.Cryptography;
namespace RsaCryptoExample
{
class RSAFileHelper
{
readonly string pubKeyPath = "public.key";//change as needed
readonly string priKeyPath = "private.key";//change as needed
public void MakeKey()
{
//lets take a new CSP with a new 2048 bit rsa key pair
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(2048);
//how to get the private key
RSAParameters privKey = csp.ExportParameters(true);
//and the public key ...
RSAParameters pubKey = csp.ExportParameters(false);
//converting the public key into a string representation
string pubKeyString;
{
//we need some buffer
var sw = new StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, pubKey);
//get the string from the stream
pubKeyString = sw.ToString();
File.WriteAllText(pubKeyPath, pubKeyString);
}
string privKeyString;
{
//we need some buffer
var sw = new StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, privKey);
//get the string from the stream
privKeyString = sw.ToString();
File.WriteAllText(priKeyPath, privKeyString);
}
}
public void EncryptFile(string filePath)
{
//converting the public key into a string representation
string pubKeyString;
{
using (StreamReader reader = new StreamReader(pubKeyPath)){pubKeyString = reader.ReadToEnd();}
}
//get a stream from the string
var sr = new StringReader(pubKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
csp.ImportParameters((RSAParameters)xs.Deserialize(sr));
byte[] bytesPlainTextData = File.ReadAllBytes(filePath);
//apply pkcs#1.5 padding and encrypt our data
var bytesCipherText = csp.Encrypt(bytesPlainTextData, false);
//we might want a string representation of our cypher text... base64 will do
string encryptedText = Convert.ToBase64String(bytesCipherText);
File.WriteAllText(filePath,encryptedText);
}
public void DecryptFile(string filePath)
{
//we want to decrypt, therefore we need a csp and load our private key
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
string privKeyString;
{
privKeyString = File.ReadAllText(priKeyPath);
//get a stream from the string
var sr = new StringReader(privKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
RSAParameters privKey = (RSAParameters)xs.Deserialize(sr);
csp.ImportParameters(privKey);
}
string encryptedText;
using (StreamReader reader = new StreamReader(filePath)) { encryptedText = reader.ReadToEnd(); }
byte[] bytesCipherText = Convert.FromBase64String(encryptedText);
//decrypt and strip pkcs#1.5 padding
byte[] bytesPlainTextData = csp.Decrypt(bytesCipherText, false);
//get our original plainText back...
File.WriteAllBytes(filePath, bytesPlainTextData);
}
}
}
I'll share my very simple code for sample purpose. Hope it will help someone like me searching for quick code reference.
My goal was to receive rsa signature from backend, then validate against input string using public key and store locally for future periodic verifications.
Here is main part used for signature verification:
...
var signature = Get(url); // base64_encoded signature received from server
var inputtext= "inputtext"; // this is main text signature was created for
bool result = VerifySignature(inputtext, signature);
...
private bool VerifySignature(string input, string signature)
{
var result = false;
using (var cps=new RSACryptoServiceProvider())
{
// converting input and signature to Bytes Arrays to pass to VerifyData rsa method to verify inputtext was signed using privatekey corresponding to public key we have below
byte[] inputtextBytes = Encoding.UTF8.GetBytes(input);
byte[] signatureBytes = Convert.FromBase64String(signature);
cps.FromXmlString("<RSAKeyValue><Modulus>....</Modulus><Exponent>....</Exponent></RSAKeyValue>"); // xml formatted publickey
result = cps.VerifyData(inputtextBytes , new SHA1CryptoServiceProvider(), signatureBytes );
}
return result;
}
for big data
public class RsaService : System.IDisposable
{
public delegate int TransformBlockCall(System.ReadOnlySpan<byte> data, System.Span<byte> destination);
private readonly RSA _encoder;
private readonly RSAEncryptionPadding _padding;
private readonly TransformBlockCall _encryptBlockCall;
private readonly TransformBlockCall _decryptBlockCall;
private int _encrypt_InputBlockSize;
private int _encrypt_OutputBlockSize;
private int _decrypt_InputBlockSize;
private int _decrypt_OutputBlockSize;
public RsaService(RSA encoder) {
if(encoder == null)
throw new System.ArgumentNullException(nameof(encoder));
_encoder = encoder;
_padding = RSAEncryptionPadding.Pkcs1;
_encryptBlockCall = new TransformBlockCall(EncryptBlock);
_decryptBlockCall = new TransformBlockCall(DecryptBlock);
OnEndSetParameters();
}
private void OnEndSetParameters() {
_encrypt_InputBlockSize = GetSizeOutputEncryptOfKeySize(_encoder.KeySize);
_encrypt_OutputBlockSize = _encoder.KeySize / 8;
_decrypt_InputBlockSize = _encrypt_OutputBlockSize;
_decrypt_OutputBlockSize = _encrypt_OutputBlockSize;
}
public void ImportParameters(RSAParameters parameters) {
_encoder.ImportParameters(parameters);
OnEndSetParameters();
}
public byte[] Encrypt(byte[] data) {
if(data == null) throw new System.ArgumentNullException(nameof(data));
if(data.Length == 0) return data;
int outputLength = GetEncryptOutputMaxByteCount(data.Length);
byte[] outputData = new byte[outputLength];
Encrypt(data, outputData);
return outputData;
}
public byte[] Decrypt(byte[] data) {
if(data == null) throw new System.ArgumentNullException(nameof(data));
if(data.Length == 0) return data;
int maxOutputLength = GetDecryptOutputMaxByteCount(data.Length);
byte[] outputData = new byte[maxOutputLength];
int actual_OutputLength = Decrypt(data, outputData);
if(maxOutputLength > actual_OutputLength)
System.Array.Resize(ref outputData, actual_OutputLength);
return outputData;
}
public int Encrypt(System.ReadOnlySpan<byte> data, System.Span<byte> destination) {
#if DEBUG
int inputBlockSize = _encrypt_InputBlockSize;
int outputBlockSize = _encoder.KeySize / 8;
int blockCount = (data.Length / inputBlockSize);
if(data.Length % inputBlockSize != 0)
blockCount++;
System.Diagnostics.Debug.Assert((blockCount * outputBlockSize) <= destination.Length);
#endif
if(data.Length > _encrypt_InputBlockSize)
return TransformFinal(_encryptBlockCall, data, destination, _encrypt_InputBlockSize);
else
return _encryptBlockCall(data, destination);
}
public int Decrypt(System.ReadOnlySpan<byte> data, System.Span<byte> destination) {
if(data.Length > _decrypt_InputBlockSize)
return TransformFinal(_decryptBlockCall, data, destination, _decrypt_InputBlockSize);
else
return _decryptBlockCall(data, destination);
}
private int EncryptBlock(System.ReadOnlySpan<byte> data, System.Span<byte> destination) => _encoder.Encrypt(data, destination, _padding);
private int DecryptBlock(System.ReadOnlySpan<byte> data, System.Span<byte> destination) => _encoder.Decrypt(data, destination, _padding);
public int GetEncryptOutputMaxByteCount(int inputCount) => GetBlockCount(inputCount, _encrypt_InputBlockSize) * _encrypt_OutputBlockSize;
public int GetDecryptOutputMaxByteCount(int inputCount) => GetBlockCount(inputCount, _decrypt_InputBlockSize) * _decrypt_OutputBlockSize;
public void Dispose() {
_encoder.Dispose();
System.GC.SuppressFinalize(this);
}
#region Methods_Helper
public static RsaService Create(RSAParameters parameters) => new RsaService(RSA.Create(parameters));
public static RsaService Create() => new RsaService(RSA.Create());
// [keySize] ÷ 8 - [11 bytes for padding] = Result
// Exsimple: [2048 key size] ÷ 8 - [11 bytes for padding] = 245
public static int GetSizeOutputEncryptOfKeySize(int keySize) => (keySize / 8) - 11;
private static int GetBlockCount(int dataLength,int inputBlockSize) {
int blockCount = (dataLength / inputBlockSize);
if(dataLength % inputBlockSize != 0)
blockCount++;
return blockCount;
}
public static int TransformFinal(TransformBlockCall transformBlockCall, System.ReadOnlySpan<byte> data, System.Span<byte> destination, int inputBlockSize) {
int blockCount = GetBlockCount(data.Length, inputBlockSize);
int data_writtenCount = 0;
int destination_writtenCount = 0;
while(blockCount-- > 0) {
if(blockCount == 0) {
inputBlockSize = data.Length - data_writtenCount;
if(inputBlockSize == 0) break;
}
destination_writtenCount += transformBlockCall(data: data.Slice(data_writtenCount, inputBlockSize)
, destination: destination.Slice(destination_writtenCount));
data_writtenCount += inputBlockSize;
}
return destination_writtenCount;
}
public static (RSAParameters keyPublic, RSAParameters keyPrivate) GenerateKeyPair(int keySize = 2048) {
RSAParameters keyPriv;
RSAParameters keyPub;
using(var rsa = RSA.Create(keySize)) {
keyPriv = rsa.ExportParameters(true);
keyPub = rsa.ExportParameters(false);
}
return (keyPub, keyPriv);
}
#endregion Methods_Helper
}
public static class Program
{
static void Main() {
var (keyPublic, keyPrivate) = RsaService.GenerateKeyPair();
var encryptor = RsaService.Create(keyPublic);
var decryptor = RsaService.Create(keyPrivate);
string originalText = "";
for(int i = 0; i < 1000; i++) {
originalText += "ABC123456789";
}
byte[] inputData = Encoding.UTF8.GetBytes(originalText); // data random for test
System.Console.WriteLine("inputData.Length: {0}", inputData.Length);
var encryptedData = encryptor.Encrypt(inputData);
System.Console.WriteLine("encryptedData.Length: {0}", encryptedData.Length);
byte[] decryptedData = decryptor.Decrypt(encryptedData);
string decryptedText = Encoding.UTF8.GetString(decryptedData);
System.Console.WriteLine("status: {0}", decryptedText == originalText);
}
}

Categories

Resources