Read RSA PrivateKey in C# and Bouncy Castle - c#

I have successfully written to public and private key files with OpenSSL format.
Files:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpHCHYgawzNlxVebSKXL7vfc/i
hP+dQgMxlaPEi7/vpQtV2szHjIP34MnUKelXFuIETJjOgjWAjTTJoj38MQUWc3u7
SRXaGVggqQEKH+cRi5+UcEObIfpi+cIyAm9MJqKabfJK2e5X/OS7FgAwPjgtDbZO
ZxamOrWWL8KGB+lH+QIDAQAB
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCpHCHYgawzNlxVebSKXL7vfc/ihP+dQgMxlaPEi7/vpQtV2szH
jIP34MnUKelXFuIETJjOgjWAjTTJoj38MQUWc3u7SRXaGVggqQEKH+cRi5+UcEOb
Ifpi+cIyAm9MJqKabfJK2e5X/OS7FgAwPjgtDbZOZxamOrWWL8KGB+lH+QIDAQAB
AoGBAIXtL6jFWVjdjlZrIl4JgXUtkDt21PD33IuiVKZNft4NOWLu+wp17/WZYn3S
C2fbSXfaKZIycKi0K8Ab6zcUo0+QZKMoaG5GivnqqTPVAuZchkuMUSVgjGvKAC/D
12/b+w+Shs9pvqED1CxfvtePXNwL6ZNuaREFC5hF/YpMVyg5AkEA3BUCZYJ+Ec96
2cwsdY6HocW8Kn+RIqMjkNtyLA19cQV5mpIP7kAiW6drBDlraVANi+5AgK2zQ+ZT
hYzs/JfRKwJBAMS1g5/B7XXnfC6VTRs8AMveZudi5wS/aGpaApybsfx1NTLLsm3l
GmGTkbCr+EPzvJ5zRSIAHAA6N6NdORwzEWsCQHTli+JTD5dyNvScaDkAvbYFi06f
d32IXYnBpcEUYT65A8BAOMn5ssYwBL23qf/ED431vLkcig1Ut6RGGFKKaQUCQEfa
UdkSWm39/5N4f/DZyySs+YO90csfK8HlXRzdlnc0TRlf5K5VyHwqDkatmoMfzh9G
1dLknVXL7jTjQZA2az8CQG0jRSQ599zllylMPPVibW98701Mdhb1u20p1fAOkIrz
+BNEdOPqPVIyqIP830nnFsJJgTG2eKB59ym+ypffRmA=
-----END RSA PRIVATE KEY-----
And public key contains just the public key portion of course.
After encrypting my message using the public key. I want to read the private key file
and decrypt it but it's not working. I'm getting exceptions trying to read the private key saying can't cast object to asymmetriccipherkey.
Here is my code:
public static 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;
}
static void Encrypt2(string publicKeyFileName, string inputMessage, string encryptedFileName)
{
UTF8Encoding utf8enc = new UTF8Encoding();
FileStream encryptedFile = null;
try
{
// Converting the string message to byte array
byte[] inputBytes = utf8enc.GetBytes(inputMessage);
// RSAKeyPairGenerator generates the RSA Key pair based on the random number and strength of key required
/*RsaKeyPairGenerator rsaKeyPairGnr = new RsaKeyPairGenerator();
rsaKeyPairGnr.Init(new Org.BouncyCastle.Crypto.KeyGenerationParameters(new SecureRandom(), 512));
Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair keyPair = rsaKeyPairGnr.GenerateKeyPair();
*/
AsymmetricKeyParameter publicKey = ReadAsymmetricKeyParameter(publicKeyFileName);
// Creating the RSA algorithm object
IAsymmetricBlockCipher cipher = new RsaEngine();
// Initializing the RSA object for Encryption with RSA public key. Remember, for encryption, public key is needed
cipher.Init(true, publicKey);
//Encrypting the input bytes
byte[] cipheredBytes = cipher.ProcessBlock(inputBytes, 0, inputMessage.Length);
//Write the encrypted message to file
// Write encrypted text to file
encryptedFile = File.Create(encryptedFileName);
encryptedFile.Write(cipheredBytes, 0, cipheredBytes.Length);
}
catch (Exception ex)
{
// Any errors? Show them
Console.WriteLine("Exception encrypting file! More info:");
Console.WriteLine(ex.Message);
}
finally
{
// Do some clean up if needed
if (encryptedFile != null)
{
encryptedFile.Close();
}
}
}
Here is the decrypt function. 2nd one is without using Bouncy Castle, however, I'd rather use Bouncy Castle since later I'll be also encrypting and decrypting in Java.
static void Decrypt2(string privateKeyFileName, string encryptedFileName, string plainTextFileName)
{
UTF8Encoding utf8enc = new UTF8Encoding();
FileStream encryptedFile = null;
StreamWriter plainFile = null;
byte[] encryptedBytes = null;
string plainText = "";
try
{
// Converting the string message to byte array
//byte[] inputBytes = utf8enc.GetBytes(inputMessage);
// RSAKeyPairGenerator generates the RSA Key pair based on the random number and strength of key required
/*RsaKeyPairGenerator rsaKeyPairGnr = new RsaKeyPairGenerator();
rsaKeyPairGnr.Init(new Org.BouncyCastle.Crypto.KeyGenerationParameters(new SecureRandom(), 512));
Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair keyPair = rsaKeyPairGnr.GenerateKeyPair();
*/
StreamReader sr = File.OpenText(privateKeyFileName);
PemReader pr = new PemReader(sr);
PemReader pemReader = new PemReader(new StringReader(privateKeyFileName));
AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
Console.WriteLine(keyPair.ToString());
AsymmetricKeyParameter privatekey = keyPair.Private;
Console.WriteLine(pr.ReadPemObject());
AsymmetricCipherKeyPair KeyPair = (AsymmetricCipherKeyPair)pr.ReadObject();
AsymmetricKeyParameter privateKey = ReadAsymmetricKeyParameter(privateKeyFileName);
// Creating the RSA algorithm object
IAsymmetricBlockCipher cipher = new RsaEngine();
Console.WriteLine("privateKey: " + privateKey.ToString());
// Initializing the RSA object for Decryption with RSA private key. Remember, for decryption, private key is needed
//cipher.Init(false, KeyPair.Private);
//cipher.Init(false, KeyPair.Private);
cipher.Init(false, keyPair.Private);
// Read encrypted text from file
encryptedFile = File.OpenRead(encryptedFileName);
encryptedBytes = new byte[encryptedFile.Length];
encryptedFile.Read(encryptedBytes, 0, (int)encryptedFile.Length);
//Encrypting the input bytes
//byte[] cipheredBytes = cipher.ProcessBlock(inputBytes, 0, inputMessage.Length);
byte[] cipheredBytes = cipher.ProcessBlock(encryptedBytes, 0, encryptedBytes.Length);
//Write the encrypted message to file
// Write encrypted text to file
plainFile = File.CreateText(plainTextFileName);
plainText = Encoding.Unicode.GetString(cipheredBytes);
plainFile.Write(plainText);
}
catch (Exception ex)
{
// Any errors? Show them
Console.WriteLine("Exception encrypting file! More info:");
Console.WriteLine(ex.Message);
}
finally
{
// Do some clean up if needed
if (plainFile != null)
{
plainFile.Close();
}
if (encryptedFile != null)
{
encryptedFile.Close();
}
}
}
// Decrypt a file
static void Decrypt(string privateKeyFileName, string encryptedFileName, string plainFileName)
{
// Variables
CspParameters cspParams = null;
RSACryptoServiceProvider rsaProvider = null;
StreamReader privateKeyFile = null;
FileStream encryptedFile = null;
StreamWriter plainFile = null;
string privateKeyText = "";
string plainText = "";
byte[] encryptedBytes = null;
byte[] plainBytes = null;
try
{
// Select target CSP
cspParams = new CspParameters();
cspParams.ProviderType = 1; // PROV_RSA_FULL
//cspParams.ProviderName; // CSP name
rsaProvider = new RSACryptoServiceProvider(cspParams);
// Read private/public key pair from file
privateKeyFile = File.OpenText(privateKeyFileName);
privateKeyText = privateKeyFile.ReadToEnd();
// Import private/public key pair
rsaProvider.FromXmlString(privateKeyText);
// Read encrypted text from file
encryptedFile = File.OpenRead(encryptedFileName);
encryptedBytes = new byte[encryptedFile.Length];
encryptedFile.Read(encryptedBytes, 0, (int)encryptedFile.Length);
// Decrypt text
plainBytes = rsaProvider.Decrypt(encryptedBytes, false);
// Write decrypted text to file
plainFile = File.CreateText(plainFileName);
plainText = Encoding.Unicode.GetString(plainBytes);
plainFile.Write(plainText);
}
catch (Exception ex)
{
// Any errors? Show them
Console.WriteLine("Exception decrypting file! More info:");
Console.WriteLine(ex.Message);
}
finally
{
// Do some clean up if needed
if (privateKeyFile != null)
{
privateKeyFile.Close();
}
if (encryptedFile != null)
{
encryptedFile.Close();
}
if (plainFile != null)
{
plainFile.Close();
}
}
} // Decrypt

I figured this out. Basically to read a private openssl key using BouncyCastle and C# is like this:
static AsymmetricKeyParameter readPrivateKey(string privateKeyFileName)
{
AsymmetricCipherKeyPair keyPair;
using (var reader = File.OpenText(privateKeyFileName))
keyPair = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
return keyPair.Private;
}
Then this key can be used to decrypt data such as below:
AsymmetricKeyParameter key = readPrivateKey(pemFilename);
RsaEngine e = new RsaEngine();
e.Init(false, key);
byte[] decipheredBytes = e.ProcessBlock(cipheredData, 0, cipheredData.Length);

Related

Decrypt a pdf file using bouncy castle using 3des algorithm

i need to decrypt a pdf file using bouncy castle libreries.
I use c#.
I can encrypt a pdf file using the following code:
public static byte[] CmsEncrypt3DES(string InFilePath, string CertFilePath)
{
byte[] encoded;
try
{
byte[] numArray = File.ReadAllBytes(InFilePath);
X509Certificate x509Certificate =ESCmsEncrypt.LoadCertificate(CertFilePath);
CmsEnvelopedDataGenerator cmsEnvelopedDataGenerator = new CmsEnvelopedDataGenerator();
CmsProcessableByteArray cmsProcessableByteArray = new CmsProcessableByteArray(numArray);
cmsEnvelopedDataGenerator.AddKeyTransRecipient(x509Certificate);
encoded = cmsEnvelopedDataGenerator.Generate(cmsProcessableByteArray, PkcsObjectIdentifiers.DesEde3Cbc.Id).GetEncoded();
}
catch (Exception exception1)
{
Exception exception = exception1;
throw exception;
}
return encoded;
}
I import the certificate using this method:
public static X509Certificate LoadCertificate(string filename)
{
X509Certificate x509Certificate;
try
{
X509CertificateParser x509CertificateParser = new X509CertificateParser();
FileStream fileStream = new FileStream(filename, FileMode.Open);
X509Certificate x509Certificate1 = x509CertificateParser.ReadCertificate(fileStream);
fileStream.Close();
x509Certificate = x509Certificate1;
}
catch (Exception exception1)
{
Exception exception = exception1;
Log.LogError("ESCmsEncrypt.LoadCertificate", exception.Message, exception.ToString());
throw exception;
}
return x509Certificate;
}
This code work well but i' don't know how to decrypt this file using bouncy castle.
I've tried but without results.
Thanks
Valerio M.
EDIT
i've also used this code but it doesn't work:
public static void test()
{
X509Certificate2Collection scollection = new X509Certificate2Collection();
// Output which certificate will be used
Console.WriteLine("Using Certificate:");
string path_certificato = ConfigurationManager.AppSettings["certificate_file"].ToString();
X509Certificate2 cert = new X509Certificate2();
X509Certificate2 x509 = new X509Certificate2(File.ReadAllBytes(path_certificato));
Console.WriteLine("---------------------------------------------------------------------");
Console.WriteLine("1.\tFull DN: {0}", x509.Subject);
Console.WriteLine("\tThumbprint: {0}", x509.Thumbprint);
Console.WriteLine("---------------------------------------------------------------------");
cert = x509;
scollection.Add(cert);
// Wait
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
// Create data for encryption
string message = "THIS IS OUR SECRET MESSAGE";
byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
// Encrypt
Console.WriteLine("Encrypting message...");
//ContentInfo contentInfo = new ContentInfo(data); // will use default ContentInfo Oid, which is "DATA"
// Explicitly use ContentInfo Oid 1.2.840.113549.1.7.1, "DATA", which is the default.
ContentInfo contentInfo = new ContentInfo(new System.Security.Cryptography.Oid("1.2.840.113549.1.7.1"), data);
// If using OID 1.2.840.113549.3.7 (the default one used if empty constructor is used) or 1.2.840.113549.1.9.16.3.6 everything works
// If using OID 2.16.840.1.101.3.4.1.42 (AES CBC) it breaks
AlgorithmIdentifier encryptionAlgorithm = new AlgorithmIdentifier(new System.Security.Cryptography.Oid("1.2.840.113549.3.7"));
EnvelopedCms envelopedCms = new EnvelopedCms(contentInfo); // this will use default encryption algorithm (3DES)
//EnvelopedCms envelopedCms = new EnvelopedCms(contentInfo, encryptionAlgorithm);
Console.WriteLine("Encyption Algorithm:" + envelopedCms.ContentEncryptionAlgorithm.Oid.FriendlyName);
Console.WriteLine("Encyption Algorithm:" + envelopedCms.ContentEncryptionAlgorithm.Oid.Value);
CmsRecipientCollection recipients = new CmsRecipientCollection(SubjectIdentifierType.IssuerAndSerialNumber, scollection);
/*Console.WriteLine("Receipientinfo count: " + encryptionEnvelopedCms.RecipientInfos.Count.ToString());
foreach (var i in encryptionEnvelopedCms.RecipientInfos)
{
Console.Write("RecipientInfo Encryption Oid: " + i.KeyEncryptionAlgorithm.Oid);
}
*/
envelopedCms.Encrypt(recipients);
byte[] encryptedData = envelopedCms.Encode();
Console.WriteLine("Message encrypted!");
EnvelopedCms envelopedCms_new = new EnvelopedCms();
envelopedCms_new.Decode(encryptedData);
envelopedCms_new.Decrypt(scollection);
byte[] decryptedData = envelopedCms_new.ContentInfo.Content;
}
"envelopedCms_new.Decode(encryptedData);"this part doesn't work
System.Security.Cryptography.CryptographicException: 'Impossibile trovare la proprietà o l'oggetto.

C# Signing and verifying signatures with RSA. Encoding issue

My question is pretty similar to the one form 2011, Signing and verifying signatures with RSA C#. Nevertheless, I also get false when I compare the signed data and the original message. Please point on my mistake.
Code:
public static void Main(string[] args)
{
//Generate a public/private key pair.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
//Save the public key information to an RSAParameters structure.
RSAParameters RSAPublicKeyInfo = RSA.ExportParameters(false);
RSAParameters RSAPrivateKeyInfo = RSA.ExportParameters(true);
string message = "2017-04-10T09:37:35.351Z";
string signedMessage = SignData(message, RSAPrivateKeyInfo);
bool success = VerifyData(message, signedMessage, RSAPublicKeyInfo);
Console.WriteLine($"success {success}");
Console.ReadLine();
}
Signing method:
public static string SignData(string message, RSAParameters privateKey)
{
ASCIIEncoding byteConverter = new ASCIIEncoding();
byte[] signedBytes;
using (var rsa = new RSACryptoServiceProvider())
{
// Write the message to a byte array using ASCII as the encoding.
byte[] originalData = byteConverter.GetBytes(message);
try
{
// Import the private key used for signing the message
rsa.ImportParameters(privateKey);
// Sign the data, using SHA512 as the hashing algorithm
signedBytes = rsa.SignData(originalData, CryptoConfig.MapNameToOID("SHA512"));
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
finally
{
// Set the keycontainer to be cleared when rsa is garbage collected.
rsa.PersistKeyInCsp = false;
}
}
// Convert the byte array back to a string message
return byteConverter.GetString(signedBytes);
}
Verification method:
public static bool VerifyData(string originalMessage, string signedMessage, RSAParameters publicKey)
{
bool success = false;
using (var rsa = new RSACryptoServiceProvider())
{
ASCIIEncoding byteConverter = new ASCIIEncoding();
byte[] bytesToVerify = byteConverter.GetBytes(originalMessage);
byte[] signedBytes = byteConverter.GetBytes(signedMessage);
try
{
rsa.ImportParameters(publicKey);
success = rsa.VerifyData(bytesToVerify, CryptoConfig.MapNameToOID("SHA512"), signedBytes);
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
return success;
}
Basically the problem is with string to byte[] encoding. I get the same problem with ASCIIEncoding and with UTF8Encoding.
Thank you in advance!
You cannot use ASCIIEncoding on the encoded message because it contains bytes which are invalid ASCII characters. The typical way you would store the encoded message is in a base64 string.
In SignData, use the following to encode the byte array into a string:
return Convert.ToBase64String(signedBytes);
and in VerifyData, use the following to decode the string back to the same byte array:
byte[] signedBytes = Convert.FromBase64String(signedMessage);

RSA decryption - Key does not exist

I'm trying to encrypt and decrypt file with RSA. Encryption is working fine. But I get error when I'm decrypting.
Error is key does not exist.
Here is the error: http://i.imgur.com/ebF09cU.png
public byte[] RSA_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes, RSAParameters RSAKeyInfo)
{
//initialze the byte arrays to the public key information.
byte[] PublicKey = {214,46,220,83,160,73,40,39,201,155,19,202,3,11,191,178,56,
74,90,36,248,103,18,144,170,163,145,87,54,61,34,220,222,
207,137,149,173,14,92,120,206,222,158,28,40,24,30,16,175,
108,128,35,230,118,40,121,113,125,216,130,11,24,90,48,194,
240,105,44,76,34,57,249,228,125,80,38,9,136,29,117,207,139,
168,181,85,137,126,10,126,242,120,247,121,8,100,12,201,171,
38,226,193,180,190,117,177,87,143,242,213,11,44,180,113,93,
106,99,179,68,175,211,164,116,64,148,226,254,172,147};
//Values to store encrypted symmetric keys.
byte[] EncryptedSymmetricKey;
byte[] EncryptedSymmetricIV;
byte[] encryptedBytes = null;
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(_stBitov))
{
//Set RSAKeyInfo to the public key values.
RSAKeyInfo.Modulus = PublicKey;
//Import key parameters into RSA.
RSA.ImportParameters(RSAKeyInfo);
//Create a new instance of the RijndaelManaged class.
RijndaelManaged RM = new RijndaelManaged();
var key = new Rfc2898DeriveBytes(PublicKey, saltBytes, 1000);
//Encrypt the symmetric key and IV.
EncryptedSymmetricKey = RSA.Encrypt(RM.Key, false);
EncryptedSymmetricIV = RSA.Encrypt(RM.IV, false);
encryptedBytes = RSA.Encrypt(bytesToBeEncrypted, false);
}
}
return encryptedBytes;
}
RSAParameters _RSAKeyInfo;
public void EncryptFile()
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
//Get an instance of RSAParameters from ExportParameters function.
RSAParameters RSAKeyInfo = RSA.ExportParameters(false);
_RSAKeyInfo = RSAKeyInfo;
string path = ofd.FileName;
if (File.Exists(path))
{
string dirPath = Path.GetDirectoryName(path);
byte[] bytesToBeEncrypted = File.ReadAllBytes(path);
byte[] passwordBytes = File.ReadAllBytes(dirPath + "/KEY_" + ofd.SafeFileName);
byte[] bytesEncrypted = RSA_Encrypt(bytesToBeEncrypted, passwordBytes, RSAKeyInfo);
string fileEncrypted = dirPath + "/ENCRYPTED_" + ofd.SafeFileName;
File.WriteAllBytes(fileEncrypted, bytesEncrypted);
}
}
private void button5_Click(object sender, EventArgs e)
{
string path = ofd2.FileName;
if (File.Exists(path))
{
DecryptFile();
richTextBox4.Text = "Dekripcija uspesna";
}
else
{
richTextBox6.Text = "Datoteka ni dodana";
}
} private void richTextBox4_TextChanged(object sender, EventArgs e) { }
public byte[] RSA_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes, RSAParameters RSAKeyInfo)
{
byte[] PublicKey = {214,46,220,83,160,73,40,39,201,155,19,202,3,11,191,178,56,
74,90,36,248,103,18,144,170,163,145,87,54,61,34,220,222,
207,137,149,173,14,92,120,206,222,158,28,40,24,30,16,175,
108,128,35,230,118,40,121,113,125,216,130,11,24,90,48,194,
240,105,44,76,34,57,249,228,125,80,38,9,136,29,117,207,139,
168,181,85,137,126,10,126,242,120,247,121,8,100,12,201,171,
38,226,193,180,190,117,177,87,143,242,213,11,44,180,113,93,
106,99,179,68,175,211,164,116,64,148,226,254,172,147};
//Values to store encrypted symmetric keys.
byte[] EncryptedSymmetricKey;
byte[] EncryptedSymmetricIV;
byte[] decryptedBytes = null;
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(_stBitov))
{
//Set RSAKeyInfo to the public key values.
RSAKeyInfo.Modulus = PublicKey;
//Import key parameters into RSA.
RSA.ImportParameters(RSAKeyInfo);
//Create a new instance of the RijndaelManaged class.
RijndaelManaged RM = new RijndaelManaged();
//Encrypt the symmetric key and IV.
EncryptedSymmetricKey = RSA.Encrypt(RM.Key, false);
EncryptedSymmetricIV = RSA.Encrypt(RM.IV, false);
decryptedBytes = RSA.Decrypt(bytesToBeDecrypted, false);
}
}
return decryptedBytes;
}
public void DecryptFile()
{
string path = ofd2.FileName;
if (File.Exists(path))
{
string dirPath = Path.GetDirectoryName(path);
byte[] bytesToBeDecrypted = File.ReadAllBytes(path);
byte[] passwordBytes = File.ReadAllBytes(dirPath + "/KEY_" + ofd.SafeFileName);
byte[] bytesDecrypted = RSA_Decrypt(bytesToBeDecrypted, passwordBytes, _RSAKeyInfo);
string file = dirPath + "/DECRYPTED_" + ofd.SafeFileName;
File.WriteAllBytes(file, bytesDecrypted);
}
}
Can somebody tell me what to do that decryption is going to work.
RSA is a kind of public-key cryptography. That means you need a public key to encrypt the message and a private key to decrypt your message. It looks like you're using your public key for both encryption and decryption. Where's your private key?
It seems you're trying to do hybrid encryption with RSA+AES, but you forgot to actually use AES to encrypt the plaintext and you forgot to encrypt the symmetric key with RSA. You also need to generate the symmetric key randomly and should not be derived from the public key which is supposed to be constant and public.
The error that you presented here is the least of your problems, but as ElectroByt already said, you need to use a private key (RSACryptoServiceProvider#ExportParameters(true)) to decrypt something with RSA. In your case, you would need to decrypt with RSA to get the symmetric key to use it to decrypt the symmetric ciphertext to get the actual message back.

C# RSA Encryption to PHP Decryption using PHP OpenSSL public key

I'm trying to load a OpenSSL public key from a SOAP server through Nusoap into C#, encrypt my data using the public key, then send the data back to the PHP server for decryption using the private key.
My C# looks like this:
static void Main(string[] args)
{
PHPRef.AddService test = new PHPRef.AddService();
var pkey = test.getPublicKey();
//Console.WriteLine(pkey.ToString());
byte[] PublicKey = GetBytes(pkey);
//Values to store encrypted symmetric keys.
byte[] EncryptedSymmetricKey;
byte[] EncryptedSymmetricIV;
//Create a new instance of RSACryptoServiceProvider.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(2048);
//Get an instance of RSAParameters from ExportParameters function.
RSAParameters RSAKeyInfo = RSA.ExportParameters(false);
//Set RSAKeyInfo to the public key values.
RSAKeyInfo.Modulus = PublicKey;
//Import key parameters into RSA.
RSA.ImportParameters(RSAKeyInfo);
//Create a new instance of the RijndaelManaged class.
RijndaelManaged RM = new RijndaelManaged();
//Encrypt the symmetric key and IV.
EncryptedSymmetricKey = RSA.Encrypt(RM.Key, false);
EncryptedSymmetricIV = RSA.Encrypt(RM.IV, false);
Console.WriteLine("RijndaelManaged Key and IV have been encrypted with RSACryptoServiceProvider.");
byte[] encryptedData = RSA.Encrypt(GetBytes("password"), false);
//byte[] returned = (byte[])(Array)test.getDecrypted((sbyte[])(Array)encryptedData);
//string answer = GetString(returned);
string answer = test.getDecrypted((sbyte[])(Array)encryptedData);
Console.WriteLine(answer);
Console.ReadLine();
}
static byte[] GetBytes(string str)
{
byte[] bytes = Encoding.ASCII.GetBytes(str);
return bytes;
}
static string GetString(byte[] bytes)
{
char[] chars = Encoding.ASCII.GetChars(bytes);
return new string(chars);
}
And my PHP like so:
function getPublicKey()
{
$crt = file_get_contents("public.crt");
// $publickey = str_ireplace("\r", "", $crt);
// $publickey = str_ireplace("\n", "", $publickey);
// $publickey = str_ireplace("-----BEGIN CERTIFICATE-----", "", $publickey);
// $publickey = str_ireplace("-----END CERTIFICATE-----", "", $publickey);
return $crt;
}
function getDecrypted($input)
{
global $privateRSA;
// $privateRSA = str_ireplace("\r", "", $privateRSA);
// $privateRSA = str_ireplace("\n", "", $privateRSA);
// $privateRSA = str_ireplace("-----BEGIN RSA PRIVATE KEY-----", "", $privateRSA);
// $privateRSA = str_ireplace("-----END RSA PRIVATE KEY-----", "", $privateRSA);
if(!openssl_private_decrypt($input, $decrypted, $privateRSA))
return "fail";
else
return "success";
return $decrypted;
}
Needless to say I get "fail" every time. Any suggestions? I'm trying to do this with pure PHP and pure C#, no special libraries. The keys are 2048 bit.
After nearly a full day trying to find this, it was incredibly simple. You don't need BouncyCastle, SecLib, any third-party libraries, nothing.
C#:
static void Main(string[] args)
{
PHPRef.AddService test = new PHPRef.AddService();
var pkey = test.getPublicKey();
byte[] pkeybyte = GetBytes(pkey);
X509Certificate2 cert = new X509Certificate2();
cert.Import(pkeybyte);
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] encryptedData = rsa.Encrypt(GetBytes("password"), false);
Console.WriteLine(GetString(encryptedData));
string answer = test.getDecrypted((sbyte[])(Array)encryptedData);
Console.WriteLine(answer);
Console.ReadLine();
}
And the PHP:
Just change getPublicKey like so
function getPublicKey()
{
$crt = file_get_contents("public.crt");
$publickey = str_ireplace("\r", "", $crt);
$publickey = str_ireplace("\n", "", $publickey);
$publickey = str_ireplace("-----BEGIN CERTIFICATE-----", "", $publickey);
$publickey = str_ireplace("-----END CERTIFICATE-----", "", $publickey);
return $publickey;
}

RSA Sign with PHP, verify with C#

Unfortunately I haven't found anything that works for me yet so I'll create a new question.
My PHP Code (using phpseclib's RSA) that signs the string, as you might notice the code is to verify a license code.
<?php
include('Crypt/RSA.php');
$rsa = new Crypt_RSA();
//$rsa->setPassword('password');
$rsa->loadKey('-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
'); // private key
$plaintext = 'AAAAA-AAAAA-AAAAA-AAAAA';
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$signature = $rsa->sign($plaintext);
echo base64_encode($signature);
The C# code that should verify the response:
bool success = false;
using (var rsa = new RSACryptoServiceProvider())
{
StreamReader reader = new StreamReader(dataStream);
String signedString = reader.ReadToEnd();
byte[] signedBytes = Convert.FromBase64String(signedString);
byte[] bytesToVerify = Encoding.UTF8.GetBytes(value);
try
{
RSAParameters parameters = new RSAParameters();
parameters.Exponent = new byte[] { 0x01, 0x10, 0x01 };
parameters.Modulus = OtherClass.StringToByteArray(Program.Modulus);
rsa.ImportParameters(parameters);
success = rsa.VerifyData(bytesToVerify, new SHA1CryptoServiceProvider(), signedBytes);
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
dataStream is the webrequest's response stream.
I've solved this now by using another way to load the key.
I've used this online converter to convert my PEM key to a XML key: https://superdry.apphb.com/tools/online-rsa-key-converter
So I changed the try { ... } part to:
rsa.FromXmlString("{XML_KEY}");
success = rsa.VerifyData(bytesToVerify, new SHA1CryptoServiceProvider(), signedBytes);
Now it works just fine. I guess I didn't really understand how to load a key via modulus and exponent.

Categories

Resources