1

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()

Benjamin K
  • 296
  • 1
  • 2
  • 15
  • 1
    [This](http://stackoverflow.com/a/251757/1816580) and [this](http://stackoverflow.com/a/32243171/1816580) seems to be capable of decoding a PKCS#1-encoded RSA private key. Have you tried it? – Artjom B. May 07 '17 at 11:56
  • The first link is for "decrypt" directly when i need to get an RSAParameters() (i'm doing an "RSA Software" (for myself) who have to display every parameters of the private key). The second link was the code i used just before but, It didn't worked for public key and some private keys generated by python was not working. – Benjamin K May 07 '17 at 12:12
  • Since there is an exception, please add it to your question. My answer is just a guess. – Artjom B. May 07 '17 at 12:35
  • 1
    Why do you need to use `ConvertRSAParametersField` at all? Shouldn't `ToByteArrayUnsigned()` work for each property? – Artjom B. May 07 '17 at 12:55
  • I used this code because he came from someone who seems to know the RSA better than me. But i already tried w/o this function, directly with ToByteArrayUnsigned() (as i tried also to ignor the size exception / resize the byte array) => every case i have an exception during the last parameters (InvQ). I updated my post with the exception. The real problem seems to be "why my object is rejected by RSACryptoServiceProvider.ImportParameters()" – Benjamin K May 07 '17 at 13:04
  • Well it's working with every key generated by C# (Python & C# working) but if python generate the key i still have this error. I guess C# want the IQ.Length to be equals to Q.Length when python doesn't care. I guess the solution is to generate key from C#. If someone have a solution with the private key i provided, i'm up ! – Benjamin K May 07 '17 at 15:14
  • You said it yourself that the second link in my first comment properly parses the private key. I'm not sure what more you want. – Artjom B. May 07 '17 at 15:41
  • I said it worked for private key not generated from python. After many try, every key generated by python librairy failing. Both solution (your second link and mine) working for C# generated private keys. I guess the issues it was i said just before, C# doesn't accepts some kinds of private key who are not formated like he want. – Benjamin K May 07 '17 at 17:11
  • the document about your ASN1 sequence can be found here ... https://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptography-standard-wp.pdf ... bottom of page 41 ... regarding the csp rejecting the params, i might be wrong here, but doesn't BigInteger have another byteorder? try converting the Bigintergs with .ToByteArray().Reverse().ToArray() – DarkSquirrel42 May 12 '17 at 21:06

0 Answers0