riki
riki

Reputation: 2393

Unable to generate public key from given mod and exp. Throws "Bad Data"

I wanted to know and understand the process to generate the JWE. I have given below details:

string mod = "2737"; // this is a 618 char long string constructed only with digits.

string exp = "65537";

string kid = "APIKEY.XX.665_Priv";

string keyEncAlgo = "RSA-OAEP";

string contentEncAlgo = "A256GCM";

And a payload in json format.

As with my limited knowledge in this field I proceeded with creating a public key using RSACryptoServiceProvider. And planned to use Jose.Jwt library.

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
RSAPaeameters rsaKeyInfo = new RSAPaeameters();
rsaKeyInfo.Modulus = Encode.ASCII.GetBytes(mod);
rsaKeyInfo.Exponent = Encode.ASCII.GetBytes(exp);
rsa.ImportParameters(rsaKeyInfo);

The last line in the above code rsa.ImportParameters(rsaKeyInfo) throws exception as bad data.

Although the same mod and exp being used in a Java app which eventually gets everything right. I am converting that Java code to C#. What I am doing here wrong. Or I have understood the process wrong.

Upvotes: 1

Views: 169

Answers (1)

Topaco
Topaco

Reputation: 49251

Modulus (assuming that 2737 is merely the beginning) and exponent appear to be decimal representations (as string).

Under .NET5+ (and .NET Core 2.1+) these can be imported as follows:

using System.Numerics;
using System.Security.Cryptography;
...
string mod = "2737...";
string exp = "65537";
var rsaPublic = new RSACryptoServiceProvider();
rsaPublic.ImportParameters(new RSAParameters
{
    Modulus = BigInteger.Parse(mod).ToByteArray(true, true),
    Exponent = BigInteger.Parse(exp).ToByteArray(true, true)
});

Note that the byte arrays are unsigned (1st true) and with big endian byte order (2nd true).


An example of JWE with jose-jwt is:

using Jose;
using System.Collections.Generic;
...
IDictionary<string, object> addHeaders = new Dictionary<string, object>()
{
    { "kid", "APIKEY.XX.665_Priv" },
};

string payload = "some string";
string token = JWT.Encode(payload, rsaPublic, JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM, null, addHeaders);

with the following header (if Base64 decoded):

{
    "alg":"RSA-OAEP",
    "enc":"A256GCM",
    "kid":"APIKEY.XX.665_Priv"
}

Upvotes: 2

Related Questions