Load RSA public key from RSAParams - c#

I have a requirement to generate RSA key pair in C# and then store public key in the database to be used in JWK format later on.
But I am unable to get the string from the RSAParams.Modulus.
I have tried UTF8,UTF32 and general encoding but still it is not showing.
Here is the code below from MSDN site.
try
{
// Create a new RSACryptoServiceProvider object.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Export the key information to an RSAParameters object.
//Pass false to export the public key information or pass
//true to export public and private key information.
RSAParameters RSAParams = RSA.ExportParameters(true);
byte[] modulus = RSAParams.Modulus;
var str = System.Text.Encoding.UTF8.GetString(RSAParams.Modulus);
Console.WriteLine(str);
Console.ReadKey();
}
}
catch (CryptographicException e)
{
//Catch this exception in case the encryption did
// not succeed.
Console.WriteLine(e.Message);
}
Thank you.

I assume that you want your output to be base64. Then you can use Convert.ToBase64String to convert the Exponent and the Modulus parts of the RSA key:
var exponent = Convert.ToBase64String(rsaParams.Modulus);
var modulus = Convert.ToBase64String(rsaParams.Exponent);
That is the same thing that your solution in the comments does (see source code of .ToXmlString) but it does require the detour over XML.

Related

How to generate CSR with Public Key exponent and modulus only using CertificateRequest in C#

Trying to generate a CSR. so I only have public key exponent and modulus since the private key is in HSM.
So i generate an RSA object to pass CertificateRequest.
public static RSA GetRsaPublicKey(byte[] modulus, byte[] exponent)
{
RSA rsa = RSA.Create();
RSAParameters keyInfo = new RSAParameters
{
Modulus = modulus,
Exponent = exponent
};
rsa.ImportParameters(keyInfo);
return rsa;
}
But when calling CreateSigningRequest() or CreateSelfSigned() methods it throws exception:
Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException:
'Key does not exist.'
The tried to use this overload CertificateRequest(X500DistinguishedName, PublicKey, HashAlgorithmName).
But unable to construct PublicKey 2nd argument.
I then found this method but getting this error:
var gen = X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1);
var req = new CertificateRequest(new X500DistinguishedName(subject), gen.PublicKey, HashAlgorithmName.SHA256);
var bytes = req.CreateSigningRequest();//exception thrown
This method cannot be used since no signing key was provided via a
constructor, use an overload accepting an X509SignatureGenerator
instead.
Any help plz? on how to create a CSR without private key.
Certification Signing Requests contain the public key, but they are signed with the private key to prove that the private key holder authorized the options included in the request.
If you know that the CA you are sending the request to isn’t going to verify the signature, you could make a custom X509SignatureGenerator that produces the right algorithm identifier, but just writes a gibberish signature.
Thanks for the help #bartonjs.
Here is my solution that worked based on this: https://source.dot.net/#System.Security.Cryptography/System/Security/Cryptography/X509Certificates/X509SignatureGenerator.cs
public class CustomX509SignatureGenerator : X509SignatureGenerator
{
private readonly byte[] publicKey;
public CustomX509SignatureGenerator(byte[] publicKey)
{
this.publicKey = publicKey;
}
protected override PublicKey BuildPublicKey()
{
Oid oid = new Oid("1.2.840.113549.1.1.1");
// The OID is being passed to everything here because that's what X509Certificate2.PublicKey does.
return new PublicKey(
oid,
// Encode the DER-NULL even though it is OPTIONAL, because everyone else does.
//
// This is due to one version of the ASN.1 not including OPTIONAL, and that was
// the version that got predominately implemented for RSA. Now it's convention.
new AsnEncodedData(oid, stackalloc byte[] { 0x05, 0x00 }),
new AsnEncodedData(oid, this.publicKey));
}
// https://source.dot.net/#System.Security.Cryptography/Oids.cs,2f70bfb7d65ebf89,references
public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlgorithm)
{
var oid = "1.2.840.113549.1.1.11";
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
writer.PushSequence();
writer.WriteObjectIdentifier(oid);
writer.WriteNull();
writer.PopSequence();
return writer.Encode();
}
// Gibberish
public override byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm)
{
return new byte[2] { 0xAA, 0xBB };
}
}
// then call
var csrBytes = req.CreateSigningRequest(new CustomX509SignatureGenerator(rsa.ExportRSAPublicKey()));

OAEP padding with CreateSignature

I have some code that creates a digital signature. The message as well as the signature is passed from one system to another. When its received, the signature is verified. This code has been run through Fortify, a service that analyzes code for security vulnerabilities. Fortify is reporting that "The method CreateDigitalSignature() in RSACryptography.cs performs public key RSA encryption without OAEP padding".
I see a parameter on the RSACryptoServiceProvider.Encrypt() method that if true, means to use OAEP padding. But I'm not using Encrypt(). I'm using a RSAPKCS1SignatureFormatter to generate and a RSAPKCS1SignatureDeformatter to verify the signature. So my question is how do I add the padding? Am I supposed to Encrypt the signature before sending it back? See my code where I have marked "IS WHAT I NEED TO DO" where I have added Encrypt and Decrypt calls. Is that what I need to do or something else?
// create a digital signature
// returns true if successful. Also, the public key (as an xml string) that can be sent to the other party to verify messages sent
public bool CreateDigitalSignature(string msgToSend, out string publicKey, out string signature)
{
bool rc = false;
publicKey = null;
signature = null;
try
{
// get the hash of the message to send
byte[] hashValue = GetHashedBytes(msgToSend);
// Load or generate a public/private key pair.
// If it already exists in the key container it will be loaded, otherwise, a new key pair is created
CspParameters cp = new CspParameters();
cp.KeyContainerName = KeyStoreContainerName;
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(cp);
// get some info about the key:
CspKeyContainerInfo info = new CspKeyContainerInfo(cp);
//Create an RSAPKCS1SignatureFormatter object and pass it the RSACryptoServiceProvider to transfer the private key.
RSAPKCS1SignatureFormatter RSAFormatter = new RSAPKCS1SignatureFormatter(RSA);
// Set the hash algorithm
RSAFormatter.SetHashAlgorithm(hashAlgorithm); // "SHA256", "SHA1", etc.
//Create a signature for the hashed value of the data
byte[] signedHashValue = RSAFormatter.CreateSignature(hashValue);
// fortify says I need to use OAEP padding
// IS THIS WHAT I NEED TO DO? Encrypt the signature before I convert it to a string?
signedHashValue = RSA.Encrypt(signedHashValue, true);
// convert the signature to a string
signature = Convert.ToBase64String(signedHashValue);
// get the public key to return so it can be pased to the receiver and used to verify the signature
// There are two ways - either export the parameters or create an xml string
// Using export: This gets public key inforation only (specify true to get both public and private keys)
// RSAParameters RSAKeyInfo = RSA.ExportParameters(false);
// get a string value of the public key
publicKey = RSA.ToXmlString(false);
// demonstration only. how to get the private key
//string privateKey = RSA.ToXmlString(true);
rc = true;
}
catch (Exception ex)
{
throw ex;
}
return rc;
}
And then to verify the signature:
public bool VerifySignature(string origintalData, string publicKeyXml, string signature)
{
bool verified = false;
try
{
// get the hashed value of the original data. used the specified algoritm stored in the this class
byte[] hashValue = GetHashedBytes(origintalData);
// get a byte array of the signature
byte[] signaturebytes = Convert.FromBase64String(signature);
// create a crypto provider
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
// set the public key of the crypto service provider
RSA.FromXmlString(publicKeyXml);
// create a deformatter
RSAPKCS1SignatureDeformatter RSADeformatter = new RSAPKCS1SignatureDeformatter(RSA);
// set the hash algorithm. The sender must use the same algorithm
RSADeformatter.SetHashAlgorithm(hashAlgorithm);
// As per Fortify, need to use OAEP padding
// IS THIS WHAT i NEED TO DO - decrypt the signature before veryfying it?
signaturebytes = RSA.Decrypt(signaturebytes, true);
// verify the signature
verified = RSADeformatter.VerifySignature(hashValue, signaturebytes);
}
catch (Exception ex)
{
throw ex;
}
return verified;
}
Update:
After upgrading from .Net 4.5.1 to 4.6.1. I can use
byte[] signedHashValue = RSA.SignData(bytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)
and the corresponding method
RSA.VerifyData(System.Text.Encoding.UTF8.GetBytes(originalData), signaturebytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)
but I can't specify RSASignaturePadding.Pss. If I do I get an exception "Specified padding mode is not valid for this algorithm."
Also I get the same signature as before, so I feel I haven't really accomplished anything. No way to use AOEP padding?

Key not valid for use in specific state:Cryptographic Encryption and Decryption exception [duplicate]

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

Using an RSA Public key to decrypt a string that was encrypted using an RSA private key

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.

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