/// <summary> /// ImportParameters will replace the existing key that ECDsaOpenSsl is working with by creating a /// new key. If the parameters contains only Q, then only a public key will be imported. /// If the parameters also contains D, then a full key pair will be imported. /// The parameters Curve value specifies the type of the curve to import. /// </summary> /// <param name="parameters">The curve parameters.</param> /// <exception cref="CryptographicException"> /// if <paramref name="parameters" /> does not contain valid values. /// </exception> /// <exception cref="NotSupportedException"> /// if <paramref name="parameters" /> references a curve that cannot be imported. /// </exception> /// <exception cref="PlatformNotSupportedException"> /// if <paramref name="parameters" /> references a curve that is not supported by this platform. /// </exception> public override void ImportParameters(ECParameters parameters) { SafeEcKeyHandle key; parameters.Validate(); if (parameters.Curve.IsPrime) { key = ImportPrimeCurveParameters(parameters); } else if (parameters.Curve.IsCharacteristic2) { key = ImportCharacteristic2CurveParameters(parameters); } else if (parameters.Curve.IsNamed) { key = ImportNamedCurveParameters(parameters); } else { throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, parameters.Curve.CurveType.ToString())); } if (key == null || key.IsInvalid) throw Interop.Crypto.CreateOpenSslCryptographicException(); SetKey(key); }
internal static byte[] GetNamedCurveBlob(ref ECParameters parameters) { Debug.Assert(parameters.Curve.IsNamed); bool includePrivateParameters = (parameters.D != null); byte[] blob; unsafe { // We need to build a key blob structured as follows: // BCRYPT_ECCKEY_BLOB header // byte[cbKey] Q.X // byte[cbKey] Q.Y // -- Only if "includePrivateParameters" is true -- // byte[cbKey] D int blobSize = sizeof(BCRYPT_ECCKEY_BLOB) + parameters.Q.X.Length + parameters.Q.Y.Length; if (includePrivateParameters) { blobSize += parameters.D.Length; } blob = new byte[blobSize]; fixed (byte* pBlob = blob) { // Build the header BCRYPT_ECCKEY_BLOB* pBcryptBlob = (BCRYPT_ECCKEY_BLOB*)pBlob; pBcryptBlob->Magic = CurveNameToMagicNumber(parameters.Curve.Oid.FriendlyName, includePrivateParameters); pBcryptBlob->cbKey = parameters.Q.X.Length; // Emit the blob int offset = sizeof(BCRYPT_ECCKEY_BLOB); Interop.BCrypt.Emit(blob, ref offset, parameters.Q.X); Interop.BCrypt.Emit(blob, ref offset, parameters.Q.Y); if (includePrivateParameters) { Interop.BCrypt.Emit(blob, ref offset, parameters.D); } // We better have computed the right allocation size above! Debug.Assert(offset == blobSize, "offset == blobSize"); } } return blob; }
private static Track2Sdk.JsonWebKey CreateTrack2SdkJWK(ECDsa ecdSa) { if (ecdSa == null) { throw new ArgumentNullException("ecdSa"); } System.Security.Cryptography.ECParameters ecParameters = ecdSa.ExportParameters(true); var webKey = new Track2Sdk.JsonWebKey(ecdSa) { // note: Keyvault need distinguish EC and EC-HSM KeyType = Track2Sdk.KeyType.EcHsm, CurveName = ecParameters.Curve.CurveType.ToString(), D = ecParameters.D, X = ecParameters.Q.X, Y = ecParameters.Q.Y }; return(webKey); }
public static ECDiffieHellmanCngPublicKey FromXmlString(string xml) { if (xml == null) { throw new ArgumentNullException("xml"); } bool isEcdh; ECParameters parameters = Rfc4050KeyFormatter.FromXml(xml, out isEcdh); if (!isEcdh) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgECDHRequiresECDHKey), "xml"); } CngKeyBlobFormat format; string curveName; byte[] blob = ECCng.EcdhParametersToBlob(ref parameters, out format, out curveName); return(new ECDiffieHellmanCngPublicKey(blob, curveName, format)); }
public override unsafe bool TryExportPkcs8PrivateKey( Span <byte> destination, out int bytesWritten) { ECParameters ecParameters = ExportParameters(true); fixed(byte *privPtr = ecParameters.D) { try { using (AsnWriter writer = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters)) { return(writer.TryEncode(destination, out bytesWritten)); } } finally { CryptographicOperations.ZeroMemory(ecParameters.D); } } }
internal static void ExportNamedCurveParameters(ref ECParameters ecParams, byte[] ecBlob, bool includePrivateParameters) { // We now have a buffer laid out as follows: // BCRYPT_ECCKEY_BLOB header // byte[cbKey] Q.X // byte[cbKey] Q.Y // -- Private only -- // byte[cbKey] D KeyBlobMagicNumber magic = (KeyBlobMagicNumber)BitConverter.ToInt32(ecBlob, 0); // Check the magic value in the key blob header. If the blob does not have the required magic, // then throw a CryptographicException. CheckMagicValueOfKey(magic, includePrivateParameters); unsafe { // Fail-fast if a rogue provider gave us a blob that isn't even the size of the blob header. if (ecBlob.Length < sizeof(BCRYPT_ECCKEY_BLOB)) throw ErrorCode.E_FAIL.ToCryptographicException(); fixed(byte *pEcBlob = &ecBlob[0]) { BCRYPT_ECCKEY_BLOB *pBcryptBlob = (BCRYPT_ECCKEY_BLOB *)pEcBlob; int offset = sizeof(BCRYPT_ECCKEY_BLOB); ecParams.Q = new ECPoint { X = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbKey), Y = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbKey) }; if (includePrivateParameters) { ecParams.D = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbKey); } } } }
/// <summary> /// Exports the key used by the ECC object into an <see cref="ECParameters"/> object. /// If the key was created as a named curve, the Curve property will contain named curve parameters /// otherwise it will contain explicit parameters. /// </summary> /// <exception cref="CryptographicException"> /// if there was an issue obtaining the curve values. /// </exception> /// <returns>The key and named curve parameters used by the ECC object.</returns> public override ECParameters ExportParameters() { using (CngKey key = Import()) { ECParameters ecparams = default; string? curveName = key.GetCurveName(out _); if (string.IsNullOrEmpty(curveName)) { byte[] fullKeyBlob = ECCng.ExportFullKeyBlob(key, includePrivateParameters: false); ECCng.ExportPrimeCurveParameters(ref ecparams, fullKeyBlob, includePrivateParameters: false); } else { byte[] keyBlob = ECCng.ExportKeyBlob(key, includePrivateParameters: false); ECCng.ExportNamedCurveParameters(ref ecparams, keyBlob, includePrivateParameters: false); ecparams.Curve = ECCurve.CreateFromFriendlyName(curveName); } return(ecparams); } }
internal const string ECDSA_P521_OID_VALUE = "1.3.132.0.35"; // Also called nistP521or secP521r1 public int ImportParameters(ECParameters parameters) { SafeEcKeyHandle key; parameters.Validate(); if (parameters.Curve.IsPrime) { key = ImportPrimeCurveParameters(parameters); } else if (parameters.Curve.IsCharacteristic2) { key = ImportCharacteristic2CurveParameters(parameters); } else if (parameters.Curve.IsNamed) { key = ImportNamedCurveParameters(parameters); } else { throw new PlatformNotSupportedException( SR.Format(SR.Cryptography_CurveNotSupported, parameters.Curve.CurveType.ToString())); } if (key == null || key.IsInvalid) { Exception e = Interop.Crypto.CreateOpenSslCryptographicException(); key?.Dispose(); throw e; } // The Import* methods above may have polluted the error queue even if in the end they succeeded. // Clean up the error queue. Interop.Crypto.ErrClearError(); FreeKey(); _key = new Lazy <SafeEcKeyHandle>(key); return(KeySize); }
private static SafeSecKeyRefHandle ImportKey(ECParameters parameters) { bool isPrivateKey = parameters.D != null; byte[] blob; if (isPrivateKey) { using (AsnWriter privateKey = EccKeyFormatHelper.WriteECPrivateKey(parameters)) { blob = privateKey.Encode(); } } else { using (AsnWriter publicKey = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters)) { blob = publicKey.Encode(); } } return(Interop.AppleCrypto.ImportEphemeralKey(blob, isPrivateKey)); }
public override unsafe bool TryExportEncryptedPkcs8PrivateKey( ReadOnlySpan <char> password, PbeParameters pbeParameters, Span <byte> destination, out int bytesWritten) { if (pbeParameters == null) { throw new ArgumentNullException(nameof(pbeParameters)); } PasswordBasedEncryption.ValidatePbeParameters( pbeParameters, password, ReadOnlySpan <byte> .Empty); ECParameters ecParameters = ExportParameters(true); fixed(byte *privPtr = ecParameters.D) { try { AsnWriter pkcs8PrivateKey = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters); AsnWriter writer = KeyFormatHelper.WriteEncryptedPkcs8( password, pkcs8PrivateKey, pbeParameters); return(writer.TryEncode(destination, out bytesWritten)); } finally { CryptographicOperations.ZeroMemory(ecParameters.D); } } }
/// <summary> /// Get a handle to the secret agreement generated between two parties /// </summary> public SafeNCryptSecretHandle DeriveSecretAgreementHandle(ECDiffieHellmanPublicKey otherPartyPublicKey) { if (otherPartyPublicKey == null) { throw new ArgumentNullException(nameof(otherPartyPublicKey)); } if (otherPartyPublicKey is ECDiffieHellmanCngPublicKey otherKey) { using (CngKey importedKey = otherKey.Import()) { return(DeriveSecretAgreementHandle(importedKey)); } } ECParameters otherPartyParameters = otherPartyPublicKey.ExportParameters(); using (ECDiffieHellmanCng otherPartyCng = (ECDiffieHellmanCng)Create(otherPartyParameters)) using (otherKey = (ECDiffieHellmanCngPublicKey)otherPartyCng.PublicKey) using (CngKey importedKey = otherKey.Import()) { return(DeriveSecretAgreementHandle(importedKey)); } }
public override void ImportParameters(ECParameters parameters) { parameters.Validate(); bool isPrivateKey = parameters.D != null; if (isPrivateKey) { // Start with the private key, in case some of the private key fields don't // match the public key fields and the system determines an integrity failure. // // Public import should go off without a hitch. SafeSecKeyRefHandle privateKey = ImportKey(parameters); ECParameters publicOnly = parameters; publicOnly.D = null; SafeSecKeyRefHandle publicKey; try { publicKey = ImportKey(publicOnly); } catch { privateKey.Dispose(); throw; } SetKey(SecKeyPair.PublicPrivatePair(publicKey, privateKey)); } else { SafeSecKeyRefHandle publicKey = ImportKey(parameters); SetKey(SecKeyPair.PublicOnly(publicKey)); } }
private static SafeSecKeyRefHandle ImportKey(ECParameters parameters) { AsnWriter keyWriter; bool hasPrivateKey; if (parameters.D != null) { keyWriter = EccKeyFormatHelper.WriteECPrivateKey(parameters); hasPrivateKey = true; } else { keyWriter = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters); hasPrivateKey = false; } byte[] rented = CryptoPool.Rent(keyWriter.GetEncodedLength()); if (!keyWriter.TryEncode(rented, out int written)) { Debug.Fail("TryEncode failed with a pre-allocated buffer"); throw new InvalidOperationException(); } // Explicitly clear the inner buffer keyWriter.Reset(); try { return(Interop.AppleCrypto.ImportEphemeralKey(rented.AsSpan(0, written), hasPrivateKey)); } finally { CryptoPool.Return(rented, written); } }
private static SafeSecKeyRefHandle ImportLegacyPrivateKey(ref ECParameters parameters) { AsnWriter keyWriter = EccKeyFormatHelper.WriteECPrivateKey(parameters); byte[] rented = CryptoPool.Rent(keyWriter.GetEncodedLength()); if (!keyWriter.TryEncode(rented, out int written)) { Debug.Fail("TryEncode failed with a pre-allocated buffer"); throw new InvalidOperationException(); } // Explicitly clear the inner buffer keyWriter.Reset(); try { return(Interop.AppleCrypto.ImportEphemeralKey(rented.AsSpan(0, written), true)); } finally { CryptoPool.Return(rented, written); } }
public ECDiffieHellmanSecurityTransformsPublicKey(ECParameters ecParameters) { Debug.Assert(ecParameters.D == null); _ecc = new EccSecurityTransforms(nameof(ECDiffieHellmanPublicKey)); _ecc.ImportParameters(ecParameters); }
public virtual void ImportParameters (ECParameters parameters) { throw new NotImplementedException (); }
public override void ImportParameters(ECParameters parameters) { KeySizeValue = _ecc.ImportParameters(parameters); }
/// <summary> /// When overridden in a derived class, imports the specified ECParameters. /// </summary> /// <param name="parameters">The curve parameters.</param> public virtual void ImportParameters(ECParameters parameters) { throw DerivedClassMustOverride(); }
internal static void ReadPkcs8Blob(this DerSequenceReader reader, ref ECParameters parameters) { // OneAsymmetricKey ::= SEQUENCE { // version Version, // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, // privateKey PrivateKey, // attributes [0] Attributes OPTIONAL, // ..., // [[2: publicKey [1] PublicKey OPTIONAL ]], // ... // } // // PrivateKeyInfo ::= OneAsymmetricKey // // PrivateKey ::= OCTET STRING int version = reader.ReadInteger(); // We understand both version 0 and 1 formats, // which are now known as v1 and v2, respectively. if (version > 1) { throw new CryptographicException(); } { // Ensure we're reading EC Public Key (well, Private, but the OID says Public) DerSequenceReader algorithm = reader.ReadSequence(); string algorithmOid = algorithm.ReadOidAsString(); if (algorithmOid != s_idEcPublicKey.Value) { throw new CryptographicException(); } } byte[] privateKeyBlob = reader.ReadOctetString(); try { // ECPrivateKey{CURVES:IOSet} ::= SEQUENCE { // version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), // privateKey OCTET STRING, // parameters [0] Parameters{{IOSet}} OPTIONAL, // publicKey [1] BIT STRING OPTIONAL // } DerSequenceReader keyReader = new DerSequenceReader(privateKeyBlob); version = keyReader.ReadInteger(); // We understand the version 1 format if (version > 1) { throw new CryptographicException(); } parameters.D = keyReader.ReadOctetString(); // Check for context specific 0 const byte ConstructedContextSpecific = DerSequenceReader.ContextSpecificTagFlag | DerSequenceReader.ConstructedFlag; const byte ConstructedContextSpecific0 = (ConstructedContextSpecific | 0); const byte ConstructedContextSpecific1 = (ConstructedContextSpecific | 1); if (keyReader.PeekTag() != ConstructedContextSpecific0) { throw new CryptographicException(); } // Parameters ::= CHOICE { // ecParameters ECParameters, // namedCurve CURVES.&id({ CurveNames}), // implicitlyCA NULL // } DerSequenceReader parametersReader = keyReader.ReadSequence(); if (parametersReader.PeekTag() != (int)DerSequenceReader.DerTag.ObjectIdentifier) { throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly); } parameters.Curve = ECCurve.CreateFromValue(parametersReader.ReadOidAsString()); // Check for context specific 1 if (keyReader.PeekTag() != ConstructedContextSpecific1) { throw new CryptographicException(); } keyReader = keyReader.ReadSequence(); byte[] encodedPoint = keyReader.ReadBitString(); ReadEncodedPoint(encodedPoint, ref parameters); // We don't care about the rest of the blob here, but it's expected to not exist. } finally { Array.Clear(privateKeyBlob, 0, privateKeyBlob.Length); } }
internal ECDiffieHellmanOpenSslPublicKey(ECParameters parameters) { _key = new ECOpenSsl(parameters); }
internal bool TryExportDataKeyParameters(bool includePrivateParameters, ref ECParameters ecParameters) { return(_ecc.TryExportDataKeyParameters(includePrivateParameters, KeySize, ref ecParameters)); }
internal static ECParameters GetECKeyParameters( SafeEcKeyHandle key, bool includePrivate) { SafeBignumHandle qx_bn, qy_bn, d_bn; IntPtr d_bn_not_owned; int qx_cb, qy_cb, d_cb; ECParameters parameters = new ECParameters(); bool refAdded = false; try { key.DangerousAddRef(ref refAdded); // Protect access to d_bn_not_owned if (!CryptoNative_GetECKeyParameters( key, includePrivate, out qx_bn, out qx_cb, out qy_bn, out qy_cb, out d_bn_not_owned, out d_cb)) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } using (qx_bn) using (qy_bn) using (d_bn = new SafeBignumHandle(d_bn_not_owned, false)) { // Match Windows semantics where qx, qy, and d have same length int cbKey = GetMax(qx_cb, qy_cb, d_cb); parameters.Q = new ECPoint { X = Crypto.ExtractBignum(qx_bn, cbKey), Y = Crypto.ExtractBignum(qy_bn, cbKey) }; parameters.D = d_cb == 0 ? null : Crypto.ExtractBignum(d_bn, cbKey); } } finally { if (refAdded) key.DangerousRelease(); } return parameters; }
internal static void ExportPrimeCurveParameters(ref ECParameters ecParams, byte[] ecBlob, bool includePrivateParameters) { // We now have a buffer laid out as follows: // BCRYPT_ECCFULLKEY_BLOB header // byte[cbFieldLength] P // byte[cbFieldLength] A // byte[cbFieldLength] B // byte[cbFieldLength] G.X // byte[cbFieldLength] G.Y // byte[cbSubgroupOrder] Order (n) // byte[cbCofactor] Cofactor (h) // byte[cbSeed] Seed // byte[cbFieldLength] Q.X // byte[cbFieldLength] Q.Y // -- Private only -- // byte[cbSubgroupOrder] D KeyBlobMagicNumber magic = (KeyBlobMagicNumber)BitConverter.ToInt32(ecBlob, 0); // Check the magic value in the key blob header. If the blob does not have the required magic, // then throw a CryptographicException. CheckMagicValueOfKey(magic, includePrivateParameters); unsafe { // Fail-fast if a rogue provider gave us a blob that isn't even the size of the blob header. if (ecBlob.Length < sizeof(BCRYPT_ECCFULLKEY_BLOB)) throw ErrorCode.E_FAIL.ToCryptographicException(); fixed (byte* pEcBlob = ecBlob) { BCRYPT_ECCFULLKEY_BLOB* pBcryptBlob = (BCRYPT_ECCFULLKEY_BLOB*)pEcBlob; var primeCurve = new ECCurve(); primeCurve.CurveType = ConvertToCurveTypeEnum(pBcryptBlob->CurveType); primeCurve.Hash = GetHashAlgorithmName(pBcryptBlob->CurveGenerationAlgId); int offset = sizeof(BCRYPT_ECCFULLKEY_BLOB); primeCurve.Prime = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength); primeCurve.A = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength); primeCurve.B = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength); primeCurve.G = new ECPoint() { X = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength), Y = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength), }; primeCurve.Order = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbSubgroupOrder); primeCurve.Cofactor = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbCofactor); // Optional parameters primeCurve.Seed = pBcryptBlob->cbSeed == 0 ? null : Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbSeed); ecParams.Q = new ECPoint { X = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength), Y = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength) }; if (includePrivateParameters) { ecParams.D = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbSubgroupOrder); } ecParams.Curve = primeCurve; } } }
internal static void ExportNamedCurveParameters(ref ECParameters ecParams, byte[] ecBlob, bool includePrivateParameters) { // We now have a buffer laid out as follows: // BCRYPT_ECCKEY_BLOB header // byte[cbKey] Q.X // byte[cbKey] Q.Y // -- Private only -- // byte[cbKey] D KeyBlobMagicNumber magic = (KeyBlobMagicNumber)BitConverter.ToInt32(ecBlob, 0); // Check the magic value in the key blob header. If the blob does not have the required magic, // then throw a CryptographicException. CheckMagicValueOfKey(magic, includePrivateParameters); unsafe { // Fail-fast if a rogue provider gave us a blob that isn't even the size of the blob header. if (ecBlob.Length < sizeof(BCRYPT_ECCKEY_BLOB)) throw ErrorCode.E_FAIL.ToCryptographicException(); fixed (byte* pEcBlob = ecBlob) { BCRYPT_ECCKEY_BLOB* pBcryptBlob = (BCRYPT_ECCKEY_BLOB*)pEcBlob; int offset = sizeof(BCRYPT_ECCKEY_BLOB); ecParams.Q = new ECPoint { X = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbKey), Y = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbKey) }; if (includePrivateParameters) { ecParams.D = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbKey); } } } }
/// <summary> /// When overridden in a derived class, imports the specified ECParameters. /// </summary> /// <param name="parameters">The curve parameters.</param> public virtual void ImportParameters(ECParameters parameters) { throw new NotSupportedException(SR.NotSupported_SubclassOverride); }
/// <summary> /// Creates an instance of the platform specific implementation of the cref="ECDsa" algorithm. /// </summary> /// <param name="parameters"> /// The <see cref="ECParameters"/> representing the elliptic curve parameters. /// </param> public static ECDsa Create(ECParameters parameters) { ECDsa ec = new ECDsaImplementation.ECDsaCng(); ec.ImportParameters(parameters); return ec; }
internal static byte[] GetPrimeCurveBlob(ref ECParameters parameters) { Debug.Assert(parameters.Curve.IsPrime); bool includePrivateParameters = (parameters.D != null); ECCurve curve = parameters.Curve; byte[] blob; unsafe { // We need to build a key blob structured as follows: // BCRYPT_ECCFULLKEY_BLOB header // byte[cbFieldLength] P // byte[cbFieldLength] A // byte[cbFieldLength] B // byte[cbFieldLength] G.X // byte[cbFieldLength] G.Y // byte[cbSubgroupOrder] Order (n) // byte[cbCofactor] Cofactor (h) // byte[cbSeed] Seed // byte[cbFieldLength] Q.X // byte[cbFieldLength] Q.Y // -- Only if "includePrivateParameters" is true -- // byte[cbSubgroupOrder] D int blobSize = sizeof(BCRYPT_ECCFULLKEY_BLOB) + curve.Prime.Length + curve.A.Length + curve.B.Length + curve.G.X.Length + curve.G.Y.Length + curve.Order.Length + curve.Cofactor.Length + (curve.Seed == null ? 0 : curve.Seed.Length) + parameters.Q.X.Length + parameters.Q.Y.Length; if (includePrivateParameters) { blobSize += parameters.D.Length; } blob = new byte[blobSize]; fixed (byte* pBlob = blob) { // Build the header BCRYPT_ECCFULLKEY_BLOB* pBcryptBlob = (BCRYPT_ECCFULLKEY_BLOB*)pBlob; pBcryptBlob->Version = 1; // No constant for this found in bcrypt.h pBcryptBlob->Magic = includePrivateParameters ? KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_GENERIC_MAGIC : KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC; pBcryptBlob->cbCofactor = curve.Cofactor.Length; pBcryptBlob->cbFieldLength = parameters.Q.X.Length; pBcryptBlob->cbSeed = curve.Seed == null ? 0 : curve.Seed.Length; pBcryptBlob->cbSubgroupOrder = curve.Order.Length; pBcryptBlob->CurveGenerationAlgId = GetHashAlgorithmId(curve.Hash); pBcryptBlob->CurveType = ConvertToCurveTypeEnum(curve.CurveType); // Emit the blob int offset = sizeof(BCRYPT_ECCFULLKEY_BLOB); Interop.BCrypt.Emit(blob, ref offset, curve.Prime); Interop.BCrypt.Emit(blob, ref offset, curve.A); Interop.BCrypt.Emit(blob, ref offset, curve.B); Interop.BCrypt.Emit(blob, ref offset, curve.G.X); Interop.BCrypt.Emit(blob, ref offset, curve.G.Y); Interop.BCrypt.Emit(blob, ref offset, curve.Order); Interop.BCrypt.Emit(blob, ref offset, curve.Cofactor); if (curve.Seed != null) { Interop.BCrypt.Emit(blob, ref offset, curve.Seed); } Interop.BCrypt.Emit(blob, ref offset, parameters.Q.X); Interop.BCrypt.Emit(blob, ref offset, parameters.Q.Y); if (includePrivateParameters) { Interop.BCrypt.Emit(blob, ref offset, parameters.D); } // We better have computed the right allocation size above! Debug.Assert(offset == blobSize, "offset == blobSize"); } return blob; } }
private static void ExtractPublicKeyFromPrivateKey(ref ECParameters ecParameters) => throw new PlatformNotSupportedException(SR.Cryptography_NotValidPublicOrPrivateKey);
public static partial ECDiffieHellman Create(ECParameters parameters);
public static partial ECDsa Create(ECParameters parameters);
public ECAndroid(ECParameters ecParameters) { ImportParameters(ecParameters); }
public override void ImportParameters(ECParameters parameters) { ThrowIfDisposed(); KeySizeValue = _key.ImportParameters(parameters); }
internal static void ReadSubjectPublicKeyInfo(this DerSequenceReader keyInfo, ref ECParameters parameters) { // SubjectPublicKeyInfo::= SEQUENCE { // algorithm AlgorithmIdentifier, // subjectPublicKey BIT STRING } DerSequenceReader algorithm = keyInfo.ReadSequence(); string algorithmOid = algorithm.ReadOidAsString(); // EC Public Key if (algorithmOid != s_idEcPublicKey.Value) { throw new CryptographicException(); } if (algorithm.PeekTag() != (int)DerSequenceReader.DerTag.ObjectIdentifier) { throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly); } parameters.Curve = ECCurve.CreateFromValue(algorithm.ReadOidAsString()); byte[] encodedPoint = keyInfo.ReadBitString(); ReadEncodedPoint(encodedPoint, ref parameters); // We don't care about the rest of the blob here, but it's expected to not exist. }
public override void ImportParameters(ECParameters parameters) { throw new NotImplementedException(); }
internal static ECParameters GetECCurveParameters( SafeEcKeyHandle key, bool includePrivate) { ECCurve.ECCurveType curveType; SafeBignumHandle qx_bn, qy_bn, p_bn, a_bn, b_bn, gx_bn, gy_bn, order_bn, cofactor_bn, seed_bn; IntPtr d_bn_not_owned; int qx_cb, qy_cb, p_cb, a_cb, b_cb, gx_cb, gy_cb, order_cb, cofactor_cb, seed_cb, d_cb; bool refAdded = false; try { key.DangerousAddRef(ref refAdded); // Protect access to d_bn_not_owned if (!CryptoNative_GetECCurveParameters( key, includePrivate, out curveType, out qx_bn, out qx_cb, out qy_bn, out qy_cb, out d_bn_not_owned, out d_cb, out p_bn, out p_cb, out a_bn, out a_cb, out b_bn, out b_cb, out gx_bn, out gx_cb, out gy_bn, out gy_cb, out order_bn, out order_cb, out cofactor_bn, out cofactor_cb, out seed_bn, out seed_cb)) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } using (qx_bn) using (qy_bn) using (p_bn) using (a_bn) using (b_bn) using (gx_bn) using (gy_bn) using (order_bn) using (cofactor_bn) using (seed_bn) using (var d_h = new SafeBignumHandle(d_bn_not_owned, false)) { int cbFieldLength; int pFieldLength; if (curveType == ECCurve.ECCurveType.Characteristic2) { // Match Windows semantics where a,b,gx,gy,qx,qy have same length // Treat length of m separately as it is not tied to other fields for Char2 (Char2 not supported by Windows) cbFieldLength = GetMax(new[] { a_cb, b_cb, gx_cb, gy_cb, qx_cb, qy_cb }); pFieldLength = p_cb; } else { // Match Windows semantics where p,a,b,gx,gy,qx,qy have same length cbFieldLength = GetMax(new[] { p_cb, a_cb, b_cb, gx_cb, gy_cb, qx_cb, qy_cb }); pFieldLength = cbFieldLength; } // Match Windows semantics where order and d have same length int cbSubgroupOrder = GetMax(order_cb, d_cb); // Copy values to ECParameters ECParameters parameters = new ECParameters(); parameters.Q = new ECPoint { X = Crypto.ExtractBignum(qx_bn, cbFieldLength), Y = Crypto.ExtractBignum(qy_bn, cbFieldLength) }; parameters.D = d_cb == 0 ? null : Crypto.ExtractBignum(d_h, cbSubgroupOrder); var curve = parameters.Curve; curve.CurveType = curveType; curve.A = Crypto.ExtractBignum(a_bn, cbFieldLength); curve.B = Crypto.ExtractBignum(b_bn, cbFieldLength); curve.G = new ECPoint { X = Crypto.ExtractBignum(gx_bn, cbFieldLength), Y = Crypto.ExtractBignum(gy_bn, cbFieldLength) }; curve.Order = Crypto.ExtractBignum(order_bn, cbSubgroupOrder); if (curveType == ECCurve.ECCurveType.Characteristic2) { curve.Polynomial = Crypto.ExtractBignum(p_bn, pFieldLength); } else { curve.Prime = Crypto.ExtractBignum(p_bn, pFieldLength); } // Optional parameters curve.Cofactor = cofactor_cb == 0 ? null : Crypto.ExtractBignum(cofactor_bn, cofactor_cb); curve.Seed = seed_cb == 0 ? null : Crypto.ExtractBignum(seed_bn, seed_cb); parameters.Curve = curve; return parameters; } } finally { if (refAdded) key.DangerousRelease(); } }
private static SafeEcKeyHandle ImportCharacteristic2CurveParameters(ECParameters parameters) { Debug.Assert(parameters.Curve.IsCharacteristic2); SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByExplicitParameters( parameters.Curve.CurveType, parameters.Q.X, parameters.Q.X.Length, parameters.Q.Y, parameters.Q.Y.Length, parameters.D, parameters.D == null ? 0 : parameters.D.Length, parameters.Curve.Polynomial, parameters.Curve.Polynomial.Length, parameters.Curve.A, parameters.Curve.A.Length, parameters.Curve.B, parameters.Curve.B.Length, parameters.Curve.G.X, parameters.Curve.G.X.Length, parameters.Curve.G.Y, parameters.Curve.G.Y.Length, parameters.Curve.Order, parameters.Curve.Order.Length, parameters.Curve.Cofactor, parameters.Curve.Cofactor.Length, parameters.Curve.Seed, parameters.Curve.Seed == null ? 0 : parameters.Curve.Seed.Length); return key; }
public override void ImportParameters(ECParameters parameters) { ThrowIfDisposed(); _key.ImportParameters(parameters); ForceSetKeySize(_key.KeySize); }
public static ECDsa Create (ECParameters parameters) { throw new NotImplementedException (); }
private static ECDsa DecodeECDsaPublicKey(CertificatePal certificatePal) { ECDsa ecdsa; using (SafeBCryptKeyHandle bCryptKeyHandle = ImportPublicKeyInfo(certificatePal.CertContext)) { CngKeyBlobFormat blobFormat; byte[] keyBlob; #if NETNATIVE blobFormat = CngKeyBlobFormat.EccPublicBlob; keyBlob = ExportKeyBlob(bCryptKeyHandle, blobFormat); using (CngKey cngKey = CngKey.Import(keyBlob, blobFormat)) { ecdsa = new ECDsaCng(cngKey); } #else string curveName = GetCurveName(bCryptKeyHandle); if (curveName == null) { if (HasExplicitParameters(bCryptKeyHandle)) { blobFormat = CngKeyBlobFormat.EccFullPublicBlob; } else { blobFormat = CngKeyBlobFormat.EccPublicBlob; } keyBlob = ExportKeyBlob(bCryptKeyHandle, blobFormat); using (CngKey cngKey = CngKey.Import(keyBlob, blobFormat)) { ecdsa = new ECDsaCng(cngKey); } } else { blobFormat = CngKeyBlobFormat.EccPublicBlob; keyBlob = ExportKeyBlob(bCryptKeyHandle, blobFormat); ECParameters ecparams = new ECParameters(); ExportNamedCurveParameters(ref ecparams, keyBlob, false); ecparams.Curve = ECCurve.CreateFromFriendlyName(curveName); ecdsa = new ECDsaCng(); ecdsa.ImportParameters(ecparams); } #endif } return ecdsa; }
private static SafeEcKeyHandle ImportNamedCurveParameters(ECParameters parameters) { Debug.Assert(parameters.Curve.IsNamed); // Use oid Value first if present, otherwise FriendlyName string oid = !string.IsNullOrEmpty(parameters.Curve.Oid.Value) ? parameters.Curve.Oid.Value : parameters.Curve.Oid.FriendlyName; SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByKeyParameters( oid, parameters.Q.X, parameters.Q.X.Length, parameters.Q.Y, parameters.Q.Y.Length, parameters.D, parameters.D == null ? 0 : parameters.D.Length); return key; }
internal ECDiffieHellmanAndroidPublicKey(ECParameters parameters) { _key = new ECAndroid(parameters); }
internal static void ExportPrimeCurveParameters(ref ECParameters ecParams, byte[] ecBlob, bool includePrivateParameters) { // We now have a buffer laid out as follows: // BCRYPT_ECCFULLKEY_BLOB header // byte[cbFieldLength] P // byte[cbFieldLength] A // byte[cbFieldLength] B // byte[cbFieldLength] G.X // byte[cbFieldLength] G.Y // byte[cbSubgroupOrder] Order (n) // byte[cbCofactor] Cofactor (h) // byte[cbSeed] Seed // byte[cbFieldLength] Q.X // byte[cbFieldLength] Q.Y // -- Private only -- // byte[cbSubgroupOrder] D KeyBlobMagicNumber magic = (KeyBlobMagicNumber)BitConverter.ToInt32(ecBlob, 0); // Check the magic value in the key blob header. If the blob does not have the required magic, // then throw a CryptographicException. CheckMagicValueOfKey(magic, includePrivateParameters); unsafe { // Fail-fast if a rogue provider gave us a blob that isn't even the size of the blob header. if (ecBlob.Length < sizeof(BCRYPT_ECCFULLKEY_BLOB)) throw ErrorCode.E_FAIL.ToCryptographicException(); fixed(byte *pEcBlob = &ecBlob[0]) { BCRYPT_ECCFULLKEY_BLOB *pBcryptBlob = (BCRYPT_ECCFULLKEY_BLOB *)pEcBlob; var primeCurve = new ECCurve(); primeCurve.CurveType = ConvertToCurveTypeEnum(pBcryptBlob->CurveType); primeCurve.Hash = GetHashAlgorithmName(pBcryptBlob->CurveGenerationAlgId); int offset = sizeof(BCRYPT_ECCFULLKEY_BLOB); primeCurve.Prime = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength); primeCurve.A = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength); primeCurve.B = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength); primeCurve.G = new ECPoint() { X = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength), Y = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength), }; primeCurve.Order = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbSubgroupOrder); primeCurve.Cofactor = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbCofactor); // Optional parameters primeCurve.Seed = pBcryptBlob->cbSeed == 0 ? null : Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbSeed); ecParams.Q = new ECPoint { X = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength), Y = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength) }; if (includePrivateParameters) { ecParams.D = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbSubgroupOrder); } ecParams.Curve = primeCurve; } } }
/// <summary> /// Get the secret agreement generated between two parties /// </summary> private byte[]? DeriveSecretAgreement(ECDiffieHellmanPublicKey otherPartyPublicKey, IncrementalHash?hasher) { Debug.Assert(otherPartyPublicKey != null); // Ensure that this ECDH object contains a private key by attempting a parameter export // which will throw an OpenSslCryptoException if no private key is available ECParameters thisKeyExplicit = ExportExplicitParameters(true); bool thisIsNamed = Interop.Crypto.EcKeyHasCurveName(_key.Value); ECDiffieHellmanOpenSslPublicKey?otherKey = otherPartyPublicKey as ECDiffieHellmanOpenSslPublicKey; bool disposeOtherKey = false; if (otherKey == null) { disposeOtherKey = true; ECParameters otherParameters = thisIsNamed ? otherPartyPublicKey.ExportParameters() : otherPartyPublicKey.ExportExplicitParameters(); otherKey = new ECDiffieHellmanOpenSslPublicKey(otherParameters); } bool otherIsNamed = otherKey.HasCurveName; SafeEvpPKeyHandle?ourKey = null; SafeEvpPKeyHandle?theirKey = null; byte[]? rented = null; int secretLength = 0; try { if (otherKey.KeySize != KeySize) { throw new ArgumentException(SR.Cryptography_ArgECDHKeySizeMismatch, nameof(otherPartyPublicKey)); } if (otherIsNamed == thisIsNamed) { ourKey = _key.UpRefKeyHandle(); theirKey = otherKey.DuplicateKeyHandle(); } else if (otherIsNamed) { ourKey = _key.UpRefKeyHandle(); using (ECOpenSsl tmp = new ECOpenSsl(otherKey.ExportExplicitParameters())) { theirKey = tmp.UpRefKeyHandle(); } } else { using (ECOpenSsl tmp = new ECOpenSsl(thisKeyExplicit)) { ourKey = tmp.UpRefKeyHandle(); } theirKey = otherKey.DuplicateKeyHandle(); } using (SafeEvpPKeyCtxHandle ctx = Interop.Crypto.EvpPKeyCtxCreate(ourKey, theirKey, out uint secretLengthU)) { if (ctx == null || ctx.IsInvalid || secretLengthU == 0 || secretLengthU > int.MaxValue) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } secretLength = (int)secretLengthU; // Indicate that secret can hold stackallocs from nested scopes Span <byte> secret = stackalloc byte[0]; // Arbitrary limit. But it covers secp521r1, which is the biggest common case. const int StackAllocMax = 66; if (secretLength > StackAllocMax) { rented = CryptoPool.Rent(secretLength); secret = new Span <byte>(rented, 0, secretLength); } else { secret = stackalloc byte[secretLength]; } Interop.Crypto.EvpPKeyDeriveSecretAgreement(ctx, secret); if (hasher == null) { return(secret.ToArray()); } else { hasher.AppendData(secret); return(null); } } } finally { theirKey?.Dispose(); ourKey?.Dispose(); if (disposeOtherKey) { otherKey.Dispose(); } if (rented != null) { CryptoPool.Return(rented, secretLength); } } }
internal static byte[] GetPrimeCurveBlob(ref ECParameters parameters, bool ecdh) { Debug.Assert(parameters.Curve.IsPrime); bool includePrivateParameters = (parameters.D != null); ECCurve curve = parameters.Curve; byte[] blob; unsafe { // We need to build a key blob structured as follows: // BCRYPT_ECCFULLKEY_BLOB header // byte[cbFieldLength] P // byte[cbFieldLength] A // byte[cbFieldLength] B // byte[cbFieldLength] G.X // byte[cbFieldLength] G.Y // byte[cbSubgroupOrder] Order (n) // byte[cbCofactor] Cofactor (h) // byte[cbSeed] Seed // byte[cbFieldLength] Q.X // byte[cbFieldLength] Q.Y // -- Only if "includePrivateParameters" is true -- // byte[cbSubgroupOrder] D int blobSize = sizeof(BCRYPT_ECCFULLKEY_BLOB) + curve.Prime.Length + curve.A.Length + curve.B.Length + curve.G.X.Length + curve.G.Y.Length + curve.Order.Length + curve.Cofactor.Length + (curve.Seed == null ? 0 : curve.Seed.Length) + parameters.Q.X.Length + parameters.Q.Y.Length; if (includePrivateParameters) { blobSize += parameters.D.Length; } blob = new byte[blobSize]; fixed(byte *pBlob = &blob[0]) { // Build the header BCRYPT_ECCFULLKEY_BLOB *pBcryptBlob = (BCRYPT_ECCFULLKEY_BLOB *)pBlob; pBcryptBlob->Version = 1; // No constant for this found in bcrypt.h pBcryptBlob->Magic = includePrivateParameters ? (ecdh ? KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC : KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_GENERIC_MAGIC) : (ecdh ? KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_GENERIC_MAGIC : KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC); pBcryptBlob->cbCofactor = curve.Cofactor.Length; pBcryptBlob->cbFieldLength = parameters.Q.X.Length; pBcryptBlob->cbSeed = curve.Seed == null ? 0 : curve.Seed.Length; pBcryptBlob->cbSubgroupOrder = curve.Order.Length; pBcryptBlob->CurveGenerationAlgId = GetHashAlgorithmId(curve.Hash); pBcryptBlob->CurveType = ConvertToCurveTypeEnum(curve.CurveType); // Emit the blob int offset = sizeof(BCRYPT_ECCFULLKEY_BLOB); Interop.BCrypt.Emit(blob, ref offset, curve.Prime); Interop.BCrypt.Emit(blob, ref offset, curve.A); Interop.BCrypt.Emit(blob, ref offset, curve.B); Interop.BCrypt.Emit(blob, ref offset, curve.G.X); Interop.BCrypt.Emit(blob, ref offset, curve.G.Y); Interop.BCrypt.Emit(blob, ref offset, curve.Order); Interop.BCrypt.Emit(blob, ref offset, curve.Cofactor); if (curve.Seed != null) { Interop.BCrypt.Emit(blob, ref offset, curve.Seed); } Interop.BCrypt.Emit(blob, ref offset, parameters.Q.X); Interop.BCrypt.Emit(blob, ref offset, parameters.Q.Y); if (includePrivateParameters) { Interop.BCrypt.Emit(blob, ref offset, parameters.D); } // We better have computed the right allocation size above! Debug.Assert(offset == blobSize, "offset == blobSize"); } return(blob); } }
/// <summary> /// When overridden in a derived class, imports the specified <see cref="ECParameters" />. /// </summary> /// <param name="parameters">The curve parameters.</param> /// <exception cref="NotSupportedException"> /// A derived class has not provided an implementation. /// </exception> public virtual void ImportParameters(ECParameters parameters) { throw new NotSupportedException(SR.NotSupported_SubclassOverride); }
private static void ExportNamedCurveParameters(ref ECParameters ecParams, byte[] ecBlob, bool includePrivateParameters) { // We now have a buffer laid out as follows: // BCRYPT_ECCKEY_BLOB header // byte[cbKey] Q.X // byte[cbKey] Q.Y // -- Private only -- // byte[cbKey] D unsafe { Debug.Assert(ecBlob.Length >= sizeof(Interop.BCrypt.BCRYPT_ECCKEY_BLOB)); fixed (byte* pEcBlob = ecBlob) { Interop.BCrypt.BCRYPT_ECCKEY_BLOB* pBcryptBlob = (Interop.BCrypt.BCRYPT_ECCKEY_BLOB*)pEcBlob; int offset = sizeof(Interop.BCrypt.BCRYPT_ECCKEY_BLOB); ecParams.Q = new ECPoint { X = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbKey), Y = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbKey) }; if (includePrivateParameters) { ecParams.D = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbKey); } } } }