System.Security.Cryptography.CryptographicException: запрошенная операция не поддерживается. виндовс сервер 2012

Я устал генерировать токен jwt для вызова apns. вот мой код:

    var header = new Dictionary<string, object>()
    {
        { "kid" , keyID }
    };
    var payload = new Dictionary<string, object>()
    {
        { "iss", teamID },
        { "iat", DateTimeOffset.Now.ToUnixTimeSeconds().ToString() }
    };

    var privateKey = GetApnsPrivateKey(authKeyPath);
    var token = JWT.Encode(payload, privateKey, JwsAlgorithm.ES256, header);
public static CngKey GetApnsPrivateKey(string authKeyPath)
{
    using (var reader = new StreamReader(new FileStream(authKeyPath, FileMode.Open, FileAccess.Read, FileShare.Read)))
    {
        var ecPrivateKeyParameters = (ECPrivateKeyParameters)new PemReader(reader).ReadObject();
        var x = ecPrivateKeyParameters.Parameters.G.AffineXCoord.GetEncoded();
        var y = ecPrivateKeyParameters.Parameters.G.AffineYCoord.GetEncoded();
        var d = ecPrivateKeyParameters.D.ToByteArrayUnsigned();
        return EccKey.New(x, y, d);

код работает на моей машине просто отлично, но на сервере это исключение для метода GetApnsPrivateKey:

System.Security.Cryptography.CryptographicException: The requested operation is not supported

после небольшого поиска на форумах я обнаружил, что это связано с поставщиками хранилища ключей CNG: https://msdn.microsoft.com/en-us/library/windows/desktop/aa376242.aspx?f=255&MSPPError=-2147217396 интересно, есть ли способ решить проблему?


person Mohammad    schedule 31.12.2017    source источник
comment
EccKey.New не является методом NetFx, так откуда он взялся / какова его реализация?   -  person bartonjs    schedule 02.01.2018
comment
привет дорогой @bartonjs. EccKey.New — это метод библиотеки криптографии. вот полный путь метода: Security.Cryptography.EccKey.New(x, y, d);   -  person Mohammad    schedule 02.01.2018


Ответы (2)


Источником исключения является библиотека System.Security.Cryptography внутри jose-jwt, поэтому избегайте ее. Поскольку здесь уже используется библиотека BouncyCastle, используйте ее для подписи. Кроме того, я использую Newtonsoft.Json.JsonConvert(..).

public string GetApnsToken(string authKeyPath,  
Dictionary<string, object> payload, 
Dictionary<string, object> header)
{
    ECPrivateKeyParameters ecPrivateKeyParameters;
    using (var reader = new StreamReader(new FileStream(authKeyPath, FileMode.Open, FileAccess.Read, FileShare.Read)))
    {
       ecPrivateKeyParameters = (ECPrivateKeyParameters)new PemReader(reader).ReadObject();
     }
     byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header));
     byte[] payloadBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload));
     byte[] bytesToSign = Encoding.UTF8.GetBytes(ConcatTokenPartsWithEncoding(headerBytes, payloadBytes));

   var signer = new DsaDigestSigner(new ECDsaSigner(), new Sha256Digest());
   signer.Init(true, ecPrivateKeyParameters);
   signer.BlockUpdate(bytesToSign, 0, bytesToSign.Length);
   byte[] signBytes = signer.GenerateSignature();

   return ConcatTokenPartsWithEncoding(headerBytes, payloadBytes, signBytes);

}

public static string ConcatTokenPartsWithEncoding(params byte[][] parts)
{
var builder = new StringBuilder();
foreach (var part in parts)
{
 //encode base64 for Url
 var base64Str = Convert.ToBase64String(part);
 base64Str = base64Str.Split('=')[0]; // Remove any trailing '='s
 base64Str = base64Str.Replace('+', '-'); 
 base64Str = base64Str.Replace('/', '_');
 builder.Append(base64Str).Append(".");
}
builder.Remove(builder.Length - 1, 1); 
return builder.ToString();
}
person Natalya    schedule 06.02.2018

Спасибо за пост Натальи. Я мог бы решить проблему следующим образом:

        var dateTime = DateTimeOffset.Now;
        var privateKeyAsBytes = Convert.FromBase64String(authKey);
        var privateKey = CngKey.Import(privateKeyAsBytes, CngKeyBlobFormat.Pkcs8PrivateBlob);
        var header = new Dictionary<string, object>() { { "kid", keyID } };
        var payload = new Dictionary<string, object>() { { "iss", teamID }, { "iat", dateTime.ToUnixTimeSeconds().ToString() } };
        var token = JWT.Encode(payload, privateKey, JwsAlgorithm.ES256, header);
person Mohammad    schedule 08.02.2018
comment
Привет, что такое authKey в этом примере? У меня тот же код, что и у вас, но я не знаю, как изменить то, что вы показали здесь. - person Shumii; 18.01.2021