< Summary

Class:Azure.Security.KeyVault.Keys.JsonWebKey
Assembly:Azure.Security.KeyVault.Keys
File(s):C:\Git\azure-sdk-for-net\sdk\keyvault\Azure.Security.KeyVault.Keys\src\JsonWebKey.cs
Covered lines:225
Uncovered lines:24
Coverable lines:249
Total lines:642
Line coverage:90.3% (225 of 249)
Covered branches:180
Total branches:200
Branch coverage:90% (180 of 200)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.cctor()-93.5%92.35%
get_Id()-100%100%
get_KeyType()-100%100%
get_KeyOps()-100%100%
.ctor()-100%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
get_N()-100%100%
get_E()-100%100%
get_DP()-100%100%
get_DQ()-100%100%
get_QI()-100%100%
get_P()-100%100%
get_Q()-100%100%
get_CurveName()-100%100%
get_X()-100%100%
get_Y()-100%100%
get_D()-100%100%
get_K()-100%100%
get_T()-100%100%
get_HasPrivateKey()-40%50%
ToAes()-100%100%
ToECDsa(...)-100%100%
ToECDsa(...)-100%100%
ToRSA(...)-100%100%
SupportsOperation(...)-100%100%
ReadProperties(...)-97.06%97.56%
WriteProperties(...)-97.06%96.88%
Azure.Security.KeyVault.IJsonDeserializable.ReadProperties(...)-100%100%
Azure.Security.KeyVault.IJsonSerializable.WriteProperties(...)-100%100%
ForceBufferLength(...)-46.67%58.33%
TrimBuffer(...)-25%50%
ValidateKeyParameter(...)-100%100%
Initialize(...)-100%50%
Convert(...)-82.76%91.67%

File(s)

C:\Git\azure-sdk-for-net\sdk\keyvault\Azure.Security.KeyVault.Keys\src\JsonWebKey.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.Collections.ObjectModel;
 7using System.Runtime.CompilerServices;
 8using System.Security.Cryptography;
 9using System.Text.Json;
 10using Azure.Core;
 11
 12namespace Azure.Security.KeyVault.Keys
 13{
 14    /// <summary>
 15    /// A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data
 16    /// structure that represents a cryptographic key.
 17    /// For more information, see <see href="http://tools.ietf.org/html/draft-ietf-jose-json-web-key-18">JSON Web Key (J
 18    /// </summary>
 19    public class JsonWebKey : IJsonDeserializable, IJsonSerializable
 20    {
 21        private const string KeyIdPropertyName = "kid";
 22        private const string KeyTypePropertyName = "kty";
 23        private const string KeyOpsPropertyName = "key_ops";
 24        private const string CurveNamePropertyName = "crv";
 25        private const string NPropertyName = "n";
 26        private const string EPropertyName = "e";
 27        private const string DPPropertyName = "dp";
 28        private const string DQPropertyName = "dq";
 29        private const string QIPropertyName = "qi";
 30        private const string PPropertyName = "p";
 31        private const string QPropertyName = "q";
 32        private const string XPropertyName = "x";
 33        private const string YPropertyName = "y";
 34        private const string DPropertyName = "d";
 35        private const string KPropertyName = "k";
 36        private const string TPropertyName = "key_hsm";
 37
 238        private static readonly JsonEncodedText s_keyTypePropertyNameBytes = JsonEncodedText.Encode(KeyTypePropertyName)
 239        private static readonly JsonEncodedText s_keyOpsPropertyNameBytes = JsonEncodedText.Encode(KeyOpsPropertyName);
 240        private static readonly JsonEncodedText s_curveNamePropertyNameBytes = JsonEncodedText.Encode(CurveNamePropertyN
 241        private static readonly JsonEncodedText s_nPropertyNameBytes = JsonEncodedText.Encode(NPropertyName);
 242        private static readonly JsonEncodedText s_ePropertyNameBytes = JsonEncodedText.Encode(EPropertyName);
 243        private static readonly JsonEncodedText s_dPPropertyNameBytes = JsonEncodedText.Encode(DPPropertyName);
 244        private static readonly JsonEncodedText s_dQPropertyNameBytes = JsonEncodedText.Encode(DQPropertyName);
 245        private static readonly JsonEncodedText s_qIPropertyNameBytes = JsonEncodedText.Encode(QIPropertyName);
 246        private static readonly JsonEncodedText s_pPropertyNameBytes = JsonEncodedText.Encode(PPropertyName);
 247        private static readonly JsonEncodedText s_qPropertyNameBytes = JsonEncodedText.Encode(QPropertyName);
 248        private static readonly JsonEncodedText s_xPropertyNameBytes = JsonEncodedText.Encode(XPropertyName);
 249        private static readonly JsonEncodedText s_yPropertyNameBytes = JsonEncodedText.Encode(YPropertyName);
 250        private static readonly JsonEncodedText s_dPropertyNameBytes = JsonEncodedText.Encode(DPropertyName);
 251        private static readonly JsonEncodedText s_kPropertyNameBytes = JsonEncodedText.Encode(KPropertyName);
 252        private static readonly JsonEncodedText s_tPropertyNameBytes = JsonEncodedText.Encode(TPropertyName);
 53
 254        private static readonly KeyOperation[] s_aesKeyOperation = { KeyOperation.Encrypt, KeyOperation.Decrypt, KeyOper
 255        private static readonly KeyOperation[] s_rSAPublicKeyOperation = { KeyOperation.Encrypt, KeyOperation.Verify, Ke
 256        private static readonly KeyOperation[] s_rSAPrivateKeyOperation = { KeyOperation.Encrypt, KeyOperation.Decrypt, 
 257        private static readonly KeyOperation[] s_eCPublicKeyOperation = { KeyOperation.Sign };
 258        private static readonly KeyOperation[] s_eCPrivateKeyOperation = { KeyOperation.Sign, KeyOperation.Verify };
 59
 60        private readonly IList<KeyOperation> _keyOps;
 61
 62        /// <summary>
 63        /// Gets the identifier of the key. This is not limited to a <see cref="Uri"/>.
 64        /// </summary>
 260465        public string Id { get; set; }
 66
 67        /// <summary>
 68        /// Gets the <see cref="KeyType"/> for this <see cref="JsonWebKey"/>.
 69        /// </summary>
 260270        public KeyType KeyType { get; set; }
 71
 72        /// <summary>
 73        /// Gets a list of <see cref="KeyOperation"/> values supported by this key.
 74        /// </summary>
 127475        public IReadOnlyCollection<KeyOperation> KeyOps { get; }
 76
 74477        internal JsonWebKey() : this(null)
 78        {
 74479        }
 80
 78481        internal JsonWebKey(IEnumerable<KeyOperation> keyOps)
 82        {
 78483            _keyOps = keyOps is null ? new List<KeyOperation>() : new List<KeyOperation>(keyOps);
 78484            KeyOps = new ReadOnlyCollection<KeyOperation>(_keyOps);
 78485        }
 86
 87        /// <summary>
 88        /// Initializes a new instance of the <see cref="JsonWebKey"/> class using type <see cref="KeyType.Oct"/>.
 89        /// </summary>
 90        /// <param name="aesProvider">An <see cref="Aes"/> provider.</param>
 91        /// <param name="keyOps">
 92        /// Optional list of supported <see cref="KeyOperation"/> values. If null, the default for the key type is used,
 93        /// <see cref="KeyOperation.Encrypt"/>, <see cref="KeyOperation.Decrypt"/>, <see cref="KeyOperation.WrapKey"/>, 
 94        /// </param>
 95        /// <exception cref="ArgumentNullException"><paramref name="aesProvider"/> is null.</exception>
 2096        public JsonWebKey(Aes aesProvider, IEnumerable<KeyOperation> keyOps = default)
 97        {
 2098            Argument.AssertNotNull(aesProvider, nameof(aesProvider));
 99
 20100            _keyOps = new List<KeyOperation>(keyOps ?? s_aesKeyOperation);
 20101            KeyOps = new ReadOnlyCollection<KeyOperation>(_keyOps);
 102
 20103            KeyType = KeyType.Oct;
 20104            K = aesProvider.Key;
 20105        }
 106
 107        /// <summary>
 108        /// Initializes a new instance of the <see cref="JsonWebKey"/> class using type <see cref="KeyType.Ec"/>.
 109        /// </summary>
 110        /// <param name="ecdsa">An <see cref="ECDsa"/> provider.</param>
 111        /// <param name="includePrivateParameters">Whether to include the private key.</param>
 112        /// <param name="keyOps">
 113        /// Optional list of supported <see cref="KeyOperation"/> values. If null, the default for the key type is used,
 114        /// <see cref="KeyOperation.Sign"/>, and <see cref="KeyOperation.Decrypt"/> if <paramref name="includePrivatePar
 115        /// </param>
 116        /// <exception cref="ArgumentNullException"><paramref name="ecdsa"/> is null.</exception>
 117        /// <exception cref="InvalidOperationException">The elliptic curve name is invalid.</exception>
 92118        public JsonWebKey(ECDsa ecdsa, bool includePrivateParameters = default, IEnumerable<KeyOperation> keyOps = defau
 119        {
 92120            Argument.AssertNotNull(ecdsa, nameof(ecdsa));
 121
 92122            _keyOps = new List<KeyOperation>(keyOps ?? (includePrivateParameters ? s_eCPrivateKeyOperation : s_eCPublicK
 92123            KeyOps = new ReadOnlyCollection<KeyOperation>(_keyOps);
 124
 92125            Initialize(ecdsa, includePrivateParameters);
 90126        }
 127
 128        /// <summary>
 129        /// Initializes a new instance of the <see cref="JsonWebKey"/> class using type <see cref="KeyType.Rsa"/>.
 130        /// </summary>
 131        /// <param name="rsaProvider">An <see cref="RSA"/> provider.</param>
 132        /// <param name="includePrivateParameters">Whether to include the private key.</param>
 133        /// <param name="keyOps">
 134        /// Optional list of supported <see cref="KeyOperation"/> values. If null, the default for the key type is used,
 135        /// <see cref="KeyOperation.Encrypt"/>, <see cref="KeyOperation.Verify"/>, and <see cref="KeyOperation.WrapKey"/
 136        /// and <see cref="KeyOperation.Decrypt"/>, <see cref="KeyOperation.Sign"/>, and <see cref="KeyOperation.UnwrapK
 137        /// </param>
 138        /// <exception cref="ArgumentNullException"><paramref name="rsaProvider"/> is null.</exception>
 116139        public JsonWebKey(RSA rsaProvider, bool includePrivateParameters = default, IEnumerable<KeyOperation> keyOps = d
 140        {
 116141            Argument.AssertNotNull(rsaProvider, nameof(rsaProvider));
 142
 116143            _keyOps = new List<KeyOperation>(keyOps ?? (includePrivateParameters ? s_rSAPrivateKeyOperation : s_rSAPubli
 116144            KeyOps = new ReadOnlyCollection<KeyOperation>(_keyOps);
 145
 116146            KeyType = KeyType.Rsa;
 116147            RSAParameters rsaParameters = rsaProvider.ExportParameters(includePrivateParameters);
 148
 114149            E = rsaParameters.Exponent;
 114150            N = rsaParameters.Modulus;
 151
 114152            D = rsaParameters.D;
 114153            DP = rsaParameters.DP;
 114154            DQ = rsaParameters.DQ;
 114155            P = rsaParameters.P;
 114156            Q = rsaParameters.Q;
 114157            QI = rsaParameters.InverseQ;
 114158        }
 159
 160        #region RSA Public Key Parameters
 161
 162        /// <summary>
 163        /// Gets the RSA modulus.
 164        /// </summary>
 978165        public byte[] N { get; set; }
 166
 167        /// <summary>
 168        /// Gets RSA public exponent.
 169        /// </summary>
 956170        public byte[] E { get; set; }
 171
 172        #endregion
 173
 174        #region RSA Private Key Parameters
 175
 176        /// <summary>
 177        /// Gets the RSA private key parameter.
 178        /// </summary>
 570179        public byte[] DP { get; set; }
 180
 181        /// <summary>
 182        /// Gets the RSA private key parameter.
 183        /// </summary>
 570184        public byte[] DQ { get; set; }
 185
 186        /// <summary>
 187        /// Gets the RSA private key parameter.
 188        /// </summary>
 570189        public byte[] QI { get; set; }
 190
 191        /// <summary>
 192        /// Gets the RSA secret prime.
 193        /// </summary>
 570194        public byte[] P { get; set; }
 195
 196        /// <summary>
 197        /// Gets the RSA secret prime.
 198        /// </summary>
 570199        public byte[] Q { get; set; }
 200
 201        #endregion
 202
 203        #region EC Public Key Parameters
 204
 205        /// <summary>
 206        /// Gets the name of the elliptical curve.
 207        /// </summary>
 1334208        public KeyCurveName? CurveName { get; set; }
 209
 210        /// <summary>
 211        /// Gets the X coordinate of the elliptic curve point.
 212        /// </summary>
 1050213        public byte[] X { get; set; }
 214
 215        /// <summary>
 216        /// Gets the Y coordinate for the elliptic curve point.
 217        /// </summary>
 1042218        public byte[] Y { get; set; }
 219
 220        #endregion
 221
 222        #region EC and RSA Private Key Parameters
 223
 224        /// <summary>
 225        /// Gets the RSA private exponent or EC private key.
 226        /// </summary>
 956227        public byte[] D { get; set; }
 228
 229        #endregion
 230
 231        #region Symmetric Key Parameters
 232
 233        /// <summary>
 234        /// Gets the symmetric key.
 235        /// </summary>
 462236        public byte[] K { get; set; }
 237
 238        #endregion
 239
 240        /// <summary>
 241        /// Gets the HSM token used with "Bring Your Own Key".
 242        /// </summary>
 390243        public byte[] T { get; set; }
 244
 245        internal bool HasPrivateKey
 246        {
 247            get
 248            {
 192249                if (KeyType == KeyType.Rsa || KeyType == KeyType.Ec || KeyType == KeyType.RsaHsm || KeyType == KeyType.E
 250                {
 192251                    return D != null;
 252                }
 253
 0254                if (KeyType == KeyType.Oct)
 255                {
 0256                    return K != null;
 257                }
 258
 0259                return false;
 260            }
 261        }
 262
 263        /// <summary>
 264        /// Converts this <see cref="JsonWebKey"/> of type <see cref="KeyType.Oct"/> to an <see cref="Aes"/> object.
 265        /// </summary>
 266        /// <returns>An <see cref="Aes"/> object.</returns>
 267        /// <exception cref="InvalidOperationException">This key is not of type <see cref="KeyType.Oct"/> or <see cref="
 268        public Aes ToAes()
 269        {
 6270            if (KeyType != KeyType.Oct)
 271            {
 2272                throw new InvalidOperationException($"key is not an {nameof(KeyType.Oct)} key");
 273            }
 274
 4275            if (K is null)
 276            {
 2277                throw new InvalidOperationException("key does not contain a value");
 278            }
 279
 2280            Aes key = Aes.Create();
 2281            key.Key = K;
 282
 2283            return key;
 284        }
 285
 286        /// <summary>
 287        /// Converts this <see cref="JsonWebKey"/> of type <see cref="KeyType.Ec"/> or <see cref="KeyType.EcHsm"/> to an
 288        /// </summary>
 289        /// <param name="includePrivateParameters">Whether to include private parameters.</param>
 290        /// <returns>An <see cref="ECDsa"/> object.</returns>
 291        /// <exception cref="InvalidOperationException">This key is not of type <see cref="KeyType.Ec"/> or <see cref="K
 40292        public ECDsa ToECDsa(bool includePrivateParameters = false) => ToECDsa(includePrivateParameters, true);
 293
 294        internal ECDsa ToECDsa(bool includePrivateParameters, bool throwIfNotSupported)
 295        {
 72296            if (KeyType != KeyType.Ec && KeyType != KeyType.EcHsm)
 297            {
 2298                throw new InvalidOperationException($"key is not an {nameof(KeyType.Ec)} or {nameof(KeyType.EcHsm)} type
 299            }
 300
 70301            ValidateKeyParameter(nameof(X), X);
 64302            ValidateKeyParameter(nameof(Y), Y);
 303
 58304            return Convert(includePrivateParameters, throwIfNotSupported);
 305        }
 306
 307        /// <summary>
 308        /// Converts this <see cref="JsonWebKey"/> of type <see cref="KeyType.Rsa"/> or <see cref="KeyType.RsaHsm"/> to 
 309        /// </summary>
 310        /// <param name="includePrivateParameters">Whether to include private parameters.</param>
 311        /// <returns>An <see cref="RSA"/> object.</returns>
 312        /// <exception cref="InvalidOperationException">This key is not of type <see cref="KeyType.Rsa"/> or <see cref="
 313        public RSA ToRSA(bool includePrivateParameters = false)
 314        {
 72315            if (KeyType != KeyType.Rsa && KeyType != KeyType.RsaHsm)
 316            {
 2317                throw new InvalidOperationException($"key is not an {nameof(KeyType.Rsa)} or {nameof(KeyType.RsaHsm)} ty
 318            }
 319
 70320            ValidateKeyParameter(nameof(E), E);
 64321            ValidateKeyParameter(nameof(N), N);
 322
 323            // Key parameter length requirements defined by 2.2.2.9.1 RSA Private Key BLOB specification: https://docs.m
 58324            var rsaParameters = new RSAParameters
 58325            {
 58326                Exponent = E,
 58327                Modulus = TrimBuffer(N),
 58328            };
 329
 58330            if (includePrivateParameters && HasPrivateKey)
 331            {
 26332                int byteLength = rsaParameters.Modulus.Length;
 26333                rsaParameters.D = ForceBufferLength(nameof(D), D, byteLength);
 334
 26335                byteLength >>= 1;
 26336                rsaParameters.DP = ForceBufferLength(nameof(DP), DP, byteLength);
 26337                rsaParameters.DQ = ForceBufferLength(nameof(DQ), DQ, byteLength);
 26338                rsaParameters.P = ForceBufferLength(nameof(P), P, byteLength);
 26339                rsaParameters.Q = ForceBufferLength(nameof(Q), Q, byteLength);
 26340                rsaParameters.InverseQ = ForceBufferLength(nameof(QI), QI, byteLength);
 341            }
 342
 58343            RSA rsa = RSA.Create();
 58344            rsa.ImportParameters(rsaParameters);
 345
 58346            return rsa;
 347        }
 348
 349        internal bool SupportsOperation(KeyOperation operation)
 350        {
 188351            if (KeyOps != null)
 352            {
 1088353                for (int i = 0; i < KeyOps.Count; ++i)
 354                {
 542355                    if (_keyOps[i] == operation)
 356                    {
 186357                        return true;
 358                    }
 359                }
 360            }
 361
 2362            return false;
 363        }
 364
 365        internal void ReadProperties(JsonElement json)
 366        {
 8816367            foreach (JsonProperty prop in json.EnumerateObject())
 368            {
 3710369                switch (prop.Name)
 370                {
 371                    case KeyIdPropertyName:
 676372                        Id = prop.Value.GetString();
 676373                        break;
 374                    case KeyTypePropertyName:
 698375                        KeyType = prop.Value.GetString();
 698376                        break;
 377                    case KeyOpsPropertyName:
 5928378                        foreach (JsonElement element in prop.Value.EnumerateArray())
 379                        {
 2314380                            _keyOps.Add(element.ToString());
 381                        }
 382                        break;
 383                    case CurveNamePropertyName:
 368384                        CurveName = prop.Value.GetString();
 368385                        break;
 386                    case NPropertyName:
 280387                        N = Base64Url.Decode(prop.Value.GetString());
 280388                        break;
 389                    case EPropertyName:
 280390                        E = Base64Url.Decode(prop.Value.GetString());
 280391                        break;
 392                    case DPPropertyName:
 2393                        DP = Base64Url.Decode(prop.Value.GetString());
 2394                        break;
 395                    case DQPropertyName:
 2396                        DQ = Base64Url.Decode(prop.Value.GetString());
 2397                        break;
 398                    case QIPropertyName:
 2399                        QI = Base64Url.Decode(prop.Value.GetString());
 2400                        break;
 401                    case PPropertyName:
 2402                        P = Base64Url.Decode(prop.Value.GetString());
 2403                        break;
 404                    case QPropertyName:
 2405                        Q = Base64Url.Decode(prop.Value.GetString());
 2406                        break;
 407                    case XPropertyName:
 368408                        X = Base64Url.Decode(prop.Value.GetString());
 368409                        break;
 410                    case YPropertyName:
 368411                        Y = Base64Url.Decode(prop.Value.GetString());
 368412                        break;
 413                    case DPropertyName:
 10414                        D = Base64Url.Decode(prop.Value.GetString());
 10415                        break;
 416                    case KPropertyName:
 2417                        K = Base64Url.Decode(prop.Value.GetString());
 2418                        break;
 419                    case TPropertyName:
 0420                        T = Base64Url.Decode(prop.Value.GetString());
 421                        break;
 422                }
 423            }
 698424        }
 425
 426        internal void WriteProperties(Utf8JsonWriter json)
 427        {
 58428            if (KeyType != default)
 429            {
 58430                json.WriteString(s_keyTypePropertyNameBytes, KeyType.ToString());
 431            }
 58432            if (KeyOps != null)
 433            {
 58434                json.WriteStartArray(s_keyOpsPropertyNameBytes);
 552435                foreach (KeyOperation operation in KeyOps)
 436                {
 218437                    json.WriteStringValue(operation.ToString());
 438                }
 58439                json.WriteEndArray();
 440            }
 58441            if (CurveName.HasValue)
 442            {
 28443                json.WriteString(s_curveNamePropertyNameBytes, CurveName.Value.ToString());
 444            }
 58445            if (N != null)
 446            {
 28447                json.WriteString(s_nPropertyNameBytes, Base64Url.Encode(N));
 448            }
 58449            if (E != null)
 450            {
 28451                json.WriteString(s_ePropertyNameBytes, Base64Url.Encode(E));
 452            }
 58453            if (DP != null)
 454            {
 26455                json.WriteString(s_dPPropertyNameBytes, Base64Url.Encode(DP));
 456            }
 58457            if (DQ != null)
 458            {
 26459                json.WriteString(s_dQPropertyNameBytes, Base64Url.Encode(DQ));
 460            }
 58461            if (QI != null)
 462            {
 26463                json.WriteString(s_qIPropertyNameBytes, Base64Url.Encode(QI));
 464            }
 58465            if (P != null)
 466            {
 26467                json.WriteString(s_pPropertyNameBytes, Base64Url.Encode(P));
 468            }
 58469            if (Q != null)
 470            {
 26471                json.WriteString(s_qPropertyNameBytes, Base64Url.Encode(Q));
 472            }
 58473            if (X != null)
 474            {
 28475                json.WriteString(s_xPropertyNameBytes, Base64Url.Encode(X));
 476            }
 58477            if (Y != null)
 478            {
 28479                json.WriteString(s_yPropertyNameBytes, Base64Url.Encode(Y));
 480            }
 58481            if (D != null)
 482            {
 46483                json.WriteString(s_dPropertyNameBytes, Base64Url.Encode(D));
 484            }
 58485            if (K != null)
 486            {
 2487                json.WriteString(s_kPropertyNameBytes, Base64Url.Encode(K));
 488            }
 58489            if (T != null)
 490            {
 0491                json.WriteString(s_tPropertyNameBytes, Base64Url.Encode(T));
 492            }
 58493        }
 494
 22495        void IJsonDeserializable.ReadProperties(JsonElement json) => ReadProperties(json);
 496
 22497        void IJsonSerializable.WriteProperties(Utf8JsonWriter json) => WriteProperties(json);
 498
 499        private static byte[] ForceBufferLength(string name, byte[] value, int requiredLengthInBytes)
 500        {
 282501            if (value is null || value.Length == 0)
 502            {
 0503                throw new InvalidOperationException($"key parameter {name} is null or empty");
 504            }
 505
 282506            if (value.Length == requiredLengthInBytes)
 507            {
 278508                return value;
 509            }
 510
 4511            if (value.Length < requiredLengthInBytes)
 512            {
 0513                byte[] padded = new byte[requiredLengthInBytes];
 0514                Array.Copy(value, 0, padded, requiredLengthInBytes - value.Length, value.Length);
 515
 0516                return padded;
 517            }
 518
 519            // Throw if any extra bytes are non-zero.
 4520            var extraLength = value.Length - requiredLengthInBytes;
 0521            for (int i = 0; i < extraLength; ++i)
 522            {
 4523                if (value[i] != 0)
 524                {
 4525                    throw new InvalidOperationException($"key parameter {name} is too long: expected at most {requiredLe
 526                }
 527            }
 528
 0529            byte[] trimmed = new byte[requiredLengthInBytes];
 0530            Array.Copy(value, value.Length - requiredLengthInBytes, trimmed, 0, requiredLengthInBytes);
 531
 0532            return trimmed;
 533        }
 534
 2535        private static readonly byte[] s_zeroBuffer = new byte[] { 0 };
 536        private static byte[] TrimBuffer(byte[] value)
 537        {
 58538            if (value is null || value.Length <= 1 || value[0] != 0)
 539            {
 58540                return value;
 541            }
 542
 0543            for (int i = 1; i < value.Length; ++i)
 544            {
 0545                if (value[i] != 0)
 546                {
 0547                    var trimmed = new byte[value.Length - i];
 0548                    Array.Copy(value, i, trimmed, 0, trimmed.Length);
 549
 0550                    return trimmed;
 551                }
 552            }
 553
 0554            return s_zeroBuffer;
 555        }
 556
 557        private static void ValidateKeyParameter(string name, byte[] value)
 558        {
 268559            if (value != null)
 560            {
 840561                for (int i = 0; i < value.Length; ++i)
 562                {
 404563                    if (value[i] != 0)
 564                    {
 244565                        return;
 566                    }
 567                }
 568            }
 569
 24570            throw new InvalidOperationException($"key parameter {name} is null or zeros");
 571        }
 572
 573        // ECParameters is defined in netstandard2.0 but not net461 (introduced in net47). Separate method with no inlin
 574        [MethodImpl(MethodImplOptions.NoInlining)]
 575        private void Initialize(ECDsa ecdsa, bool includePrivateParameters)
 576        {
 92577            KeyType = KeyType.Ec;
 578
 92579            ECParameters ecParameters = ecdsa.ExportParameters(includePrivateParameters);
 90580            CurveName = KeyCurveName.FromOid(ecParameters.Curve.Oid, ecdsa.KeySize).ToString() ?? throw new InvalidOpera
 90581            D = ecParameters.D;
 90582            X = ecParameters.Q.X;
 90583            Y = ecParameters.Q.Y;
 90584        }
 585
 586        [MethodImpl(MethodImplOptions.NoInlining)]
 587        private ECDsa Convert(bool includePrivateParameters, bool throwIfNotSupported)
 588        {
 58589            if (!CurveName.HasValue)
 590            {
 2591                if (throwIfNotSupported)
 592                {
 2593                    throw new InvalidOperationException("missing required curve name");
 594                }
 595
 0596                return null;
 597            }
 598
 56599            KeyCurveName curveName = CurveName.Value;
 600
 56601            int requiredParameterSize = curveName.KeyParameterSize;
 56602            if (requiredParameterSize <= 0)
 603            {
 4604                if (throwIfNotSupported)
 605                {
 2606                    throw new InvalidOperationException($"invalid curve name: {CurveName.ToString()}");
 607                }
 608
 2609                return null;
 610            }
 611
 52612            ECParameters ecParameters = new ECParameters
 52613            {
 52614                Curve = ECCurve.CreateFromOid(curveName.Oid),
 52615                Q = new ECPoint
 52616                {
 52617                    X = ForceBufferLength(nameof(X), X, requiredParameterSize),
 52618                    Y = ForceBufferLength(nameof(Y), Y, requiredParameterSize),
 52619                },
 52620            };
 621
 48622            if (includePrivateParameters && HasPrivateKey)
 623            {
 24624                ecParameters.D = ForceBufferLength(nameof(D), D, requiredParameterSize);
 625            }
 626
 48627            ECDsa ecdsa = ECDsa.Create();
 628            try
 629            {
 48630                ecdsa.ImportParameters(ecParameters);
 48631            }
 0632            catch when (!throwIfNotSupported)
 633            {
 0634                ecdsa.Dispose();
 635
 0636                return null;
 637            }
 638
 48639            return ecdsa;
 0640        }
 641    }
 642}