I have a .NET program and a Borland Win32 program that need to pass some cryptographically secure information. The plan right now is to have the .NET app create a public/private key pair, store the public key on disk and keep the private key in memory for as long as the .NET program is running.
The Borland app will then read the public key from disk and use the OpenSSL library to encrypt the data with the public key and write that result to disk.
Finally the .NET app will read the encrypted data and decrypt it with the private key.
What is the best way to export the key from .NET and in turn import it into the OpenSSL library?
In the .NET program create a new RSACryptoServiceProvider
. Export the public key as RSAParameters
and write the Modulus
and Exponent
values to disk. Like this:
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(4096); //4096 bit key
RSAParameters par = rsa.ExportParameters(false); // export the public key
File.WriteAllBytes(@"C:\modulus.bin", par.Modulus); // write the modulus and the exponent to disk
File.WriteAllBytes(@"C:\exponent.bin", par.Exponent);
On the C++ side you'll need to read the modulus and exponent values from disk convert them into BIGNUM
values. These values will be loaded into an RSA key and then you can encrypt the plain text and write the cipher text to disk. Like this:
RSA * key;
unsigned char *modulus;
unsigned char *exp;
FILE * fp = fopen("c:\\modulus.bin", "rb"); // Read the modulus from disk
modulus = new unsigned char[512];
memset(modulus, 0, 512);
fread(modulus, 512, 1, fp);
fclose(fp);
fp = fopen("c:\\exponent.bin", "rb"); // Read the exponent from disk
exp = new unsigned char[3];
memset(exp, 0, 3);
fread(exp, 3, 1, fp);
fclose(fp);
BIGNUM * bn_mod = NULL;
BIGNUM * bn_exp = NULL;
bn_mod = BN_bin2bn(modulus, 512, NULL); // Convert both values to BIGNUM
bn_exp = BN_bin2bn(exp, 3, NULL);
key = RSA_new(); // Create a new RSA key
key->n = bn_mod; // Assign in the values
key->e = bn_exp;
key->d = NULL;
key->p = NULL;
key->q = NULL;
int maxSize = RSA_size(key); // Find the length of the cipher text
cipher = new char[valid];
memset(cipher, 0, valid);
RSA_public_encrypt(strlen(plain), plain, cipher, key, RSA_PKCS1_PADDING); // Encrypt plaintext
fp = fopen("C:\\cipher.bin", "wb"); // write ciphertext to disk
fwrite(cipher, 512, 1, fp);
fclose(fp);
Finally you can take the ciphertext and decrypt it in C# without any difficulty.
byte[] cipher = File.ReadAllBytes(@"c:\cipher.bin"); // Read ciphertext from file
byte[] plain = rsa.Decrypt(cipher, false); // Decrypt ciphertext
Console.WriteLine(ASCIIEncoding.ASCII.GetString(plain)); // Decode and display plain text
You could use OpenSSL directly in C# with the OpenSSL.NET wrapper!