I want functions for import/export PEM/DER strings in C#. I'm using RSA on python and C# but i had no solution who worked fine beetween both language. After many many tries and many research, i finally found an solution who working for read PEM public key. The following code works :
// pubkey is the PEM file without header/footer and encoded base64
Asn1Object obj = Asn1Object.FromByteArray(pubkey_bytes);
DerSequence publicKeySequence = (DerSequence)obj;
DerSequence publicKey = (DerSequence)Asn1Object.FromByteArray(publicKeySequence.GetEncoded());
DerInteger modulus = (DerInteger)publicKey[0];
DerInteger exponent = (DerInteger)publicKey[1];
RsaKeyParameters keyParameters = new RsaKeyParameters(false, modulus.PositiveValue, exponent.PositiveValue);
RSAParameters parameters = DotNetUtilities.ToRSAParameters(keyParameters);
this code is inspired of a solution i found on StackOverflow. But when i'm trying to use the same solution for private key i have an exception "Spécified size too small". This error seems appears on the "InverseQ" line. Below the code i'm using :
// Private key encode base64 without header/footer
Asn1Object obj = Asn1Object.FromByteArray(privkey_bytes);
DerSequence privateKeySequence = (DerSequence)obj;
DerSequence privateKey = (DerSequence)Asn1Object.FromByteArray(privateKeySequence.GetEncoded());
DerInteger M = (DerInteger)privateKey[1];
DerInteger E = (DerInteger)privateKey[2];
DerInteger D = (DerInteger)privateKey[3];
DerInteger P = (DerInteger)privateKey[4];
DerInteger Q = (DerInteger)privateKey[5];
DerInteger DP = (DerInteger)privateKey[6];
DerInteger DQ = (DerInteger)privateKey[7];
DerInteger IQ = (DerInteger)privateKey[8];
var keyParameters = new RsaPrivateCrtKeyParameters(M.PositiveValue,
E.PositiveValue, D.PositiveValue, P.PositiveValue, Q.PositiveValue,
DP.PositiveValue, DQ.PositiveValue, IQ.PositiveValue);
RSAParameters parameters = DotNetUtilities.ToRSAParameters(keyParameters); // Exception here !
I tried also this code from another StackOverflow post, for fix padding issues, but it's not my problem here :
RSAParameters parameters = new RSAParameters();
parameters.Modulus = M.PositiveValue.ToByteArrayUnsigned();
parameters.Exponent = E.PositiveValue.ToByteArrayUnsigned();
parameters.P = P.PositiveValue.ToByteArrayUnsigned();
parameters.Q = Q.PositiveValue.ToByteArrayUnsigned();Modulus.Length);
parameters.DP = ConvertRSAParametersField(DP.PositiveValue, parameters.P.Length);
parameters.DQ = ConvertRSAParametersField(DQ.PositiveValue, parameters.Q.Length);
parameters.InverseQ = ConvertRSAParametersField(IQ.PositiveValue, parameters.Q.Length);
public static RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters privKey)
{
RSAParameters rp = new RSAParameters();
rp.Modulus = privKey.Modulus.ToByteArrayUnsigned();
rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned();
rp.P = privKey.P.ToByteArrayUnsigned();
rp.Q = privKey.Q.ToByteArrayUnsigned();
rp.D = ConvertRSAParametersField(privKey.Exponent, rp.Modulus.Length);
rp.DP = ConvertRSAParametersField(privKey.DP, rp.P.Length);
rp.DQ = ConvertRSAParametersField(privKey.DQ, rp.Q.Length);
rp.InverseQ = ConvertRSAParametersField(privKey.QInv, rp.Q.Length); // Exception HERE
return rp;
}
private static byte[] ConvertRSAParametersField(BigInteger n, int size)
{
byte[] bs = n.ToByteArrayUnsigned();
if (bs.Length == size)
return bs;
if (bs.Length > size) // HERE
throw new ArgumentException("Specified size too small", "size");
byte[] padded = new byte[size];
Array.Copy(bs, 0, padded, size - bs.Length, bs.Length);
return padded;
}
My private key is generated by python and i think it a normal key :
-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCUkUk/vvyTI3begsdjz7eQVchjMTYMTyqt8HHHSXYXY2GrQCZS
VfBVxFLmx19brgMdLrKO93CjJWt+ACXAaLHmuGCsvNgGjCFqgg4XxM4Xamt9PeOc
F8HhMH7iS3OcgybQuu9GrekZB0yL2L9GVpyVrXpVlVHi4gBVjUr80e5LUwIDAQAB
AoGAGgK9wk1bxx8EZrya0BzD1J9QMB2jitApdr6MDQoNhNa/eM4IZ43oP/vZT9JE
Hbb/kJJmbKVhsQ6SHUNFO6qJA0FWYNqEA1xsTtat3RXAB/WCExxW9GwDG6pEXjK8
OrJFbKyIOhmqy3sBib9V76ROYsMi7Gioih8vtYKz8NFBiZECRQCmOHzCqEbsWJnK
5JUsUG8DyR3wg8mzi98m1qYGz3hsuBJMCW2M/QBSgyWGdDxExbQMcTb9lmTelq4W
sHbZLQ3FVxJsbwI9AOTP4ZCLDnzblroQjiUCW1vbVE6YnoO0YTb67Dj/g9CNOZpz
E0lJ3boUlg6lOEpDdwKxSswXhQU53OMJXQJFAKC+BaB0/Uk4EVnNHZkiG4lsp2Bd
AeR4wg8cCqiRYCK7Cy6u+1sZm4Mvwk05AMN88TYLEiO/mcJLswTMF9LDqAqLvoxP
AjxDmlPXo+4k37AZyzhkIN0jN5siGZ+D5DBw0RQoBv5ICOHDC0rgdW2IQ/rN2uzV
rDcmWYFy6WQI1j636ZUCRHWmzCi6ymkcUnqwlYXsjbZSVM7njOc3sJyVhaOgqs+o
1Zjbtpqq7DYEBHPFizh/nu6kf4lT3w5+vIKGs8r4k2IUMcJi
-----END RSA PRIVATE KEY-----
I have a doubt about the order of the parameters returned by "Asn1Object.FromByteArray()". I noticied the [0] was just a "0", that means empty for me. The length is 9 so it seems to be the good way, i'm just not sure about in which order they are returned. Tried to find some documentation but i found nothing.
Thanks in advance for people gonna help me
EDIT
First, i want to say my goal is to get a RSAParameters object.
As suggered by someone who deleted his post, i changed
rp.InverseQ = ConvertRSAParametersField(privKey.QInv, rp.Q.Length);
to
rp.InverseQ = ConvertRSAParametersField(privKey.QInv, rp.P.Length);
but after doing it, i got an exception System.Security.Cryptography.CryptographicException who telling me "Incorrect data." on the line
var csp = new RSACryptoServiceProvider(); // my csp object is already defined somewhere else but it change nothing
csp.ImportParameters(parameters); // Exception here, he doesn't like my object who doesn't seems valid for him.
The real problem seems to be "why my object is rejected by RSACryptoServiceProvider.ImportParameters()