As a part of my project I have to encrypt some text with RSA and I have got a public key from another company. The public key looks like this:
var publicKey="MIGfMA0GCSq2GSIb3DQEBAQUAA4GNADCBiQKBgQCgFGVfrY4jQSoZQWWygZ83roKXWD4YeT2x2p41dGkPixe73rT2IW04glatgN2vgoZsoHuOPqah5and6kAmK2ujmCHu6D1auJhE2tXP+yLkpSiYMQucDKmCsWXlC5K7OSL77TXXcfvTvyZcjObEz6LIBRzs6+FqpFbUO9SJEfh6wIDAQAB"
The problem is that I don't know what is its format and how to deserialize it to RSAParameters. Other examples on the Internet have used XML serialization. The key is created by Java.
Then I also want to know how to deserialize its related private key which I don't have access to any sample of it right now.
Update :
Here is part of my code :
var pk = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiiTx4F35eWP10AFMAo8MLhCKq2ryKFG9PKKWeMLQuwMSdiQq347BkMYA+Q+YscScf7weUSTk9BHVNNfTchDwzjQrIoz6TZGggqD+ufin1Ccy0Sp6QeBMnIB89JsdzQGpVcsoTxk53grW0nYY8D+rlFvBwFicKe/tmVPVMYsEyFwIDAQAB";
...
public static RSACryptoServiceProvider ImportPublicKey(string pem)
{
//var newPem = "-----BEGIN PUBLIC KEY-----\n" + pem + "-----END PUBLIC KEY-----";
Org.BouncyCastle.OpenSsl.PemReader pr = new Org.BouncyCastle.OpenSsl.PemReader(new StringReader(Pem));
Org.BouncyCastle.Crypto.AsymmetricKeyParameter publicKey = (Org.BouncyCastle.Crypto.AsymmetricKeyParameter)pr.ReadObject();
RSAParameters rsaParams = Org.BouncyCastle.Security.DotNetUtilities.ToRSAParameters((Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)publicKey);
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();// cspParams);
csp.ImportParameters(rsaParams);
return csp;
}
The posted key is a PEM encoded public key in X.509 (SPKI) format, but without header (-----BEGIN PUBLIC KEY-----) and footer (-----END PUBLIC KEY-----). This can be easily verified with an ASN.1 parser, e.g. here.
The import of such a key depends on the .NET version. .NET Core offers from v3.0 on methods that directly support the import of PKCS#1, PKCS#8 and X.509 keys, e.g. RSA.ImportSubjectPublicKeyInfo for the latter. This option is not available for .NET Framework, but BouncyCastle offers a similarly comfortable solution.
Here (see ImportPublicKey method) is an example that imports a PEM encoded public key in X.509 (SPKI) format using BouncyCastle. However, the PemReader used there expects the complete PEM data, including header and footer, both separated from the body by line breaks. Therefore, when using the public keys posted here, header and footer must be added accordingly, e.g:
using System.IO;
using System.Security.Cryptography;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
...
// from: https://gist.github.com/valep27/4a720c25b35fff83fbf872516f847863
public static RSACryptoServiceProvider ImportPublicKey(string pemBody)
{
var pem = "-----BEGIN PUBLIC KEY-----\n" + pemBody + "\n-----END PUBLIC KEY-----"; // Add header and footer
PemReader pr = new PemReader(new StringReader(pem));
AsymmetricKeyParameter publicKey = (AsymmetricKeyParameter)pr.ReadObject();
RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaKeyParameters)publicKey);
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();// cspParams);
csp.ImportParameters(rsaParams);
return csp;
}
Related
I'm training to asymmetric encryption with RSA. I created a key pair with ssh-keygen, and I managed to encrypt some data with my public key.
But when I try to decrypt this data with my private key, this exception is raised :
System.Security.Cryptography.CryptographicException : 'ASN1 corrupted data.'
Here is my PEM file containing my private key :
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,E79376C1ECFD82F05A871D9245BFC958
iEL9aNdWIC3TckveRH2ADdHrnCAQeyg0GUFx0obx1sHOCDdiCIb2u46vFUQ8QP6H
vHHgA9Kf4lY8Jq6Qkv/Iyhh9WcWTR2nNjbN7Ndlb343MyjeNdlXdVrHsfR8Q98ul
06FiKZdnS640PzxAUvibbmkLVus8g3V14qZqeDTqN1rbOCAk2Kxfy5V4kd6M7wCm
fqABkYpp+2EYf4Z4YcJbLDXEEIg7HD/AI1gPpE5nRQoSib/9bm87j98VnG5dOYAJ
38ZMTvJjIImQveOUeSNyR/re71V+YUy0N/zvqMrlp4pDFsDb6infZga0jPFzGXGy
5S3XYXSs9iPReFHQnhWr/L3dRx9TpfZJcl4BJ6D8j9wxrWRcharGNNgCK/kV9FJw
BpwFu01jNESDHV3dyWTcOAzQit4pDkr0A9EK4N1vfWaLLO8vqyGtqlvtU5sD2rYQ
JvrMEsUsAYXJcBDUX2cksNEen+7s338cBGg4NdE+xAUeKv5EysYIKgojPJi6WQ39
FAgkr1TfWaffO/TgfL/DwC1wyHXleNyDQ87unyxRIRu/wWnqJaQQG8Z0BilIbDp8
KrKfkHW9CWaPCbldOzHJ5UDZmA5+AvfoaATRw/vW1Wg0GYkuNqqHzV7tNFKcnUG1
DmIaSI+Y55cngqeOStFfgRTehbXK84w3PzR3lnpuxG4rtOjDV8RfZSozaSValqju
ZWRYEbKn7Za2XZWJT4kkDa5O4nJUMbihBOUL+FWc6dmDIaZY/nUKJAm2pxmd0R1s
9PcXhqLEnBTvGh1CrOdhiqkHQ5A5OtIp/FrPhUltjsy129NC5/dPZaN9v4TgNYQu
zNd8vSlVXuimB+2OoXu3fNE75ywxmrs4H8M4y3u87GQWFdYwQFFnv2fyCzV8iqvy
ybQR599v5qL2IKvHdw68q9PDmasd4jSTAoFP/g6QQKMCaQuMUbrtlHzvPvNnCgk1
AChbFeuLK57c2rwVwTx0YEATcKz27/V5af0E2x6sLDoqQv5SBkREuuWyA6DsSO/S
vX1WR/hZWk2PVi24N/AG8T/sIfyBeTPw7Yx3RuT5MWLdR6haSEKkGGrGuxr1HnoF
lt3JruZczavGpAn5Q8DSVKb78Q8kqI/gdLYNIuq5Yy7Mz1ldocN0N2CarUGWgU7e
+z0TM2CWkTBE7Q0CU4Na5QusvaLYDgH4LW4WY9BNN86C4uKQFjJHz6gZoI3zx8/L
RxN2bGyd0H83k4xuQXml2RnnPPB6L5JwJxxme5ecWpMdp5c6xyXX1ZPKkkGuRbFs
OxeQqNNfPEExqtC2U/Jn5B1HYJqCYCeKlUNdqUoZv5vT8x9UDoE5vKtP3DtTckeB
+6n7S2viNWzV2qid8moh9DfWGMlF4i1y91pdcNJx+M01OfLOB1EPlD0MoTvkfU6s
x0VQh5t4wCbcJ7kcIrp2siPbBg4RPV8MNKtaBhTvFf+nH1TAEsUMjdi7FrnfBn3b
4o4BqC+ibQHC/+SkGAxRakdJjM5XcXO1BZp4zLYSBQyXGu7kp8ohOvHx65vtwvls
XCdbtnJs/iAORxAgLnuVPzLUfTd6bLlszOsyIvC8+j587GX5YFW+h4s+bicZMwCm
-----END RSA PRIVATE KEY-----
And here is the code sample using this private key :
static string RSA_Decrypt(byte[] value)
{
byte[] deciphered;
using (var reader = File.OpenText(#"C:\Users\???\.ssh\id_rsa"))
{
// Extracting the payload
string privateKeyFile = reader.ReadToEnd();
var exp = privateKeyFile.Split("\n\n");
var privateKey = exp[1].Split("\n-----")[0];
// using the payload to decrypt my data
using(var rsa = RSA.Create())
{
rsa.ImportRSAPrivateKey(Convert.FromBase64String(privateKey), out _); //CryptographicException
deciphered = rsa.Decrypt(value, RSAEncryptionPadding.Pkcs1);
}
}
return Encoding.Default.GetString(deciphered);
}
What am I doing wrong?
The posted private key is a PEM encoded PKCS#1 key that is encrypted.
RSA.ImportRSAPrivateKey() can only import unencrypted keys of this format that are furthermore DER encoded. The DER encoding results from the PEM encoding by removing the header and footer and Base64 decoding the rest.
As far as I know, an encrypted PKCS#1 key cannot be imported with .NET Core 3.1 on-board means. But an import is possible with BouncyCastle and its Org.BouncyCastle.OpenSsl.PemReader class, see e.g. here.
Unlike the PKCS#1 format, a DER encoded private key in PKCS#8 format can be imported with .NET Core 3.1 out of the box (RSA.ImportPkcs8PrivateKey()), even if it is encrypted (RSA.ImportEncryptedPkcs8PrivateKey()).
Keys of this format can be generated e.g. with openssl genpkey. With OpenSSL it is also possible to convert between the formats.
Thanks Topaco, that's exactly what I needed! I used BouncyCastle to decrypt my private key, and now it's working perfectly! I don't know why RSA class does not have any method to do it...
So here is my code now :
static string RSA_Decrypt(byte[] value)
{
string deciphered;
using (var reader = File.OpenText(#"C:\Users\???\.ssh\id_rsa"))
{
string privateKeyFile = reader.ReadToEnd();
var keyReader = new StringReader(privateKeyFile);
var decryptEngine = new Pkcs1Encoding(new RsaEngine());
object pemReader = new PemReader(keyReader, new PasswordFinder("azerty")).ReadObject();
var keyPair = (AsymmetricCipherKeyPair)pemReader;
decryptEngine.Init(false, keyPair.Private);
deciphered = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(value, 0, value.Length));
}
return deciphered;
}
PS : Yeah, my private key password is "azerty" ^^ I wasn't inspired when I created my key pair ^^
I am trying to decrypt some text that is encrypted with RSA, I have the public key to do this
`
-----BEGIN RSA PUBLIC KEY-----
MIGWAoGBAMqfGO9sPz+kxaRh/qVKsZQGul7NdG1gonSS3KPXTjtcHTFfexA4MkGA
mwKeu9XeTRFgMMxX99WmyaFvNzuxSlCFI/foCkx0TZCFZjpKFHLXryxWrkG1Bl9+
+gKTvTJ4rWk1RvnxYhm3n/Rxo2NoJM/822Oo7YBZ5rmk8NuJU4HLAhAYcJLaZFTO
sYU+aRX4RmoF
-----END RSA PUBLIC KEY-----
`
How can I load this into RSACryptoServiceProvider because this can only load from XMLString and I do not know how to convert this to Xml format
The key size is 128
I tried to initialize it using the following code
public byte[] Decrypt128(byte[] input)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(128);
rsa.ImportCspBlob(Encoding.ASCII.GetBytes(_longKey));
return rsa.Decrypt(input, true);
}
_longKey is the content between BEGIN and END and also including the BEGIN and END, bot Bad Version of provider.
This is not a duplicate question of How do you convert Byte Array to Hexadecimal String, and vice versa?
I already know how to convert byte to hex and hex to byte, but that in any way does not help me initializing RSACryptoServiceProvider maybe give me example how that would help but at this point it doesn't
You could use BouncyCastle which has a PemReader allowing you to extract the modulus and exponent for the key:
using (var reader = File.OpenText("mykey.key"))
{
var pem = new PemReader(reader);
var o = (RsaKeyParameters)pem.ReadObject();
using (var rsa = new RSACryptoServiceProvider())
{
var parameters = new RSAParameters();
parameters.Modulus = o.Modulus.ToByteArray();
parameters.Exponent = o.Exponent.ToByteArray();
rsa.ImportParameters(parameters);
// Do what you need to do with the RSACryptoServiceProvider instance
}
}
If you don't want to have a dependency on BouncyCastle in your project, once loaded the public key into the RSACryptoServiceProvider using this method you could export it to XML for future use:
string xml = rsa.ToXmlString(false);
File.WriteAllText("mykey.xml", xml);
Is it possible to generate an RSA key pair, export that into ASN1 format compatible with DKIM's PEM-like format, using only C#?
I'd like to reduce my dependencies on 3rd parties, but here are some that I have found
Bouncy Castle
https://stackoverflow.com/a/251757
Cryptography Application Block
http://msdn.microsoft.com/en-us/library/dd203099.aspx
https://stackoverflow.com/a/243787
Win32 PFXImportCertStore
http://msdn.microsoft.com/en-us/library/aa387314(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/aa387313(v=vs.85)
Import PEM
This code only imports PEM data, but is different from OpenSSL in that it fixes an issue with .NET 4.0 and leading zeros in the key http://www.codeproject.com/Articles/162194/Certificates-to-DB-and-Back
Microsoft's CLR Security enhancements
http://clrsecurity.codeplex.com/
Microsoft CNG
http://msdn.microsoft.com/en-us/magazine/cc163389.aspx
Here is code for the Microsoft CNG provider with the .NET dll on codeplex (above)... however I don't know how to export and import both the public and private keys in DKIM compatible ASN1 format.
byte[] pkcs8PrivateKey = null;
byte[] signedData = null;
CngKey key = CngKey.Create(CngAlgorithm2.Rsa);
byte[] exportedPrivateBytes = key.Export(CngKeyBlobFormat.GenericPrivateBlob);
string exportedPrivateString= Encoding.UTF8.GetString(exportedPrivateBytes);
pkcs8PrivateKey = Encoding.UTF8.GetBytes(exportedPrivateString);
using (CngKey signingKey = CngKey.Import(pkcs8PrivateKey, CngKeyBlobFormat.Pkcs8PrivateBlob))
{
using (RSACng rsa = new RSACng(signingKey))
{
rsa.SignatureHashAlgorithm = CngAlgorithm.Sha1;
signedData = rsa.SignData(dataToSign);
}
}
Question
Are there any direct examples of using Microsoft's libraries (Win32, PFX, or CLR on Codeplex) that illustrate how to create a key pair and export / import those values in PEM format?
So you just need a pkcs8 of the key then.
CngKeyCreationParameters ckcParams = new CngKeyCreationParameters()
{
ExportPolicy = CngExportPolicies.AllowPlaintextExport,
KeyCreationOptions = CngKeyCreationOptions.None,
KeyUsage = CngKeyUsages.AllUsages,
};
ckcParams.Parameters.Add(new CngProperty("Length", BitConverter.GetBytes(2048), CngPropertyOptions.None));
myCngKey = CngKey.Create(CngAlgorithm.Rsa, null, ckcParams);
byte[] privatePlainTextBlob = myCngKey.Export(CngKeyBlobFormat.Pkcs8PrivateBlob);
Console.WriteLine(Convert.ToBase64String(privatePlainTextBlob));
}
Now your key pair is contained in the PKCS#8 ASN.1 encoded string.
I am trying to use C# to read in a .pem file that contains only a RSA public key. I do not have access to the private key information, nor does my application require it. The file myprivatekey.pem file begins with
-----BEGIN PUBLIC KEY-----
and ends with
-----END PUBLIC KEY-----.
My current code is as follows:
Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair keyPair;
using (var reader = File.OpenText(#"c:\keys\myprivatekey.pem"))
keyPair = (Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair)new Org.BouncyCastle.OpenSsl.PemReader(reader).ReadObject();
However the code throws an InvalidCastException with the message
Unable to cast object of type
'Org.BouncyCastle.Crypto.Parameters.DsaPublicKeyParameters' to type
'Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair'.
How can I use Bouncy Castle's PemReader to read only a public key, when no private key information is available?
The following code will read a public key from a given filename. The exception handling should be changed for any production code. This method returns an AsymetricKeyParameter:
public Org.BouncyCastle.Crypto.AsymmetricKeyParameter ReadAsymmetricKeyParameter(string pemFilename)
{
var fileStream = System.IO.File.OpenText(pemFilename);
var pemReader = new Org.BouncyCastle.OpenSsl.PemReader(fileStream);
var KeyParameter = (Org.BouncyCastle.Crypto.AsymmetricKeyParameter)pemReader.ReadObject();
return KeyParameter;
}
Here's a possible solution that reads both public and private PEM files into RSACryptoServiceProvider:
public class PemReaderB
{
public static RSACryptoServiceProvider GetRSAProviderFromPem(String pemstr)
{
CspParameters cspParameters = new CspParameters();
cspParameters.KeyContainerName = "MyKeyContainer";
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParameters);
Func<RSACryptoServiceProvider, RsaKeyParameters, RSACryptoServiceProvider> MakePublicRCSP = (RSACryptoServiceProvider rcsp, RsaKeyParameters rkp) =>
{
RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(rkp);
rcsp.ImportParameters(rsaParameters);
return rsaKey;
};
Func<RSACryptoServiceProvider, RsaPrivateCrtKeyParameters, RSACryptoServiceProvider> MakePrivateRCSP = (RSACryptoServiceProvider rcsp, RsaPrivateCrtKeyParameters rkp) =>
{
RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(rkp);
rcsp.ImportParameters(rsaParameters);
return rsaKey;
};
PemReader reader = new PemReader(new StringReader(pemstr));
object kp = reader.ReadObject();
// If object has Private/Public property, we have a Private PEM
return (kp.GetType().GetProperty("Private") != null) ? MakePrivateRCSP(rsaKey, (RsaPrivateCrtKeyParameters)(((AsymmetricCipherKeyPair)kp).Private)) : MakePublicRCSP(rsaKey, (RsaKeyParameters)kp);
}
public static RSACryptoServiceProvider GetRSAProviderFromPemFile(String pemfile)
{
return GetRSAProviderFromPem(File.ReadAllText(pemfile).Trim());
}
}
Hope this helps someone.
In answer to c0d3Junk13, I had the same issue for a PEM private key and it took me all afternoon to find the solution using the C# BouncyCastle Version 1.7 and Visual Studio 2013 Desktop Express. Don't forget to add the project reference to BouncyCastle.Crypto.dll
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Collections;
using System.IO;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Utilities.Collections;
using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.OpenSsl;
/*
For an Active Directory generated pem, strip out everything in pem file before line:
"-----BEGIN PRIVATE KEY-----" and re-save.
*/
string privateKeyFileName = #"C:\CertificateTest\CS\bccrypto-net-1.7-bin\private_key3.pem";
TextReader reader = File.OpenText(privateKeyFileName);
Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters key;
using (reader = File.OpenText(privateKeyFileName))
{
key = (Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters)new PemReader(reader).ReadObject();
}
cipher.Init(false, key);
//Decrypting the input bytes
byte[] decipheredBytes = cipher.ProcessBlock(cipheredBytes, 0, cipheredBytes.Length);
MessageBox.Show(Encoding.UTF8.GetString(decipheredBytes));
EDIT:
It looks like this depends on what type of key file you are using. For ssh-keygen keys, the private key appears to have a type of AsymmetricCipherKeyPair, but for openssl keys, the private key has a type of RsaPrivateCrtKeyParameters.
Bryan Jyh Herng Chong's answer no longer appears to work for me (at least with Bouncy Castle version v1.8.5). It appears kp.GetType().GetProperty("Private") is no longer set differently for public vs private key PEM objects. It also appears that the object returned using PemReader.ReadObject() is now directly a RsaPrivateCrtKeyParameters object, so there's no longer a need to cast through a AsymmetricCipherKeyPair object first.
I changed that line to this and it worked like a charm:
return (kp.GetType() == typeof(RsaPrivateCrtKeyParameters)) ? MakePrivateRCSP(rsaKey, (RsaPrivateCrtKeyParameters)kp)) : MakePublicRCSP(rsaKey, (RsaKeyParameters)kp);
Instead of:
keyPair = (Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair)new Org.BouncyCastle.OpenSsl.PemReader(reader).ReadObject();
Use:
keyPair = (Org.BouncyCastle.Crypto.AsymmetricKeyParameter)new Org.BouncyCastle.OpenSsl.PemReader(reader).ReadObject();
Since you are only using a public key and you don't actually have a pair of keys (public & private) you can't cast it as 'AsymmetricCipherKeyPair' you should cast it as 'AsymmetricKeyParameter'.
Try the following code:
Using Org.BouncyCastle.Crypto;
string path = HttpContext.Current.Server.MapPath(#"~\key\ABCD.pem");
AsymmetricCipherKeyPair Key;
TextReader tr = new StreamReader(#path);
PemReader pr = new PemReader(tr);
Key = (AsymmetricCipherKeyPair)pr.ReadObject();
pr.Reader.Close();
tr.Close();
AsymmetricKeyParameter keaa = Key.Public;
I am staring at this for quite a while and thanks to the MSDN documentation I cannot really figure out what's going. Basically I am loading a PFX file from the disc into a X509Certificate2 and trying to encrypt a string using the public key and decrypt using the private key.
Why am I puzzled: the encryption/decryption works when I pass the reference to the RSACryptoServiceProvider itself:
byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider);
string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider);
But if the export and pass around the RSAParameter:
byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false));
string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true));
...it throws a "Key not valid for use in specified state." exception while trying to export the private key to RSAParameter. Please note that the cert the PFX is generated from is marked exportable (i.e. I used the pe flag while creating the cert). Any idea what is causing the exception?
static void Main(string[] args)
{
X509Certificate2 x = new X509Certificate2(#"C:\temp\certs\1\test.pfx", "test");
x.FriendlyName = "My test Cert";
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
try
{
store.Add(x);
}
finally
{
store.Close();
}
byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider);
string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider);
byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false));
string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true));
}
private static byte[] EncryptRSA(string data, RSAParameters rsaParameters)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
byte[] plainData = bytConvertor.GetBytes(data);
RSACryptoServiceProvider publicKey = new RSACryptoServiceProvider();
publicKey.ImportParameters(rsaParameters);
return publicKey.Encrypt(plainData, true);
}
private static string DecryptRSA(byte[] data, RSAParameters rsaParameters)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
RSACryptoServiceProvider privateKey = new RSACryptoServiceProvider();
privateKey.ImportParameters(rsaParameters);
byte[] deData = privateKey.Decrypt(data, true);
return bytConvertor.GetString(deData);
}
private static byte[] EncryptRSA(string data, RSACryptoServiceProvider publicKey)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
byte[] plainData = bytConvertor.GetBytes(data);
return publicKey.Encrypt(plainData, true);
}
private static string DecryptRSA(byte[] data, RSACryptoServiceProvider privateKey)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
byte[] deData = privateKey.Decrypt(data, true);
return bytConvertor.GetString(deData);
}
Just to clarify in the code above the bold part is throwing:
string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider)**.ExportParameters(true)**);
I believe that the issue may be that the key is not marked as exportable. There is another constructor for X509Certificate2 that takes an X509KeyStorageFlags enum. Try replacing the line:
X509Certificate2 x = new X509Certificate2(#"C:\temp\certs\1\test.pfx", "test");
With this:
X509Certificate2 x = new X509Certificate2(#"C:\temp\certs\1\test.pfx", "test", X509KeyStorageFlags.Exportable);
For the issue I encountered a code change was not an option as the same library was installed and working elsewhere.
Iridium's answer lead me to look making the key exportable and I was able to this as part of the MMC Certificate Import Wizard.
Hope this helps someone else. Thanks heaps
I've met some similar issue, and X509KeyStorageFlags.Exportable solved my problem.
I'm not exactly an expert in these things, but I did a quick google, and found this:
http://social.msdn.microsoft.com/Forums/en/clr/thread/4e3ada0a-bcaf-4c67-bdef-a6b15f5bfdce
"if you have more than 245 bytes in your byte array that you pass to your RSACryptoServiceProvider.Encrypt(byte[] rgb, bool fOAEP) method then it will throw an exception."
For others that end up here through Google, but don't use any X509Certificate2, if you call ToXmlString on RSACryptoServiceProvider but you've only loaded a public key, you will get this message as well. The fix is this (note the last line):
var rsaAlg = new RSACryptoServiceProvider();
rsaAlg.ImportParameters(rsaParameters);
var xml = rsaAlg.ToXmlString(!rsaAlg.PublicOnly);
AFAIK this should work and you're likely hitting a bug/some limitations. Here's some questions that may help you figure out where's the issue.
How did you create the PKCS#12 (PFX) file ? I've seen some keys that CryptoAPI does not like (uncommon RSA parameters). Can you use another tool (just to be sure) ?
Can you export the PrivateKey instance to XML, e.g. ToXmlString(true), then load (import) it back this way ?
Old versions of the framework had some issues when importing a key that was a different size than the current instance (default to 1024 bits). What's the size of your RSA public key in your certificate ?
Also note that this is not how you should encrypt data using RSA. The size of the raw encryption is limited wrt the public key being used. Looping over this limit would only give you really bad performance.
The trick is to use a symmetric algorithm (like AES) with a totally random key and then encrypt this key (wrap) using the RSA public key. You can find C# code to do so in my old blog entry on the subject.
Old post, but maybe can help someone.
If you are using a self signed certificate and make the login with a different user, you have to delete the old certificate from storage and then recreate it. I've had the same issue with opc ua software