I have a json web key(https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key-41) and I want to use it to sign some data with the private key and then later verify it with the public key. I am using c# with .net framework 4.5.1 and I can't seem to instantiate the classes properly using the keys I have. I generated the keys using this tool: https://github.com/mitreid-connect/json-web-key-generator. The following json is available and from this I should be able to sign and verify:
{
"kty": "RSA",
"d": "rZ_cdME7usL5EavJW1q0cjz8dhfdO9P-E4dacHYFf4I-TN7o-Q0ksfWCb4fpQPghUoz6v2b6-m3IZk4CocmdEAoFH2JqI0PbH5HIBqgva-bE8-elNJIKwza0Hbrw13bRU6KgpOrc9hrX-NcRCTkeKHYtDWGUa2NDB_lNQvkyg-V0NVXf5oSa_cZ9_H4kHPXrzcBeQapn2M_CFb3qfYgVgQb5xU5n67eAcSlztWHIaSaLyu_YAR0SxnEAvWiik1rtSYrEOWsVrPHfHBFwVHluP0g--bedH6kI3mZRI6H_UbmTMnRtxBkCA5mVdzOmsyX2e98MUqIlOeDQ4zB21xSDQQ",
"e": "AQAB",
"use": "sig",
"alg": "RS512",
"n": "xwHPJaSvKvLqrqb6oeXDL3A4iNgRo5PEQOQCE5zGa6ZWeoC88IuJZxXFJ93wzJk0J22QZJWofC8vV8GAeB3d9mD25koh0dbtb0yoWK-ttWamMIAN4WPiZu30JWzxY1k8LRzOz5lIT9Ze87gV_lgXbpkzQzKFNhxOmV_BhEu1PCLcOTHhic93WQk_E97nYCOwOifmkEFOCBzHEuTG1XHJ1nGEfBCAsdUXrMg_lU3w86TfVDYS6xLVtfVAq4ihDjBsmtPthrdMG4H5Qls8EM-_cbIRe7UEAQK9MgXDLHaQZbx_lQ46_P852SpCprbvqWaoM8zKyEiDf1q6O89D6YIaDw"
}
Then in C# I have a model with those fields and I made a function to test if I can verify data:
public class RSAKeyPair
{
public string kty { get; set; }
public string e { get; set; }
public string use { get; set; }
public string alg { get; set; }
public string n { get; set; }
public string d { get; set; }
}
And the test code:
public static bool TestSigning(RSAKeyPair keySet)
{
if (keySet.alg != "RS512")
{
throw new ArgumentException("Only RS512 is supported.");
}
var oid = CryptoConfig.MapNameToOID("SHA512");
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider();
rsaProvider.ImportParameters(
new RSAParameters()
{
Modulus = FromBase64Url(keySet.n),
Exponent = FromBase64Url(keySet.e),
D = FromBase64Url(keySet.d)
}
);
var hasher = SHA512.Create();
var testmsg = System.Text.Encoding.UTF8.GetBytes("TestMsg");
var hash = hasher.ComputeHash(new MemoryStream(testmsg));
var signedData = rsaProvider.SignHash(hash, oid);
var isSigned = rsaProvider.VerifyHash(hash, oid, signedData);
return isSigned;
}
private static byte[] FromBase64Url(string base64Url)
{
string padded = base64Url.Length % 4 == 0
? base64Url : base64Url + "====".Substring(base64Url.Length % 4);
string base64 = padded.Replace("_", "/")
.Replace("-", "+");
var s = Convert.FromBase64String(base64);
return s;
}
However when I run it. I get the System.Security.Cryptography.CryptographicException
with the message Object contains only the public half of a key pair. A private key must also be provided.
when trying to get the signedData
I have no idea which parameters to set because this seems correct according to what I understand from RSA and reading the docs.
I have also tried to create two instances of the RSACryptoServiceProvider
One signer with Exponent = keySet.d
and one verifier with Exponent = keySet.e
. But when I call RSACryptoServiceProvider.ImportParameters
for the signer it throws a Bad data
exception.
Any help is appreciated.