/// <summary> /// Creates an encrypted message /// </summary> /// <param name="recipientsEcPublicKey">The public portion of the message recpient's EC key.</param> /// <param name="plaintextMessageAsByteArray">The message to encrypt.</param> public EcEncryptedMessageAesCbcHmacSha256(ECDiffieHellmanPublicKey recipientsEcPublicKey, byte[] plaintextMessageAsByteArray) { ECDiffieHellmanCng oneTimeEcKey = new ECDiffieHellmanCng(CngKey.Create(CngAlgorithm.ECDiffieHellmanP256, null, new CngKeyCreationParameters())); PublicOneTimeEcKey = oneTimeEcKey.PublicKey.ToByteArray(); byte[] sessionKey = oneTimeEcKey.DeriveKeyMaterial(recipientsEcPublicKey); EncryptedMessage = Encryption.EncryptAesCbc(plaintextMessageAsByteArray, sessionKey, addHmac: true); }
/// <summary> /// Derive key material using the formula HASH(secretPrepend || x || secretAppend) where x is the computed /// result of the EC Diffie-Hellman algorithm. /// </summary> /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param> /// <param name="hashAlgorithm">The identifier for the hash algorithm to use.</param> /// <param name="secretPrepend">A value to prepend to the derived secret before hashing. A <c>null</c> value is treated as an empty array.</param> /// <param name="secretAppend">A value to append to the derived secret before hashing. A <c>null</c> value is treated as an empty array.</param> /// <returns>A hashed output suitable for key material</returns> /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception> public virtual byte[] DeriveKeyFromHash( ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm, byte[] secretPrepend, byte[] secretAppend) { throw DerivedClassMustOverride(); }
public static void ExportKey(string Path, ECDiffieHellmanPublicKey Key) { using (BinaryWriter Writer = new BinaryWriter(File.Create(Path))) { Writer.Write((byte)Key.ToByteArray().Length); Writer.Write(Key.ToByteArray()); } }
/// <summary> /// Decrypts the provided data. /// </summary> /// <param name="privateKey">The private key used for decryption.</param> /// <param name="publicKey">The public key used for decryption.</param> /// <param name="nonce">The nonce used for decryption.</param> /// <param name="encryptedData">The data to decrypt.</param> /// <returns>The decrypted data.</returns> public static byte[] Decrypt(ECDiffieHellmanCng privateKey, ECDiffieHellmanPublicKey publicKey, byte[] nonce, byte[] encryptedData) { try { Aes aes = DeriveKeyAndIv(privateKey, publicKey, nonce); return aes.CreateDecryptor().TransformFinalBlock(encryptedData, 0, encryptedData.Length); } catch (Exception E) { throw new DecryptionException(E.ToString()); } }
/// <summary> /// Creates an encrypted message /// </summary> /// <param name="recipientsEcPublicKey">The public portion of the message recpient's EC key.</param> /// <param name="plaintextMessageAsByteArray">The message to encrypt.</param> public EcEncryptedMessageAesCbcHmacSha256(ECDiffieHellmanPublicKey recipientsEcPublicKey, byte[] plaintextMessageAsByteArray) { byte[] sessionKey; using (CngKey oneTimeEcCngKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256)) { using (ECDiffieHellmanCng oneTimeEcKey = new ECDiffieHellmanCng(oneTimeEcCngKey)) { PublicOneTimeEcKey = oneTimeEcKey.PublicKey.ToByteArray(); sessionKey = oneTimeEcKey.DeriveKeyMaterial(recipientsEcPublicKey); } } EncryptedMessage = Encryption.EncryptAesCbc(plaintextMessageAsByteArray, sessionKey, addHmac: true); }
public override byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed) { ArgumentNullException.ThrowIfNull(otherPartyPublicKey); ArgumentNullException.ThrowIfNull(prfLabel); ArgumentNullException.ThrowIfNull(prfSeed); using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey)) { return(Interop.NCrypt.DeriveKeyMaterialTls( secretAgreement, prfLabel, prfSeed, Interop.NCrypt.SecretAgreementFlags.None)); } }
public SafeNCryptSecretHandle DeriveSecretAgreementHandle(ECDiffieHellmanPublicKey otherPartyPublicKey) { if (otherPartyPublicKey == null) { throw new ArgumentNullException("otherPartyPublicKey"); } ECDiffieHellmanCngPublicKey key = otherPartyPublicKey as ECDiffieHellmanCngPublicKey; if (otherPartyPublicKey == null) { throw new ArgumentException(System.SR.GetString("Cryptography_ArgExpectedECDiffieHellmanCngPublicKey")); } using (CngKey key2 = key.Import()) { return(this.DeriveSecretAgreementHandle(key2)); } }
public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) { if (otherPartyPublicKey == null) { throw new ArgumentNullException("otherPartyPublicKey"); } ECDiffieHellmanCngPublicKey key = otherPartyPublicKey as ECDiffieHellmanCngPublicKey; if (otherPartyPublicKey == null) { throw new ArgumentException(System.SR.GetString("Cryptography_ArgExpectedECDiffieHellmanCngPublicKey")); } using (CngKey key2 = key.Import()) { return(this.DeriveKeyMaterial(key2)); } }
// For the public ECDiffieHellmanCng this is exposed as the HashAlgorithm property // which is a CngAlgorithm type. We're not doing that, but we do need the default value // for DeriveKeyMaterial. public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) { if (otherPartyPublicKey == null) { throw new ArgumentNullException(nameof(otherPartyPublicKey)); } // ECDiffieHellmanCng on .NET Framework will throw an ArgumentException in this method // if otherPartyPublicKey is not an ECDiffieHellmanCngPublicKey. All of the other methods // will use Import/Export to coerce the correct type for interop. // None of the other Core types will match that behavior, so the ECDiffieHellman.Create() on // Windows on .NET Core won't, either. // The default behavior for ECDiffieHellmanCng / ECDiffieHellman.Create() on .NET Framework was // to derive from hash, no prepend, no append, SHA-2-256. return(DeriveKeyFromHash(otherPartyPublicKey, HashAlgorithmName.SHA256)); }
public override byte[] DeriveKeyFromHash( ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm, byte[] secretPrepend, byte[] secretAppend) { if (otherPartyPublicKey == null) throw new ArgumentNullException(nameof(otherPartyPublicKey)); if (string.IsNullOrEmpty(hashAlgorithm.Name)) throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm)); return ECDiffieHellmanDerivation.DeriveKeyFromHash( otherPartyPublicKey, hashAlgorithm, secretPrepend, secretAppend, (pubKey, hasher) => DeriveSecretAgreement(pubKey, hasher)); }
public override byte[] DeriveKeyFromHash( ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm, byte[]?secretPrepend, byte[]?secretAppend) { ArgumentNullException.ThrowIfNull(otherPartyPublicKey); ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm)); ThrowIfDisposed(); return(ECDiffieHellmanDerivation.DeriveKeyFromHash( otherPartyPublicKey, hashAlgorithm, secretPrepend, secretAppend, DeriveSecretAgreement)); }
private static Aes DeriveKeyAndIv(ECDiffieHellmanCng privateKey, ECDiffieHellmanPublicKey publicKey, byte[] nonce) { privateKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; privateKey.HashAlgorithm = CngAlgorithm.Sha256; privateKey.SecretAppend = nonce; byte[] keyAndIv = privateKey.DeriveKeyMaterial(publicKey); byte[] key = new byte[16]; Array.Copy(keyAndIv, 0, key, 0, 16); byte[] iv = new byte[16]; Array.Copy(keyAndIv, 16, iv, 0, 16); Aes aes = new AesManaged(); aes.Key = key; aes.IV = iv; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; return aes; }
/// <summary> /// Get a handle to the secret agreement generated between two parties /// </summary> public SafeNCryptSecretHandle DeriveSecretAgreementHandle(ECDiffieHellmanPublicKey otherPartyPublicKey) { if (otherPartyPublicKey == null) { throw new ArgumentNullException("otherPartyPublicKey"); } // We can only work with ECDiffieHellmanCngPublicKeys ECDiffieHellmanCngPublicKey otherKey = otherPartyPublicKey as ECDiffieHellmanCngPublicKey; if (otherPartyPublicKey == null) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgExpectedECDiffieHellmanCngPublicKey)); } using (CngKey importedKey = otherKey.Import()) { return(DeriveSecretAgreementHandle(importedKey)); } }
public override byte[] DeriveKeyFromHash( ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm, byte[]?secretPrepend, byte[]?secretAppend) { ArgumentNullException.ThrowIfNull(otherPartyPublicKey); ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm)); using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey)) { return(Interop.NCrypt.DeriveKeyMaterialHash( secretAgreement, hashAlgorithm.Name, secretPrepend, secretAppend, Interop.NCrypt.SecretAgreementFlags.None)); } }
public override byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed) { if (otherPartyPublicKey == null) { throw new ArgumentNullException(nameof(otherPartyPublicKey)); } if (prfLabel == null) { throw new ArgumentNullException(nameof(prfLabel)); } if (prfSeed == null) { throw new ArgumentNullException(nameof(prfSeed)); } return(ECDiffieHellmanDerivation.DeriveKeyTls( otherPartyPublicKey, prfLabel, prfSeed, (pubKey, hasher) => DeriveSecretAgreement(pubKey, hasher))); }
internal static byte[] DeriveKeyFromHash( ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm, ReadOnlySpan <byte> secretPrepend, ReadOnlySpan <byte> secretAppend, DeriveSecretAgreement deriveSecretAgreement) { Debug.Assert(otherPartyPublicKey != null); Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name)); using (IncrementalHash hash = IncrementalHash.CreateHash(hashAlgorithm)) { hash.AppendData(secretPrepend); byte[]? secretAgreement = deriveSecretAgreement(otherPartyPublicKey, hash); // We want the side effect, and it should not have returned the answer. Debug.Assert(secretAgreement == null); hash.AppendData(secretAppend); return(hash.GetHashAndReset()); } }
/// <summary> /// Given a second party's public key, derive shared key material /// </summary> public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) { Contract.Ensures(Contract.Result <byte[]>() != null); Contract.Assert(m_kdf >= ECDiffieHellmanKeyDerivationFunction.Hash && m_kdf <= ECDiffieHellmanKeyDerivationFunction.Tls); if (otherPartyPublicKey == null) { throw new ArgumentNullException("otherPartyPublicKey"); } // We can only work with ECDiffieHellmanCngPublicKeys ECDiffieHellmanCngPublicKey otherKey = otherPartyPublicKey as ECDiffieHellmanCngPublicKey; if (otherKey == null) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgExpectedECDiffieHellmanCngPublicKey)); } using (CngKey import = otherKey.Import()) { return(DeriveKeyMaterial(import)); } }
/// <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 byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed) { if (otherPartyPublicKey == null) { throw new ArgumentNullException(nameof(otherPartyPublicKey)); } if (prfLabel == null) { throw new ArgumentNullException(nameof(prfLabel)); } if (prfSeed == null) { throw new ArgumentNullException(nameof(prfSeed)); } using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey)) { return(Interop.NCrypt.DeriveKeyMaterialTls( secretAgreement, prfLabel, prfSeed, Interop.NCrypt.SecretAgreementFlags.None)); } }
/// <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); } } }
// This method must be implemented by derived classes. In order to conform to the contract, it cannot be abstract. public virtual byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) { throw DerivedClassMustOverride(); }
public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey !!) { if (otherPartyPublicKey is ECDiffieHellmanCngPublicKey otherKey)
/// <summary> /// Get a handle to the secret agreement generated between two parties /// </summary> public SafeNCryptSecretHandle DeriveSecretAgreementHandle(ECDiffieHellmanPublicKey otherPartyPublicKey) { if (otherPartyPublicKey == null) { throw new ArgumentNullException("otherPartyPublicKey"); } // We can only work with ECDiffieHellmanCngPublicKeys ECDiffieHellmanCngPublicKey otherKey = otherPartyPublicKey as ECDiffieHellmanCngPublicKey; if (otherPartyPublicKey == null) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgExpectedECDiffieHellmanCngPublicKey)); } using (CngKey importedKey = otherKey.Import()) { return DeriveSecretAgreementHandle(importedKey); } }
public override byte[] DeriveKeyFromHash( ECDiffieHellmanPublicKey otherPartyPublicKey !!,
private byte[]? DeriveSecretAgreement(ECDiffieHellmanPublicKey otherPartyPublicKey, IncrementalHash?hasher) { if (!(otherPartyPublicKey is ECDiffieHellmanSecurityTransformsPublicKey secTransPubKey)) { secTransPubKey = new ECDiffieHellmanSecurityTransformsPublicKey(otherPartyPublicKey.ExportParameters()); } try { SafeSecKeyRefHandle otherPublic = secTransPubKey.KeyHandle; if (Interop.AppleCrypto.EccGetKeySizeInBits(otherPublic) != KeySize) { throw new ArgumentException( SR.Cryptography_ArgECDHKeySizeMismatch, nameof(otherPartyPublicKey)); } SafeSecKeyRefHandle?thisPrivate = GetKeys().PrivateKey; if (thisPrivate == null) { throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); } // Since Apple only supports secp256r1, secp384r1, and secp521r1; and 521 fits in // 66 bytes ((521 + 7) / 8), the Span path will always succeed. Span <byte> secretSpan = stackalloc byte[66]; byte[]? secret = Interop.AppleCrypto.EcdhKeyAgree( thisPrivate, otherPublic, secretSpan, out int bytesWritten); // Either we wrote to the span or we returned an array, but not both, and not neither. // ("neither" would have thrown) Debug.Assert( (bytesWritten == 0) != (secret == null), $"bytesWritten={bytesWritten}, (secret==null)={secret == null}"); if (hasher == null) { return(secret ?? secretSpan.Slice(0, bytesWritten).ToArray()); } if (secret == null) { hasher.AppendData(secretSpan.Slice(0, bytesWritten)); } else { hasher.AppendData(secret); Array.Clear(secret, 0, secret.Length); } return(null); } finally { if (!ReferenceEquals(otherPartyPublicKey, secTransPubKey)) { secTransPubKey.Dispose(); } } }
public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) { if (otherPartyPublicKey == null) { throw new ArgumentNullException("otherPartyPublicKey"); } ECDiffieHellmanCngPublicKey key = otherPartyPublicKey as ECDiffieHellmanCngPublicKey; if (otherPartyPublicKey == null) { throw new ArgumentException(System.SR.GetString("Cryptography_ArgExpectedECDiffieHellmanCngPublicKey")); } using (CngKey key2 = key.Import()) { return this.DeriveKeyMaterial(key2); } }
public Microsoft.Win32.SafeHandles.SafeNCryptSecretHandle DeriveSecretAgreementHandle(ECDiffieHellmanPublicKey otherPartyPublicKey) { Contract.Ensures(this.Key.Handle != null); return default(Microsoft.Win32.SafeHandles.SafeNCryptSecretHandle); }
public override byte[] ProcessServerKeys(ProtocolVersion version, byte[] data) { // Only ECCurveType.named_curve is supported if (data[0] != 3) { throw new Exception("ECCurveType " + data[0] + " is not supported"); } // Create our ECDiffieHellmanCng provider with correct curve UInt16 namedCurve = (UInt16) ((data[1] << 8) + data[2]); _ecdhCng = new ECDiffieHellmanCng(NamedCurveToKeySize(namedCurve)); // Extract the ECPoint data int keyLength = data[3]; byte[] ecPoint = new byte[keyLength]; Buffer.BlockCopy(data, 4, ecPoint, 0, keyLength); // Extract the signature byte[] signature = new byte[data.Length-4-keyLength]; Buffer.BlockCopy(data, 4+keyLength, signature, 0, data.Length-4-keyLength); // Create the public key from the ecPoint byte[] keyBlob = Point2Blob(ecPoint); _publicKey = ECDiffieHellmanCngPublicKey.FromByteArray(keyBlob, CngKeyBlobFormat.EccPublicBlob); return signature; }
/// <summary> /// Initializes a new instance of the <see cref="ECDiffieHellmanPublicKey"/> class. /// </summary> /// <param name="publicKey">The underlying platform public key.</param> internal ECDiffieHellmanPublicKey(Platform.ECDiffieHellmanPublicKey publicKey) { Requires.NotNull(publicKey, nameof(publicKey)); this.publicKey = publicKey; }
/// <summary> /// Initializes a new instance of the <see cref="ECDiffieHellmanPublicKey"/> class. /// </summary> /// <param name="publicKey">The underlying platform public key.</param> internal ECDiffieHellmanPublicKey(Platform.ECDiffieHellmanPublicKey publicKey) { Requires.NotNull(publicKey, nameof(publicKey)); this.publicKey = publicKey; }
public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) => _wrapped.DeriveKeyMaterial(Unwrap(otherPartyPublicKey));
private ECPublicKeyParameters GetPublicKeyParameters(ECDiffieHellmanPublicKey publicKey) { byte[] ecdhBlob = publicKey.ToByteArray(); int keySize; string magic = Encoding.ASCII.GetString(ecdhBlob, 0, 4); if (magic.Equals("ECK1")) { keySize = 256; } else if (magic.Equals("ECK3")) { keySize = 384; } else if (magic.Equals("ECK5")) { keySize = 521; } else { throw new Exception("Unknown public key type"); } if (keySize != _keySize) { throw new Exception("Public key size doesn't match our key size"); } byte[] encoded = new byte[1 + ecdhBlob.Length - 8]; encoded[0] = 0x04; Buffer.BlockCopy(ecdhBlob, 8, encoded, 1, ecdhBlob.Length - 8); Org.BouncyCastle.Math.EC.ECPoint ecPoint = _domainParameters.Curve.DecodePoint(encoded); return new ECPublicKeyParameters(ecPoint, _domainParameters); }
public byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) { ECPublicKeyParameters publicKey = GetPublicKeyParameters(otherPartyPublicKey); // Calculate the shared secret from public key Org.BouncyCastle.Crypto.Agreement.ECDHBasicAgreement agreement = new Org.BouncyCastle.Crypto.Agreement.ECDHBasicAgreement(); agreement.Init(_privateKeyParameters); byte[] secret = agreement.CalculateAgreement(publicKey).ToByteArray(); // Make sure the secret is always correct length byte[] tmpSecret = new byte[(_keySize+7)/8]; Buffer.BlockCopy(secret, System.Math.Max(0, secret.Length-tmpSecret.Length), tmpSecret, System.Math.Max(0, tmpSecret.Length-secret.Length), System.Math.Min(tmpSecret.Length, secret.Length)); secret = tmpSecret; if (_kdf == ECDiffieHellmanKeyDerivationFunction.Hash || _kdf == ECDiffieHellmanKeyDerivationFunction.Hmac) { HashAlgorithm hashAlgorithm; if (_kdf == ECDiffieHellmanKeyDerivationFunction.Hash) { if (_hashAlgorithm.Equals(CngAlgorithm.MD5)) { hashAlgorithm = new MD5CryptoServiceProvider(); } else if (_hashAlgorithm.Equals(CngAlgorithm.Sha1)) { hashAlgorithm = new SHA1CryptoServiceProvider(); } else if (_hashAlgorithm.Equals(CngAlgorithm.Sha256)) { hashAlgorithm = new SHA256Managed(); } else if (_hashAlgorithm.Equals(CngAlgorithm.Sha384)) { hashAlgorithm = new SHA384Managed(); } else if (_hashAlgorithm.Equals(CngAlgorithm.Sha512)) { hashAlgorithm = new SHA512Managed(); } else { throw new Exception("Unsupported hash algorithm type: " + _hashAlgorithm); } } else { byte[] hmacKey = _hmacKey; if (UseSecretAgreementAsHmacKey) { hmacKey = secret; } if (_hashAlgorithm.Equals(CngAlgorithm.MD5)) { hashAlgorithm = new HMACMD5(hmacKey); } else if (_hashAlgorithm.Equals(CngAlgorithm.Sha1)) { hashAlgorithm = new HMACSHA1(hmacKey); } else if (_hashAlgorithm.Equals(CngAlgorithm.Sha256)) { hashAlgorithm = new HMACSHA256(hmacKey); } else if (_hashAlgorithm.Equals(CngAlgorithm.Sha384)) { hashAlgorithm = new HMACSHA384(hmacKey); } else if (_hashAlgorithm.Equals(CngAlgorithm.Sha512)) { hashAlgorithm = new HMACSHA512(hmacKey); } else { throw new Exception("Unsupported hash algorithm type: " + _hashAlgorithm); } } hashAlgorithm.Initialize(); if (_secretPrepend != null) { hashAlgorithm.TransformBlock(_secretPrepend, 0, _secretPrepend.Length, _secretPrepend, 0); } hashAlgorithm.TransformBlock(secret, 0, secret.Length, secret, 0); if (_secretAppend != null) { hashAlgorithm.TransformBlock(_secretAppend, 0, _secretAppend.Length, _secretAppend, 0); } hashAlgorithm.TransformFinalBlock(new byte[0], 0, 0); return hashAlgorithm.Hash; } throw new Exception("KeyDerivationFunction not implemented yet"); }
public SafeNCryptSecretHandle DeriveSecretAgreementHandle(ECDiffieHellmanPublicKey otherPartyPublicKey) { if (otherPartyPublicKey == null) { throw new ArgumentNullException("otherPartyPublicKey"); } ECDiffieHellmanCngPublicKey key = otherPartyPublicKey as ECDiffieHellmanCngPublicKey; if (otherPartyPublicKey == null) { throw new ArgumentException(System.SR.GetString("Cryptography_ArgExpectedECDiffieHellmanCngPublicKey")); } using (CngKey key2 = key.Import()) { return this.DeriveSecretAgreementHandle(key2); } }
public abstract byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey);
/// <summary> /// Derive key material using the formula HMAC(hmacKey, x) where x is the computed /// result of the EC Diffie-Hellman algorithm. /// </summary> /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param> /// <param name="hashAlgorithm">The identifier for the hash algorithm to use.</param> /// <param name="hmacKey">The key to use in the HMAC. A <c>null</c> value indicates that the result of the EC Diffie-Hellman algorithm should be used as the HMAC key.</param> /// <returns>A hashed output suitable for key material</returns> /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception> public byte[] DeriveKeyFromHmac( ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm, byte[] hmacKey) { return DeriveKeyFromHmac(otherPartyPublicKey, hashAlgorithm, hmacKey, null, null); }
/// <summary> /// Encrypt a plaintext incorrect password with the account's EC Diffie Helman public key so that it can /// be safely stored until the correct password is provided in the future. Store it in the /// EncryptedIncorrectPassword field. (This doesn't expose information about the correct password because /// the corresponding EC secret key needed to decrypt this incorrect password is itself encrypted with the /// phase1 hash of the correct password.) /// /// The encryption format is a JSON-encoded EcEncryptedMessageAesCbcHmacSha256. /// </summary> /// <param name="incorrectPassword">The incorrect password to be stored into the EncryptedIncorrectPassword /// field.</param> /// <param name="ecPublicLogKey">The public key used to encrypt the incorrect password.</param> public void EncryptAndWriteIncorrectPassword(string incorrectPassword, ECDiffieHellmanPublicKey ecPublicLogKey) { EncryptedIncorrectPassword = JsonConvert.SerializeObject( new EcEncryptedMessageAesCbcHmacSha256(ecPublicLogKey, Encoding.UTF8.GetBytes(incorrectPassword))); }
internal static unsafe byte[] DeriveKeyTls( ECDiffieHellmanPublicKey otherPartyPublicKey, ReadOnlySpan <byte> prfLabel, ReadOnlySpan <byte> prfSeed, DeriveSecretAgreement deriveSecretAgreement) { Debug.Assert(otherPartyPublicKey != null); if (prfSeed.Length != 64) { throw new CryptographicException(SR.Cryptography_TlsRequires64ByteSeed); } // Windows produces a 48-byte output, so that's what we do, too. byte[] ret = new byte[48]; const int Sha1Size = 20; const int Md5Size = 16; byte[]? secretAgreement = deriveSecretAgreement(otherPartyPublicKey, null); Debug.Assert(secretAgreement != null); // Reduce the likelihood of the value getting copied during heap compaction. fixed(byte *pinnedSecretAgreement = secretAgreement) { try { // https://tools.ietf.org/html/rfc4346#section-5 // // S1 and S2 are the two halves of the secret, and each is the same // length. S1 is taken from the first half of the secret, S2 from the // second half. Their length is created by rounding up the length of // the overall secret, divided by two; thus, if the original secret is // an odd number of bytes long, the last byte of S1 will be the same as // the first byte of S2. // int half = secretAgreement.Length / 2; int odd = secretAgreement.Length & 1; // PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR // P_SHA-1(S2, label + seed); PHash( HashAlgorithmName.MD5, new ReadOnlySpan <byte>(secretAgreement, 0, half + odd), prfLabel, prfSeed, Md5Size, ret); Span <byte> part2 = stackalloc byte[ret.Length]; PHash( HashAlgorithmName.SHA1, new ReadOnlySpan <byte>(secretAgreement, half, half + odd), prfLabel, prfSeed, Sha1Size, part2); for (int i = 0; i < ret.Length; i++) { ret[i] ^= part2[i]; } return(ret); } finally { Array.Clear(secretAgreement, 0, secretAgreement.Length); } } }
public override byte[] DeriveKeyFromHmac( ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm, byte[] hmacKey, byte[] secretPrepend, byte[] secretAppend) { Contract.Ensures(Contract.Result<byte[]>() != null); if (otherPartyPublicKey == null) throw new ArgumentNullException("otherPartyPublicKey"); if (string.IsNullOrEmpty(hashAlgorithm.Name)) throw new ArgumentException(SR.GetString(SR.Cryptography_HashAlgorithmNameNullOrEmpty), "hashAlgorithm"); using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey)) { NCryptNative.SecretAgreementFlags flags = hmacKey == null ? NCryptNative.SecretAgreementFlags.UseSecretAsHmacKey : NCryptNative.SecretAgreementFlags.None; return NCryptNative.DeriveKeyMaterialHmac( secretAgreement, hashAlgorithm.Name, hmacKey, secretPrepend, secretAppend, flags); } }
/// <summary> /// Given a second party's public key, derive shared key material /// </summary> public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) { Contract.Ensures(Contract.Result<byte[]>() != null); Contract.Assert(m_kdf >= ECDiffieHellmanKeyDerivationFunction.Hash && m_kdf <= ECDiffieHellmanKeyDerivationFunction.Tls); if (otherPartyPublicKey == null) { throw new ArgumentNullException("otherPartyPublicKey"); } // We can only work with ECDiffieHellmanCngPublicKeys ECDiffieHellmanCngPublicKey otherKey = otherPartyPublicKey as ECDiffieHellmanCngPublicKey; if (otherPartyPublicKey == null) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgExpectedECDiffieHellmanCngPublicKey)); } using (CngKey import = otherKey.Import()) { return DeriveKeyMaterial(import); } }
public override byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed) { Contract.Ensures(Contract.Result<byte[]>() != null); if (otherPartyPublicKey == null) throw new ArgumentNullException("otherPartyPublicKey"); if (prfLabel == null) throw new ArgumentNullException("prfLabel"); if (prfSeed == null) throw new ArgumentNullException("prfSeed"); using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey)) { return NCryptNative.DeriveKeyMaterialTls( secretAgreement, prfLabel, prfSeed, NCryptNative.SecretAgreementFlags.None); } }
public abstract byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey);
public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) { return default(byte[]); }
/// <summary> /// Derive key material using the TLS pseudo-random function (PRF) derivation algorithm. /// </summary> /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param> /// <param name="prfLabel">The ASCII encoded PRF label.</param> /// <param name="prfSeed">The 64-byte PRF seed.</param> /// <returns>A 48-byte output of the TLS pseudo-random function.</returns> /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception> /// <exception cref="ArgumentNullException"><paramref name="prfLabel"/> is null</exception> /// <exception cref="ArgumentNullException"><paramref name="prfSeed"/> is null</exception> /// <exception cref="CryptographicException"><paramref name="prfSeed"/> is not exactly 64 bytes in length</exception> public virtual byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed) { throw DerivedClassMustOverride(); }
/// <summary> /// Derive key material using the TLS pseudo-random function (PRF) derivation algorithm. /// </summary> /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param> /// <param name="prfLabel">The ASCII encoded PRF label.</param> /// <param name="prfSeed">The 64-byte PRF seed.</param> /// <returns>A 48-byte output of the TLS pseudo-random function.</returns> /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception> /// <exception cref="ArgumentNullException"><paramref name="prfLabel"/> is null</exception> /// <exception cref="ArgumentNullException"><paramref name="prfSeed"/> is null</exception> /// <exception cref="CryptographicException"><paramref name="prfSeed"/> is not exactly 64 bytes in length</exception> public virtual byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed) { throw DerivedClassMustOverride(); }
/// <summary> /// Derive key material using the formula HASH(x) where x is the computed result of the EC Diffie-Hellman algorithm. /// </summary> /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param> /// <param name="hashAlgorithm">The identifier for the hash algorithm to use.</param> /// <returns>A hashed output suitable for key material</returns> /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception> public byte[] DeriveKeyFromHash(ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm) { return(DeriveKeyFromHash(otherPartyPublicKey, hashAlgorithm, null, null)); }
// This method must be implemented by derived classes. In order to conform to the contract, it cannot be abstract. public virtual byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) { throw DerivedClassMustOverride(); }
public override byte[] DeriveKeyFromHash( ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm, byte[]?secretPrepend, byte[]?secretAppend) => _wrapped.DeriveKeyFromHash(Unwrap(otherPartyPublicKey), hashAlgorithm, secretPrepend, secretAppend);
/// <summary> /// Encrypts the provided data. /// </summary> /// <param name="privateKey">The private key used for encryption.</param> /// <param name="publicKey">The public key used for encryption.</param> /// <param name="nonce">The nonce used for encryption.</param> /// <param name="data">The data to encrypt.</param> /// <returns>The encrypted data.</returns> public static byte[] Encrypt(ECDiffieHellmanCng privateKey, ECDiffieHellmanPublicKey publicKey, byte[] nonce, byte[] data) { Aes aes = DeriveKeyAndIv(privateKey, publicKey, nonce); return aes.CreateEncryptor().TransformFinalBlock(data, 0, data.Length); }
public override byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed) => _wrapped.DeriveKeyTls(Unwrap(otherPartyPublicKey), prfLabel, prfSeed);
public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) { return(default(byte[])); }
/// <summary> /// Given a second party's public key, derive shared key material /// </summary> public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) => DeriveKeyFromHash(otherPartyPublicKey, HashAlgorithmName.SHA256, null, null);
public Microsoft.Win32.SafeHandles.SafeNCryptSecretHandle DeriveSecretAgreementHandle(ECDiffieHellmanPublicKey otherPartyPublicKey) { Contract.Ensures(this.Key.Handle != null); return(default(Microsoft.Win32.SafeHandles.SafeNCryptSecretHandle)); }
/// <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); } } }
public override void ProcessClientKeys(ProtocolVersion version, ProtocolVersion clientVersion, CertificatePrivateKey privateKey, byte[] data) { if (data[0] != data.Length-1) { throw new Exception("Incorrect ECPoint length"); } // Exctract the ECPoint byte[] ecPoint = new byte[data.Length-1]; Buffer.BlockCopy(data, 1, ecPoint, 0, ecPoint.Length); // Create key blob and public key byte[] keyBlob = Point2Blob(ecPoint); _publicKey = ECDiffieHellmanCngPublicKey.FromByteArray(keyBlob, CngKeyBlobFormat.EccPublicBlob); }