Here is the Objective-C we are using to generate the RSA object using the following lib: https://github.com/kuapay/iOS-Certificate--Key--and-Trust-Sample-Project
BDRSACryptor *rsa = [[BDRSACryptor alloc] init];
BDRSACryptorKeyPair *RSAKeyPair = [rsa generateKeyPairWithKeyIdentifier:nil error:error];
We then pass RSAKeyPair.publicKey to our c#, where using the BouncyCastles library:
using (TextReader sr = new StringReader(pempublic))
{
var pemReader = new PemReader(sr);
var temp = (RsaKeyParameters)pemReader.ReadObject();
var RSAKeyInfo = new RSAParameters
{
Modulus = temp.Modulus.ToByteArray(),
Exponent = temp.Exponent.ToByteArray()
};
var rsaEncryptor = new RSACryptoServiceProvider();
rsaEncryptor.ImportParameters(RSAKeyInfo);
}
There are no errors, but the encryption is different. The same string encrypted in c# and obj-c are different, and we are unable to encrypt on one end and decrypt on the other.
Help!
Edit: Willing to consider any methodology of exchanging public keys between c# and obj-c. This is just the closest we have come so far.
Edit2: Contents of pempublic
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/ugxekK+lY0VLeD8qA5nEhIn7IzBkgcrpiEM109chFxHobtvWEZbu8TqTIBtIgtISNp4idcEvahPniEyUawjmRSWB7uYmcHJ3pWaIo5/wBthmGrqS/XjedVXT6RuzaoPf9t0YXyW6YiH1kQZn4gjZF51O6iIk2+VnfkYVqeKBtQIDAQAB-----END PUBLIC KEY-----
Edit3: Regarding padding: C# and obj-c are both using OEAP padding.
Edit4: How the text is being encrypted: c#
byte[] testBytes = Encoding.UTF8.GetBytes("1234567890");
byte[] encryptedBytes = rsaEncryptor.Encrypt(testBytes, true);
string base64 = Convert.ToBase64String(encryptedBytes);
obj-c
NSString *encrypted = [rsa encrypt:#"1234567890" key:RSAKeyPair.publicKey error:error];
Final Edit:
Solved by using the Chilkat encryption library on the .NET server. We are now able to load an RSA encryptor from a public key in both XML and PEM format generated from a .NET, Java, or Objective-C Client. If anyone could explain why the .NET RSACryptoServiceProvider wouldn't work, we are all quite curious.
please check my answer to my own question
RSA C# encryption with public key to use with PHP openssl_private_decrypt(): Chilkat, BouncyCastle, RSACryptoServiceProvider
i think it may be helpful
to make it short, try using temp.Modulus.ToByteArrayUnsigned()
I wrote RSA and AES implementation using CommonCrypto, implementation is done in order to be interoperable with .NET
Check it out
https://github.com/ozgurshn/EncryptionForiOS
I used base64 encoding
.NET side could be
public string RsaDecryption(byte[] cipherText, string privateKey)
{
var cspDecryption = new RSACryptoServiceProvider();
cspDecryption.FromXmlString(privateKey);
var bytesPlainTextData = cspDecryption.Decrypt(cipherText, false);
return Encoding.UTF8.GetString(bytesPlainTextData);
}
public byte[] RsaEncryption(string plainText, string publicKey)
{
var cspEncryption = new RSACryptoServiceProvider();
cspEncryption.FromXmlString(publicKey);
var bytesPlainTextData = Encoding.UTF8.GetBytes(plainText);
var bytesCypherText = cspEncryption.Encrypt(bytesPlainTextData, false);
return bytesCypherText;
}
Related
I have a situation where a Java program encrypts text using RSA/ECB/OAEPWithSHA-256AndMGF1Padding.
I need to decrypt it in c#.
Encryption and decryption work fine in Java.
Encryption in Java and decryption in c# with RSA/ECB/OAEPWithSHA-1AndMGF1Padding works absolutely fine.
However, with RSA/ECB/OAEPWithSHA-256AndMGF1Padding encryption in Java and decryption with OaepSHA256 in C# gives me the error : The parameter is incorrect.
Java Code for encrypt:
public static String encrypt(KeyPair keypair, String data) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
Cipher c = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
//Cipher c = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
c.init(Cipher.ENCRYPT_MODE, keypair.getPublic());
return Base64.getEncoder().encodeToString(c.doFinal(data.getBytes()));
}
C # code for decrypt :
public string DecryptRsa(byte[] encryptedBytes, X509Certificate2 x509Certificate2, RSAEncryptionPadding rSAEncryptionPadding)
{
var text = string.Empty;
using (RSACng csp = (RSACng)x509Certificate2.GetRSAPrivateKey())
{
byte[] bytesDecrypted = csp.Decrypt(encryptedBytes, rSAEncryptionPadding);
text = Encoding.UTF8.GetString(bytesDecrypted);
}
return text;
}
What am i doing wrong? Please help.
OAEP uses two digests, the OAEP digest and the MGF1 digest, see RFC8017.
The SunJCE provider specifies with RSA/ECB/OAEPWithSHA-256AndMGF1Padding the OAEP digest as SHA256, while the MGF1 digest defaults to SHA1, see here. The C# code, on the other hand, specifies with OaepSHA256 both digests as SHA256. Therefore, both codes are incompatible.
The fix is to either explicitly specify the digests in Java with OAEPParameterSpec (which should always be done anyway for this very reason). On the C# side, no fix is possible with on board means, since a separate specification of both digests is not supported. But BouncyCastle can be used which supports this.
Fix, Java code side (SHA256 for both digests):
RSAPublicKey publicKey = ...
OAEPParameterSpec oaepParameterSpec = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParameterSpec);
byte[] ciphertext = cipher.doFinal(plaintext);
Fix, C# code side, using BouncyCastle (SHA256 for OAEP digest, SHA1 for MGF1 digest):
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Parameters;
...
RsaKeyParameters privateKey = ...
OaepEncoding oaepEncoding = new OaepEncoding(new RsaEngine(), new Sha256Digest(), new Sha1Digest(), null);
oaepEncoding.Init(false, privateKey);
byte[] decrypted = oaepEncoding.ProcessBlock(ciphertext, 0, ciphertext.Length);
I'm trying to encrypt a string given a public key that I've retrieved from an API. The public key is plain text (base 64 encoded), something like:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCH9/o5IG0tu9VNYiJSltzV5ewK9TNoLeToSYkoH4lEytRM61AMeO6aBRZ3dsY1Czb+fgK6Q+M4ub/9jbcXIGmVLvTypdn+VW1dotXzMP5sfDgCUuhScjH7gqsXQAvaF5LxjLUbL5I5zCGXbPVwBCEyVhN0oNp3TtNKoMcF6AjNhwIDAQAB
I now want to encrypt a string using this public key. I've found some relevant code that reads from a PEM format, but obviously it won't work here:
byte[] dataToEncrypt = Encoding.UTF8.GetBytes(aString);
var encryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(key))
{
var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject();
encryptEngine.Init(true, keyParameter);
}
var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(dataToEncrypt, 0, dataToEncrypt.Length));
keyParameter ends up being null. The documentation for Bouncycastle seems to be pretty scant, I don't really have an idea of what I should be using to get the right AsymmetricKeyParameter type.
I suppose I could write a PEM file from the key but feels a bit wasteful.
So the broader question is: How do I encrypt using PKSC1 padding when I have the public key as a string already?
The more precise question is: What AsymmetricKeyParameter type should I be using?
Thanks in advance.
EDIT
I've found a workaround using the native RSACryptoServiceProvider here. Still, would be good to know how to do this with BC.
This is a duplicate of an unanswered question here: Using an RSA Public Key to decrypt a string that was encrypted using RSA Private Key
You can see the author found a solution using some code from here:
http://www.codeproject.com/KB/security/PrivateEncryption.aspx
Using code from that link looks very promising. The only thing missing is the padding. I typically use PKCS1.5 padding which is the default for OpenSSL RSA.
I know the answer to this question is very close. I know the only thing holding back decryption is the pkcs1.5 padding on the encrypted openssl ciphertext.
I was surprised to see how little information is out there on this subject because there are many situations where you would need a server to encrypt something, sign something, etc, and have a client application verify, decrypt, etc with the public key.
I also extensively tried using the RSACryptoServiceProvider to verify hash's resulting from the encryption using OpenSSL. For example, I would do a private key encryption using a SHA256 hash of the plaintext, then try to do a RSACryptoServiceProvider verify on that signature, and it does not work. I think the way MS does this is non standard and there are perhaps special customization at work with that.
So, the alternative is this question, which is simply taking private key encrypted ciphertext and using C# to decrypt it, thus, verifying it's authenticity. Hashes can be incorporated to make a simple signature verification system for data objects signed by the server and verified on the client.
I've looked through the PKCS1 RFC's, OpenSSL rsa source code, and other projects, I cannot get a solid answer on how to account for PKCS1 padding when doing my RSA Decrypt. I cannot locate where in the OpenSSL source code they handle the PKCS1 padding, otherwise, I might have an answer by now.
Also, this is my first question, I know it's a duplicate of an unanswered question, so, what to do? I googled that too, and found nothing.
The other thing I don't understand is why my decrypt method doesn't work. Since padding is removed after decryption, my decrypted data should resemble plaintext, and it's not even close. So, I'm almost sure that pkcs1 padding means that other things are happening, specifically, to the ciphertext which means that the ciphertext must be preprocessed prior to decryption to remove padding elements.
Perhaps simply filtering the ciphertext to remove padding elements is the simplest solution here...
Here is my Decrypt method:
public static byte[] PublicDecryption(this RSACryptoServiceProvider rsa, byte[] cipherData)
{
if (cipherData == null)
throw new ArgumentNullException("cipherData");
BigInteger numEncData = new BigInteger(cipherData);
RSAParameters rsaParams = rsa.ExportParameters(false);
BigInteger Exponent = GetBig(rsaParams.Exponent);
BigInteger Modulus = GetBig(rsaParams.Modulus);
BigInteger decData = BigInteger.ModPow(numEncData, Exponent, Modulus);
byte[] data = decData.ToByteArray();
byte[] result = new byte[data.Length - 1];
Array.Copy(data, result, result.Length);
result = RemovePadding(result);
Array.Reverse(result);
return result;
}
private static byte[] RemovePadding(byte[] data)
{
byte[] results = new byte[data.Length - 4];
Array.Copy(data, results, results.Length);
return results;
}
The problem isn't with the padding. In fact, removing padding values from decrypted ciphertext is actually very simple. The problem was with the software at this location:
You can see the author found a solution using some code from here: http://www.codeproject.com/KB/security/PrivateEncryption.aspx
And with Microsoft's implementation of System.Numeric which simply cannot handle larger integers...
To fix the issue, I looked at previous releases of code on the codeproject site and ended up with this PublicDecrypt method.
public static byte[] PublicDecryption(this RSACryptoServiceProvider rsa, byte[] cipherData)
{
if (cipherData == null)
throw new ArgumentNullException("cipherData");
BigInteger numEncData = new BigInteger(cipherData);
RSAParameters rsaParams = rsa.ExportParameters(false);
BigInteger Exponent = new BigInteger(rsaParams.Exponent);
BigInteger Modulus = new BigInteger(rsaParams.Modulus);
BigInteger decData2 = numEncData.modPow(Exponent, Modulus);
byte[] data = decData2.getBytes();
bool first = false;
List<byte> bl = new List<byte>();
for (int i = 0; i < data.Length; ++i)
{
if (!first && data[i] == 0x00)
{
first = true;
}
else if (first)
{
if (data[i] == 0x00)
{
return bl.ToArray();
}
bl.Add(data[i]);
}
}
if (bl.Count > 0)
return bl.ToArray();
return new byte[0];
}
That will perfectly decrypt ciphertext created by openssl using the rsautl utility, or the Perl Crypt::OpenSSL::RSA private_encrypt method.
The other big change was dropping the Microsoft BitInteger library which simply didn't work. I ended up using the one mentioned in the Code Project article , and found here:
http://www.codeproject.com/Articles/2728/C-BigInteger-Class
The key here is to set the maxintsize in the library to a value which is larger based on how big of a key size you are using. For 4096 bit, a value of 500 worked fine (approx length of the modulus).
Here is the calling method:
var encmsg3 = "JIA7qtOrbBthptILxnurAeiQM3JzSoi5WiPCpZrIIqURKfVQMN1BrondF9kyNzbjTs1DaEKEuMBVwKExZe22yCvXXpm8pwcEGc9EHcVK2MPqNo89tIF8LJcaDqBMwLvxdaa/QgebtpmOVN/TIWfuiV8KR+Wn07KwsgV+3SALbNgbOIR3RtCx3IiQ3tZzybJb08+ZKwJEOT011uwvvGmtJskQgq9PC8kr1RPXMgaP6xMX7PHFJ8ORhkuWOFfCh+R4NhY1cItVhnRewKpIC2qVlpzUYRAgKIKdCXuZDqUQdIponR29eTovvLb0DvKQCLTf9WI1SzUm6pKRn0vLsQL7L3UYHWl43ISrTpDdp+3oclhgRF3uITR4WCvoljephbGc6Gelk5z3Vi6lN0oQaazJ7zIen+a/Ts7ZX3KKlwPl4/lAFRjdjoqu7u4IAK7O7u1Jf2xDiGw18C/eGt8UHl09zU4qQf9/u+7gtJ+10z2NERlLSaCDjVqslwmmxu81pG2gCv8LfpR4JlPaFfBZMGfGBihyGryWhJwizUXXo8wgdoYbHRXe8/gL19qro0ea5pA9aAhDjTpX1Zzbwu2rUU7j6wtwQtUDJOGXXCw1VOHsx6WXeW196RkqG72ucVIaSAlx5TFJv8cnj6werEx1Ung5456gth3gj19zHc8E/Mwcpsk=";
byte[] enc = Convert.FromBase64String(encmsg3);
var dec = rsa2.PublicDecryption(enc);
Debug.Print("PLAINTEXT: " + Encoding.UTF8.GetString(dec));
The only last thing someone would need to completely replicate this would be getting the private key into openssl format so that they could pass the private and public keys back and forth between openssl and C#.
I used openssl.net, and created an RSA instance, and set all the variables using bignumbers. Here's the code for that:
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(Properties.Resources.RSAParameters);
RSAParameters par = rsa.ExportParameters(true); // export the private key
using (OpenSSL.Crypto.RSA rsaos = new OpenSSL.Crypto.RSA())
using (BigNumber bnmod = BigNumber.FromArray(par.Modulus))
using (BigNumber bnexp = BigNumber.FromArray(par.Exponent))
using (BigNumber bnD = BigNumber.FromArray(par.D))
using (BigNumber bnP = BigNumber.FromArray(par.P))
using (BigNumber bnQ = BigNumber.FromArray(par.Q))
using (BigNumber bnDmodP = BigNumber.FromArray(par.DP))
using (BigNumber bnDmodQ = BigNumber.FromArray(par.DQ))
using (BigNumber bnInverse = BigNumber.FromArray(par.InverseQ))
{
rsaos.PublicExponent = bnexp;
rsaos.PublicModulus = bnmod;
rsaos.IQmodP = bnInverse;
rsaos.DmodP1 = bnDmodP;
rsaos.DmodQ1 = bnDmodQ;
rsaos.SecretPrimeFactorP = bnP;
rsaos.SecretPrimeFactorQ = bnQ;
rsaos.PrivateExponent = bnD;
string privatekey = rsaos.PrivateKeyAsPEM;
string publickey = rsaos.PublicKeyAsPEM
}
With that you can easily create an RSA key, export everything to OpenSSL, and encrypt/decrypt anything you want within reason. It is enough to handle private key encryption followed by public key decryption.
Cool.
There is a problem in the line in the PublicDecryption function:
BigInteger numEncData = new BigInteger(cipherData);
it shall be:
BigInteger numEncData = GetBig(cipherData);
This line shall also be removed:
Array.Reverse(result);
You may encounter some padding problem, but if you can get the data right, it shall be easy to correct that.
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.
I have been given a Base64 Encoded encrypted string, which was encrypted in Java using Bouncy Castle. Example Java snippet below:
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key.getPublic());
byte[] encryptedText = cipher.doFinal("xxxxx|xxxxx".getBytes("UTF-8"));
String encodedText = new BASE64Encoder().encode(encryptedText);
I need to decrypt the resulting string using Bouncy Castle, but in C#
I have been given a code snippet on how to do this in Java, but I can't convert this for C# (reasons is we are building a .net site, and is going to be an iFrame within a Java site. The Java site is going to passing in the RSA Encrypted string to the .NET site). Example Java code to decrypt below:
Cipher cipherDec = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipherDec.init(Cipher.DECRYPT_MODE, key.getPrivate());
byte[] decodedText = new BASE64Decoder().decodeBuffer(encodedText);
byte[] decryptedText = cipherDec.doFinal(decodedText);
String finalValue = new String(decryptedText, "UTF-8");
I have downloaded the examples from http://www.bouncycastle.org/csharp/ but there doesn't seem to be an example of inputting a string value to get encrypted, and it then going though the encrypt/decrypt process.
I have been given values for modulus, public exponent, private expontent, prime P, prime q, prime exponent p, prime exponent q and crt coefficient.
I have seen that I can use the following:
IAsymmetricBlockCipher signer = new Pkcs1Encoding(new RsaEngine());
signer.Init(true, pubParameters);
But the signer object doesn't seem to have the same methods as the Java examples above.
Only method I can use is
ProcessBlock(byte[] inbuf, int inOff, int inLen);
But I can't see how to use this in my context.
Any help here would be most appreciated.
To Help others, the final code to convert is as follows:
RsaKeyParameters privParameters = new RsaPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef);
RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod, pubExp);
IAsymmetricBlockCipher eng = new Pkcs1Encoding(new RsaEngine());
eng.Init(false, privParameters);
byte[] encdata = System.Convert.FromBase64String("{the enc string}");
encdata = eng.ProcessBlock(encdata, 0, encdata.Length);
string result = Encoding.UTF8.GetString(encdata);
mod, pubExp etc etc are all BigInteger values:
static BigInteger mod = new BigInteger("big int value");
The Following using directives are required:
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Math;
Which can be obtained from the bouncycastle site. http://www.bouncycastle.org/csharp/
Have you tried converting the base 64 string to a byte array and then using the process block method? There may be more to it than that but it's definitely the first step I would take.
Here's an example of how to do this: http://msdn.microsoft.com/en-us/library/system.convert.frombase64string.aspx
I'm not sure I understand why you must use Bouncycastle. The following small code snippet shows and RSA encryption/decryption example using only .NET classes:
using System;
using System.Text;
using System.Security.Cryptography;
namespace RsaForDotNet
{
class Program
{
static void Main(string[] args)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512);
var encrypted_msg = rsa.Encrypt(Encoding.UTF8.GetBytes("Secret Data"), false);
var encoded_msg = Convert.ToBase64String(encrypted_msg);
Console.WriteLine(encoded_msg);
var decoded_msg = Convert.FromBase64String(encoded_msg);
var decrypted_msg = Encoding.UTF8.GetString(rsa.Decrypt(decoded_msg, false));
Console.WriteLine(decrypted_msg);
}
}
}