public static SafeEcKeyHandle GenerateKeyByKeySize(int keySize) { string oid; switch (keySize) { case 256: oid = Oids.secp256r1; break; case 384: oid = Oids.secp384r1; break; case 521: oid = Oids.secp521r1; break; default: // Only above three sizes supported for backwards compatibility; named curves should be used instead throw new InvalidOperationException(SR.Cryptography_InvalidKeySize); } SafeEcKeyHandle?key = Interop.AndroidCrypto.EcKeyCreateByOid(oid); if (key == null || key.IsInvalid) { key?.Dispose(); throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_CurveNotSupported, oid)); } return(key); }
private void FreeKey() { if (_key != null && _key.IsValueCreated) { SafeEcKeyHandle handle = _key.Value; if (handle != null) { handle.Dispose(); } } }
internal static SafeEcKeyHandle DuplicateHandle(IntPtr handle) { Debug.Assert(handle != IntPtr.Zero); // Reliability: Allocate the SafeHandle before calling EC_KEY_up_ref so // that we don't lose a tracked reference in low-memory situations. SafeEcKeyHandle safeHandle = new SafeEcKeyHandle(); if (!Interop.AndroidCrypto.EcKeyUpRef(handle)) { safeHandle.Dispose(); throw new CryptographicException(); } safeHandle.SetHandle(handle); return(safeHandle); }
internal int GenerateKey(ECCurve curve) { curve.Validate(); FreeKey(); if (curve.IsNamed) { // Use oid Value first if present, otherwise FriendlyName because Oid maintains a hard-coded // cache that may have different casing for FriendlyNames than OpenSsl string oid = !string.IsNullOrEmpty(curve.Oid.Value) ? curve.Oid.Value : curve.Oid.FriendlyName !; SafeEcKeyHandle?key = Interop.Crypto.EcKeyCreateByOid(oid); if (key == null || key.IsInvalid) { key?.Dispose(); throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_CurveNotSupported, oid)); } if (!Interop.Crypto.EcKeyGenerateKey(key)) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } SetKey(key); } else if (curve.IsExplicit) { SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByExplicitCurve(curve); if (!Interop.Crypto.EcKeyGenerateKey(key)) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } SetKey(key); } else { throw new PlatformNotSupportedException( SR.Format(SR.Cryptography_CurveNotSupported, curve.CurveType.ToString())); } return(KeySize); }
internal ECDiffieHellmanOpenSslPublicKey(SafeEvpPKeyHandle pkeyHandle) { ArgumentNullException.ThrowIfNull(pkeyHandle); if (pkeyHandle.IsInvalid) { throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(pkeyHandle)); } // If ecKey is valid it has already been up-ref'd, so we can just use this handle as-is. SafeEcKeyHandle key = Interop.Crypto.EvpPkeyGetEcKey(pkeyHandle); if (key.IsInvalid) { key.Dispose(); throw Interop.Crypto.CreateOpenSslCryptographicException(); } _key = new ECOpenSsl(key); }
public ECDsaOpenSsl(SafeEvpPKeyHandle pkeyHandle) { ArgumentNullException.ThrowIfNull(pkeyHandle); if (pkeyHandle.IsInvalid) { throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(pkeyHandle)); } ThrowIfNotSupported(); // If ecKey is valid it has already been up-ref'd, so we can just use this handle as-is. SafeEcKeyHandle key = Interop.Crypto.EvpPkeyGetEcKey(pkeyHandle); if (key.IsInvalid) { key.Dispose(); throw Interop.Crypto.CreateOpenSslCryptographicException(); } _key = new ECOpenSsl(key); KeySizeValue = _key.KeySize; }
/// <summary> /// Create an ECDsaOpenSsl from an <see cref="SafeEvpPKeyHandle"/> whose value is an existing /// OpenSSL <c>EVP_PKEY*</c> wrapping an <c>EC_KEY*</c> /// </summary> /// <param name="pkeyHandle">A SafeHandle for an OpenSSL <c>EVP_PKEY*</c></param> /// <exception cref="ArgumentNullException"><paramref name="pkeyHandle"/> is <c>null</c></exception> /// <exception cref="ArgumentException"><paramref name="pkeyHandle"/> <see cref="SafeHandle.IsInvalid" /></exception> /// <exception cref="CryptographicException"><paramref name="pkeyHandle"/> is not a valid enveloped <c>EC_KEY*</c></exception> public ECDsaOpenSsl(SafeEvpPKeyHandle pkeyHandle) { if (pkeyHandle == null) { throw new ArgumentNullException(nameof(pkeyHandle)); } if (pkeyHandle.IsInvalid) { throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(pkeyHandle)); } // If ecKey is valid it has already been up-ref'd, so we can just use this handle as-is. SafeEcKeyHandle key = Interop.Crypto.EvpPkeyGetEcKey(pkeyHandle); if (key.IsInvalid) { key.Dispose(); throw Interop.Crypto.CreateOpenSslCryptographicException(); } SetKey(key); }
/// <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.AndroidCrypto.EcKeyHasCurveName(_key.Value); ECDiffieHellmanAndroidPublicKey?otherKey = otherPartyPublicKey as ECDiffieHellmanAndroidPublicKey; bool disposeOtherKey = false; if (otherKey == null) { disposeOtherKey = true; ECParameters otherParameters = thisIsNamed ? otherPartyPublicKey.ExportParameters() : otherPartyPublicKey.ExportExplicitParameters(); otherKey = new ECDiffieHellmanAndroidPublicKey(otherParameters); } bool otherIsNamed = otherKey.HasCurveName; SafeEcKeyHandle?ourKey = null; SafeEcKeyHandle?theirKey = null; byte[]? rented = null; // Calculate secretLength in bytes. int secretLength = AsymmetricAlgorithmHelpers.BitsToBytes(KeySize); 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 (ECAndroid tmp = new ECAndroid(otherKey.ExportExplicitParameters())) { theirKey = tmp.UpRefKeyHandle(); } } else { using (ECAndroid tmp = new ECAndroid(thisKeyExplicit)) { ourKey = tmp.UpRefKeyHandle(); } theirKey = otherKey.DuplicateKeyHandle(); } // 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]; } if (!Interop.AndroidCrypto.EcdhDeriveKey(ourKey, theirKey, secret, out int usedBufferLength)) { throw new CryptographicException(); } Debug.Assert(secretLength == usedBufferLength, $"Expected secret length {secretLength} does not match actual secret length {usedBufferLength}."); 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); } } }