C# RSA implementation with OpenSSL keys & Bouncy castle - c#

I'm trying to implement string encryption-decryption in C# using OpenSSL-generated keypair and Bouncy Castle.
OpenSSL granted me keypair, which I have separated in 2 files. Now I am using Pemreader from Bouncy Castle to read the keys and change them to AsymmetricKeyParameters.
The code below runs, but the decrypted string isn't the same as the original - I am getting a bunch of ?'s.
If I print out the keys, they seem just like in the text file.
Could someone point out what I am doing wrong? The pemreading procedure or engine-using seem to be the cause. How strong this encryption will be with 2048-bit key without padding?
string test = "qwerty12345";
AsymmetricKeyParameter keyparmeter = readPublicKey(public_path); // Read public key into string
/* Print the test key */
Console.WriteLine("test key = " + test);
/* Convert test to byte array */
byte[] bytes = new byte[test.Length * sizeof(char)];
System.Buffer.BlockCopy(test.ToCharArray(), 0, bytes, 0, bytes.Length);
byte[] cipheredbytes = null;
/* Initiate rsa engine */
RsaEngine e = new RsaEngine();
e.Init(true, keyparmeter); // initialize engine true, encrypting
/* Crypt! */
cipheredbytes = e.ProcessBlock(bytes, 0, bytes.Length);
// ## NOW DECRYPTION ##
/* Get the private key */
AsymmetricKeyParameter privkeyparameter = readPrivKey(privkey_path);
byte[] reversedbytes = null;
/* Initiate rsa decrypting engine */
RsaEngine d = new RsaEngine();
d.Init(false, privkeyparameter); // initialize engine false, decrypting
/* Decrypt! */
reversedbytes = d.ProcessBlock(cipheredbytes, 0, cipheredbytes.Length);
char[] chars = new char[cipheredbytes.Length / sizeof(char)];
System.Buffer.BlockCopy(cipheredbytes, 0, chars, 0, cipheredbytes.Length);
string reversedtest = new string(chars);
### PEMREADING ###
/* Convert PEM into AsymmetricKeyParameter */
private AsymmetricKeyParameter readPublicKey(string path_to_key)
{
RsaKeyParameters asmkeypar;
using(var reader = File.OpenText(path_to_key))
asmkeypar = (RsaKeyParameters) new PemReader(reader).ReadObject();
return asmkeypar;
}
/* Convert PEM into AsymmetricKeyParameter */
private AsymmetricKeyParameter readPrivKey(string path_to_key)
{
AsymmetricCipherKeyPair asmkeypar;
using (var reader = File.OpenText(path_to_key))
asmkeypar = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
return (RsaKeyParameters) asmkeypar.Private;
}

You are using the base RSA algorithm. This is also known as raw or textbook RSA. Basically it performs modular exponentiation, but it doesn't do the padding or unpadding. So what you are receiving is the plaintext + the zero's that have been put in front of the value, as the unpadding does not seem to take place.
Finally, you should perform character encoding instead of System.Buffer.BlockCopy, the latter will probably make a mess out of it because it has to operate on a Unicode encoded string in .NET.
I can refer you to this question on crypto that tries to list all the possible attacks on raw/textbook RSA. There are a lot, the chance that your code is secure is about zero.

Related

AES decryption only producing part of the answer C#

I'm trying to learn cyber security and this is the very first thing I've done on it. I'm using this MSDN document ( https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes?redirectedfrom=MSDN&view=netcore-3.1 ) and it partly works. I assume it's encrypting it fine as when it comes to the decryption some of the original data is there but some is lost. The data that is being encrypted is a class that has been formatted into a JSON string( I don't think this is relevant as it's still a string being encrypted).
But once it's been encrypted and decrypted it turns out like this:
I've ran this code and compared the results 5+ times and it's always: the start is wrong, username is partly right, password is always right and loginkey is partly right. So the error is recurring and always in the same spot.
Information you should know, the data get's encrypted and saved to a .txt file. The programme will run again and it will try and decrypted it. The Salt and password are saved on another file and those are read and used in the decryption.
There is a similar question on stackoverflow but the answer just says to use Rijndael(so not really an answer), this code is for me to learn and want an answer that isn't 4 lines long.
Code if curious(but it's basically the same as the MSDN document):
Encryption:
static void EncryptFile()
{
string pwd1 = SteamID;//steamID is referring to account ID on Valve Steam
using (RNGCryptoServiceProvider rngCsp = new
RNGCryptoServiceProvider())
{
rngCsp.GetBytes(salt1); //salt1 is a programme variable and will get saved to a file
}
SecureData File = new SecureData(_UserName,_PassWord,_LoginKey);
string JsonFile = JsonConvert.SerializeObject(File); //puts the class into Json format
int myIterations = 1000; //not needed
try
{
Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1, salt1,
myIterations);
Aes encAlg = Aes.Create(); // This might be the issue as AES will be different when you decrypt
encAlg.Key = k1.GetBytes(16);
MemoryStream encryptionStream = new MemoryStream();
CryptoStream encrypt = new CryptoStream(encryptionStream,
encAlg.CreateEncryptor(), CryptoStreamMode.Write);
byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(
JsonFile); //encrypt Data
encrypt.Write(utfD1, 0, utfD1.Length);
encrypt.FlushFinalBlock();
encrypt.Close();
byte[] edata1 = encryptionStream.ToArray();
k1.Reset();
System.IO.File.WriteAllBytes(SecureFile, edata1); //writes encrypted data to file
}
catch (Exception e)
{
Console.WriteLine("Error: ", e);
}
}
Decryption:
static void DecryptFile()
{
string pwd1 = SteamID;
byte[] edata1;
try
{
edata1 = System.IO.File.ReadAllBytes(SecureFile); //reads the file with encrypted data on it
Aes encAlg = Aes.Create(); //I think this is the problem as the keyvalue changes when you create a new programme
Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(pwd1, salt1); //inputs from last time carry over
Aes decAlg = Aes.Create();
decAlg.Key = k2.GetBytes(16);
decAlg.IV = encAlg.IV;
MemoryStream decryptionStreamBacking = new MemoryStream();
CryptoStream decrypt = new CryptoStream(
decryptionStreamBacking, decAlg.CreateDecryptor(), CryptoStreamMode.Write);
decrypt.Write(edata1, 0, edata1.Length);
decrypt.Flush();
decrypt.Close();
k2.Reset();
string data2 = new UTF8Encoding(false).GetString(
decryptionStreamBacking.ToArray());//decrypted data
SecureData items = JsonConvert.DeserializeObject<SecureData>(data2); //reformat it out of JSon(Crashes as format isn't accepted)
_UserName = items.S_UserName;
_PassWord = items.S_Password;
_LoginKey = items.S_LoginKey;
}
catch (Exception e)
{
Console.WriteLine("Error: ", e);
NewLogin();
}
}
Class Struct:
class SecureData
{
public string S_UserName { get; set; } //These are variables that are apart of Valve steam Login process
public string S_Password { get; set; }
public string S_LoginKey { get; set; }
public SecureData(string z, string x, string y)
{
S_UserName = z;
S_Password = x;
S_LoginKey = y;
}
}
The problem is caused by different IVs for encryption and decryption. For a successful decryption the IV from the encryption must be used.
Why are different IVs applied? When an AES instance is created, a random IV is implicitly generated. Two different AES instances therefore mean two different IVs. In the posted code, different AES instances are used for encryption and decryption. Although the reference encAlg used in the decryption has the same name as that of the encryption, the referenced instance is a different one (namely an instance newly created during decryption). This is different in the Microsoft example. There, the IV of the encryption is used in the decryption: decAlg.IV = encAlg.IV, where encAlg is the AES instance with which the encryption was performed.
The solution is to store the IV from the encryption in the file so that it can be used in the decryption. The IV is not secret and is usually placed before the ciphertext:
Necessary changes in EncryptFile:
...
byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(JsonFile);
encryptionStream.Write(encAlg.IV, 0, encAlg.IV.Length); // Write the IV
encryptionStream.Flush();
encrypt.Write(utfD1, 0, utfD1.Length);
...
Necessary changes in DecryptFile:
...
edata1 = System.IO.File.ReadAllBytes(SecureFile);
byte[] iv = new byte[16]; // Separate IV and ciphertext
byte[] ciphertext = new byte[edata1.Length - iv.Length];
Array.Copy(edata1, 0, iv, 0, iv.Length);
Array.Copy(edata1, iv.Length, ciphertext, 0, ciphertext.Length);
...
Aes encAlg = Aes.Create(); // Remove this line
...
decAlg.IV = iv; // Use the separated IV
...
decrypt.Write(ciphertext, 0, ciphertext.Length); // Use the separated ciphertext
A few remarks:
For each encryption a new, random salt should be generated and concatenated with the ciphertext analogous to the IV. During decryption, the salt can then be determined analogous to IV. Consider additionally RFC8018, sec 4.1.
The iteration count slows down the derivation of the key, which should make an attack by repeated attempts more difficult. Therefore the value should be as large as possible. Consider additionally RFC8018, sec 4.2.
Authentication data (i.e. passwords) are not encrypted, but hashed, here.

Convert simple encryption method in c# to php

We have the following simple encryption method in c#, we want write the same method in php7+
method in C#
using System.Security.Cryptography;
public string Encrypt(string strText, string encKey)
{
byte[] newEncKey = new byte[encKey.Length];
for (int i = 0; i < encKey.Length; i++)
newEncKey[i] = (byte)encKey[i];
try
{
TripleDESCryptoServiceProvider provider = new TripleDESCryptoServiceProvider();
byte[] bytes = Encoding.UTF8.GetBytes(strText);
MemoryStream stream = new MemoryStream();
CryptoStream stream2 = new CryptoStream(stream, provider.CreateEncryptor(newEncKey, newEncKey), CryptoStreamMode.Write);
stream2.Write(bytes, 0, bytes.Length);
stream2.FlushFinalBlock();
return Convert.ToBase64String(stream.ToArray());
}
catch (Exception)
{
return string.Empty;
}
}
We want get the same encryption text with the same key in c# and php7+,
We tried to use the following code in php
public function encryptData($key, $plainText)
{
$byte = mb_convert_encoding($key, 'ASCII');
$desKey = md5(utf8_encode($byte), true);
$desKey .= substr($desKey,0,8);
$data = mb_convert_encoding($plainText, 'ASCII');
// add PKCS#7 padding
$blocksize = mcrypt_get_block_size('tripledes', 'ecb');
$paddingSize = $blocksize - (strlen($data) % $blocksize);
$data .= str_repeat(chr($paddingSize), $paddingSize);
// encrypt password
$encData = mcrypt_encrypt('tripledes', $desKey, $data, 'ecb');
return base64_encode($encData);
}
, but encryption text using this method not match the encryption text in C# method.
Example :
C#:
String key = "234576385746hfgr";
String text = "hello";
Console.WriteLine(Encrypt(text, key));
// output: Hg1qjUsdwNM=
PHP:
$key = "234576385746hfgr";
$text = "hello";
echo encryptData($key, $text);
// output: SRdeQHyKJF8=
How to get the same encryption text in php7+, we want convert C# code to PHP!
In the C# code, the mode is not explicitly specified, so that the CBC mode is used by default. In the PHP code, however, the ECB mode is applied, which must be changed into the CBC mode.
In the C# code newEncKey is used as key, which is 16 bytes in size and is implicitly extended to 24 bytes (3 times the TripleDES block size of 8 bytes) by appending the first 8 bytes at the end (this corresponds to 2TDEA). This must be done explicitly in the PHP code. Also remove the MD5 digest, as it's not used in C# code:
$byte = mb_convert_encoding($key, 'ASCII');
//$desKey = md5(utf8_encode($byte), true);
$desKey = $byte . substr($byte, 0, 8);
In the C# code newEncKey is also used as IV, of which implicitly only the first 8 bytes are applied (1 times the TripleDES block size). In the PHP code the shortening of the IV must be done explicitely, e.g. with
$desIV = substr($byte, 0, 8);
The IV must be passed as 5th parameter in mcrypt_encrypt:
$encData = mcrypt_encrypt('tripledes', $desKey, $data, 'cbc', $desIV);
The C# code uses PKCS7 padding by default, so this is consistent with the padding of the PHP code.
With these changes, the PHP code produces the same result as the C# code.
For security reasons, key/IV pairs may not be used more than once. The logic used here (generation of the IV from the key) therefore requires a new key for each encryption. Furthermore mcrypt_encrypt is deprecated, a better alternative is openssl_encrypt, which also uses PKCS7 padding by default.

AES/CBC/NoPadding between C# and Java

I'm using some encryption functions in C# and Java whose output doesn't seem to match. I'm feeding in the same key and IV strings as a test.
Input string: "&app_version=1.0.0.0"
Java:
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes("UTF-8"));
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(input.getBytes("UTF-8"));
// Then I convert encrypted to hex by building a string of encrypted[i] & 0xFF
Output:
60f73a575b647263d75011bb974a90e85201b8dfeec6ec8ffba04c75ab5649b3
C#:
SymmetricKeyAlgorithmProvider alg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbc);
BinaryStringEncoding encoding = BinaryStringEncoding.Utf8;
// Create key and IV buffers
IBuffer keyBuffer = CryptographicBuffer.ConvertStringToBinary(key, encoding);
CryptographicKey cKey = alg.CreateSymmetricKey(keyBuffer);
IBuffer ivBuffer = CryptographicBuffer.ConvertStringToBinary(iv, encoding);
// Create input text buffer
IBuffer inputBuffer = CryptographicBuffer.ConvertStringToBinary(input, encoding);
// Do the encryption
IBuffer encryptedBuffer = CryptographicEngine.Encrypt(cKey, inputBuffer, ivBuffer);
// Convert encrypted back to hex
string encryptedStr = CryptographicBuffer.EncodeToHexString(encryptedBuffer);
Output:
4b6fd83c35565fc30a9ce56134c277cbea74d14886cf99e11f4951075d4f4505
I am using a Java decrypter to check and it decrypts the Java-encrypted string correctly but the C# string is read as "&app_version=1Q0.0.0" so it seems close but slightly off.
I have checked that the bytes of the key, input, and IV match before the encryption step. Are there any other differences that would cause a discrepancy?
EDIT
With all-zero key "00000000000000000000000000000000" and IV "0000000000000000" I got the same output for both Java and C#:
081821ab6599650b4a31e29994cb130203e0d396a1d375c7d1c05af73b44a86f
So perhaps there is something wrong with the key or IV that one is reading...
I feel like a fool...my IV contained a zero in one and a capital O in another!! Well, at least I know this code is equivalent.

Encrypt data using c# and decrypt it using openssl api, why there are lots of trashy padding at the end of decrypted data?

I using RSA(1024) to encrypt/decrypt strings. The encryption is implemented using public key and is written in C#, and the decryption is implementation by c. I encrypt the string:
86afaecb-c211-4d55-8e90-2b715d6d64b9
and write the encrypted data to a file. Then, I using openssl api to read the encrypted data from the file and decrypt it. However, I got the output as:
86afaecb-c211-4d55-8e90-2b715d6d64b9oeheBjQ8fo1AmDnor1D3BLuPyq9wJBAOV+M/WVNYzYr
PJBKoskOj+4LaNpT+SpkfK81nsnQEbHbjgao4eHNU+PmWl9
It seems that there are some trashy padding at the end of original string. Why It Occurs? And how to solve the problem?
Some code snippet is shown below:
// Encrypt
{
string plainData = “86afaecb-c211-4d55-8e90-2b715d6d64b9”;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(paraPub);
byte[] testData = Encoding.UTF8.GetBytes(plainData);
byte[] encryptedData = rsa.Encrypt(testData, true);
FileStream pFileStream = null;
string fileName = "encryptedData.dat";
pFileStream = new FileStream(fileName, FileMode.OpenOrCreate);
pFileStream.Write(encryptedData, 0, encryptedData.Length);
...
}
// Decrypt
{
char *encrypt = malloc(RSA_size(privateKey));
FILE *out = fopen("encryptedData.dat", "r");
int encrypt_len = fread(encrypt, sizeof(*encrypt), RSA_size(privateKey), out);
fclose(out);
decrypt = malloc(encrypt_len);
if(RSA_private_decrypt(encrypt_len,
(unsigned char*)encrypt,
(unsigned char*)decrypt,
privateKey, RSA_PKCS1_OAEP_PADDING) == -1) {
// error handle
}
printf("Decrypted message: %s\n", decrypt);
}
I solve the problem by initializing the decrypt using "memset(decrypt, 0, encrypt_len);" after "decrypt = malloc(encrypt_len);". Thx everyone.
The issue is that you should use the decrypted size instead of directly treating the output of the decryption as a null terminated string.
RSA_private_decrypt() returns the size of the recovered plaintext.

Encrypt in C# using RSACryptoServiceProvide and decrypt using openssl_private_decrypt in PHP

I spent whole day for trying to get it work but no luck:(
I use these code in C# for encryption:
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
RSAParameters rsaParam = rsa.ExportParameters(false);
rsaParam.Modulus = Convert.FromBase64String("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwlhAsNcNCDRgzCc49u/0iSDrdJn7yoiH/HHipbQp0QSejzg/48mMA6wb32OPQ7qzBgJNvwiQbMvi89BvGNAJ9K8vM0RW7WOqtnb/8IK9BAJVtEwJ3vvKTf5EluiUgWVbGYpWPjbl/lsD3/hRTR0uF46h7q4OlARxOupl9xVS2wQIDAQAB");
rsa.ImportParameters(rsaParam);
string msg = "This is a test.";
byte[] encValue = rsa.Encrypt(Encoding.UTF8.GetBytes(msg), true);
Console.WriteLine(Convert.ToBase64String(encValue));
This is the PHP code I use to decrypt.
// Read key
$fp = fopen($KeyPath,"r");
$Key = fread($fp,8192);
fclose($fp);
openssl_private_decrypt($data, $decrypted, openssl_get_privatekey($Key, "123456"));
The private key I used(Passphase "123456"):
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,16B167A1F1E4E61E
A0eOxhU9Fp4ZIkmSpCUOA2VGG8evE71bEz/eO5LlUatUTt4RQcu68mFOM23PdnHl
YqjTV7AwedUu+LsNtjDfy+NJzvvi+re/kpYAD9RWDE0buHGp86vIhxJLCA633JSt
kcMbkFBBbJPBW74FK7Djo2tlE/jKFb4Uy6EIBEsI56pcbdOIKWHTOLHb3/gG8spx
/jPyylR1D1Rm1Nw9mhfQ8c+GZoXYn919Zx9fvKYq5CiH8hqy6q1TCsTjUpdgdkxz
3kDQ6nn4cOCCwCwU2F+iRpzmSE0DORPtCK/rNdhHXaVqm/SvIDSerpX6L4l8NiRx
Vb19htQChysfB7O/XiDVxL8gqSUmMrSujP50NUlyuBEG/32JyCounlX/4JQEGvAN
ALGkLwULhp1D2ATQVck5aNncxcbuB56laf+KZm5E83Tbeu1j4MG+JzJq+kbLVuYi
7TJ1JqjjL4Ixlyh/M23UuViFsw1V0zuZslFhvtq0/hdNXhIgNVmMFPFadOSKMtVY
kTkX7+coEXrtwPV+4ztoH3M2+zwZczkNECbed9H0PPw6uhrOpu+EyGR4qJ/TsMe1
Ht60veBMuPhwC5TqKP8Luz8x57d5Y4+kBFMvQda1b38PUuXSRw2OZ+cBHk0wrET/
pnyOIhg3lvREPvhXpe1oyaSZZLu95xTAj9YSDG+iKToDCD8hgdaRn1Pi6VOaz8Ru
+AUjz0L0fbwrU7jZ3x2L1AGsdwVwmwTL8Fwk/WY8sWu3KCW4olW1nQ8o/4+jO7q9
JvrYW/HxqIxP0Mnc9ODNmaG/NH1q5v7LIPAz47bpqXwdr8hDV/L5mA==
-----END RSA PRIVATE KEY-----
I am not familiar with encryption, can some one please tell how to get it work?
PS: I think the code in php is fine since I tested the code seperately.
You can use this code for encrypt your string.
public string EncodeData(string sData)
{
try {
byte[] encData_byte = new byte[sData.Length];
encData_byte = System.Text.Encoding.UTF8.GetBytes(sData);
string encodedData = Convert.ToBase64String(encData_byte);
return encodedData;
} catch (Exception ex) {
throw new Exception("Error in base64Encode" + ex.Message);
}
}
and for decrypt your string you can use this code.
public string DecodeData(string sData)
{
System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
System.Text.Decoder utf8Decode = encoder.GetDecoder();
byte[] todecode_byte = Convert.FromBase64String(sData);
int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
char[] decoded_char = new char[charCount];
utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
string result = new String(decoded_char);
return result;
}
Try this this will work.
Thank you.
Are you sure RSACryptoProvider is working with the key in the format you're providing it in?
A lot of examples of RSACryptoProvider I've seen use XML-based private keys. eg.
RSA Signing with PHP and verifying with C#
"<RSAKeyValue><Modulus>3BqiIB3ouyXHDMpW43TlZrx8fkts2FVVARJKNXFRQ/WIlsthDzL2jY2KEJVN6BKE4A51X+8LMzAI+2z3vIgAQT3bRSfOwygpGBjdhhnXJwFlQ6Gf/+z0ffQfVx/DHw3+QWphcwGDBst+KIA6u6ayy+RDE+jEityyyWDiWqkR9J8=</Modulus><Exponent>AQAB</Exponent><P>8a8nuVhIANh7J2TLn4wWTXhZY1tvlyFKaslOeAOVr+wgEWLQpLZ0Jpjm8aUyyOYPXlk7xrA5BOebtz41diu4RQ==</P><Q>6SQ9y3sEMjrf/c4bHGVlhOj4LUVykradWWUNC0ya7llnR8y1djJ1uUut+EoAa1JQCGukuv4K8NvN1Ieo72Fhkw==</Q><DP>cg0VMusNN5DxNRrk2IrUL4TesfuBQpGMO6554DrY1acZTvsRuNj9IQXA3kH2IEYo9H4prk6U6dKeci/iLLze/Q==</DP><DQ>m/pZNXeZ+RkWnrFzxe24m9FZqMAbxThT0Wkf7v1Tcj9yL8EvbmKYDF4riD/KRAMP9HJABbLNExObg6M3TOAz7Q==</DQ><InverseQ>w8PvW8srrPCuOcphBKXSyoZxCZn81+rovBxuE8AB95m5X+URE8SunK7f+g7hBBin6nUOaVGohBP8jzkQEsdx1Q==</InverseQ> <D>AsVPDypxOJHkLJQLffeFv8JVqt1WNG72j/nj90JC7KEVpBhRU3inw+ZpO4Y1odtB0vQ7pAaFVJKhOlEH2Va48hNUEQujML8rE+LZXgI3lu0TlqOCIqTHIljeJry0ca30XFtFDp9kh0Kr/0CgGMqgIed+hDUjAad8ke9D2YicDok=</D></RSAKeyValue>"
I searched for days and finally figured out myself:)
I am loading the parameters in the wrong way.
According to the RSA Public key structures(PEM):
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwlhAsNcNCDRgzCc49u/0iSDrdJn7yoiH/HHipbQp0QSejzg/48mMA6wb32OPQ7qzBgJNvwiQbMvi89BvGNAJ9K8vM0RW7WOqtnb/8IK9BAJVtEwJ3vvKTf5EluiUgWVbGYpWPjbl/lsD3/hRTR0uF46h7q4OlARxOupl9xVS2wQIDAQAB
Which I split the string into 3 parts(base64 encoded):
Header
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC
Modulus:
wlhAsNcNCDRgzCc49u/0iSDrdJn7yoiH/HHipbQp0QSejzg/48mMA6wb32OPQ7qzBgJNvwiQbMvi89BvGNAJ9K8vM0RW7WOqtnb/8IK9BAJVtEwJ3vvKTf5EluiUgWVbGYpWPjbl/lsD3/hRTR0uF46h7q4OlARxOupl9xVS2wQ
Exponent:
IDAQAB
(Note that I still didn't get a clear idea of the RSA key strutures. Those above are just a blurry view of a key structure, but for those who interested in, I recommend you to read the API Documentation "RSAParameters" or the RSA specification)
Obviously what I was doing is to import the entire key string to the RSAParameters.Modulus. That is not the way to import the key. So that's why it didn't work.
The way to do it is to extract the modulus and exponent which was needed for a public encryption from the key file. And import into RSAParameters
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = new RSAParameters();
RSAKeyInfo.Modulus = modulus;
RSAKeyInfo.Exponent = exponent;
RSA.ImportParameters(RSAKeyInfo);
Then encrypt the string:
RSA.Encrypt("HAHA I GOT IT!!", false);
The way to extract. I recommend going to JavaScience for more info. There are bunch of cryptographic utilities there.

Categories