Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keys used with the ECDsaCng algorithm must have an algorithm group of ECDsa

I have the following problem, and cant find solution:

While consuming APN (Apple push notifications) API, i implemented tokenized authorization. It's apple's new way of authorization on their push notifications api.

Apple provides me private key, which i use to create c# CngKey object, which then i use to sign data.

    CngKey key = CngKey.Import(
       Convert.FromBase64String(privateKey),
       CngKeyBlobFormat.Pkcs8PrivateBlob);

using (ECDsaCng dsa = new ECDsaCng(key))
{
    dsa.HashAlgorithm = CngAlgorithm.Sha256;
    var unsignedJwtData =
        Url.Base64urlEncode(Encoding.UTF8.GetBytes(header)) + "." + Url.Base64urlEncode(Encoding.UTF8.GetBytes(payload));
    var signature =
        dsa.SignData(Encoding.UTF8.GetBytes(unsignedJwtData));
    return unsignedJwtData + "." + Url.Base64urlEncode(signature);
}

The result is signed token, which i then use as authorization header while consuming API and sending push notifications.

It works well on my dev machine, but when i deploy it to Windows Server, when this code runs i get next:

System.ArgumentException: Keys used with the ECDsaCng algorithm must have an algorithm group of ECDsa.
Parameter name: key
   at System.Security.Cryptography.ECDsaCng..ctor(CngKey key)
   at OTTCommon.Encryption.ECDSA.SignES256(String privateKey, String header, String payload, ILog log)

I cant find solution, it is something with windows key storage or something like that....

What should i do?

like image 862
MIslavMIslav Avatar asked May 15 '17 13:05

MIslavMIslav


1 Answers

This is fixed in the .NET Framework 4.6.2, so the easiest solution would perhaps be to get the server upgraded.

A workaround that works for NIST P-256, NIST P-384, and NIST P-521 is to change the dwMagic value in the blob export. (It won't work for the Windows 10 Generic ECC, because the dwMagic values aren't aligned the same way).

byte[] blob = key.Export(CngKeyBlobFormat.EccPrivateBlob);
key.Dispose();

The first 4 bytes of this blob map to the dwMagic value in the BCRYPT_ECCKEY_BLOB structure.

BCRYPT_ECDH_PRIVATE_P256_MAGIC has value 0x324B4345, which is the Little-Endian representation of "ECK2" (Elliptic Curve Key-exchange 2). BCRYPT_ECDSA_PRIVATE_P256_MAGIC has value 0x32534345, which is the Little-Endian representation of "ECS2" (Elliptic Curve Signing 2).

// Change it from Key-exchange (ECDH) to Signing (ECDSA)
blob[1] = 0x53;

key = CngKey.Import(blob, CngKeyBlobFormat.EccPrivateBlob);

And now it sees that it's an ECDSA key, and everything is happy.

like image 71
bartonjs Avatar answered Oct 22 '22 17:10

bartonjs