/* * Secucore * * Copyright (C) 2023 Trevor Hall * All rights reserved. * * This software may be modified and distributed under the terms * of the MIT license. * */ using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using SecuCore.Security; namespace SecuCore.TLS { public static class CipherSuites { public enum ConnectionEnd { SERVER, CLIENT } public enum PRFAlgorithm { LEGACY, TLS_PRF_SHA256, TLS_PRF_SHA384 } public enum KeyExchangeAlgorithm { NULL, RSA, RSA_EXPORT, DHE_DSS, DHE_DSS_EXPORT, DHE_RSA, DHE_RSA_EXPORT, DH_DSS, DH_DSS_EXPORT, DH_RSA, DH_RSA_EXPORT, DH_anon, DH_anon_EXPORT, //RFC 4279 PSK, DHE_PSK, RSA_PSK, //RFC 4429 ECDH_ECDSA, ECDHE_ECDSA, ECDH_RSA, ECDHE_RSA, ECDH_anon, //RFC 5054 SRP, SRP_DSS, SRP_RSA, //RFC 5489 ECDHE_PSK } public enum BulkCipherAlgorithm { NULL, RC4, RC2, DES, _3DES, DES40, AES, IDEA } public enum CipherType { STREAM, BLOCK, AEAD } public enum MACAlgorithm { NULL, MD5, SHA, HMAC_MD5 = MD5, HMAC_SHA1 = SHA, HMAC_SHA256, HMAC_SHA384, HMAC_SHA512 } public enum CompressionMethod { NULL, DEFLATE } public class SecurityParameters { public ConnectionEnd entity; public BulkCipherAlgorithm bulk_cipher_algorithm; public CipherType cipher_type; public byte key_size; public CompressionMethod compression_algorithm; public byte[] master_secret; public byte[] client_random; public byte[] server_random; } public enum BulkAlgorithmType { Stream, Block, AEAD } public class TLSEncryptionProvider { public TLSCipherSuite tcs; public BulkAlgorithmType bulkAlgorithmType; public int AuthenticationTagSize; public int HashSize; public int IVSize; public int BlockSize; public KeyedHashAlgorithm LocalHasher; public KeyedHashAlgorithm RemoteHasher; public ICryptoTransform Encryptor; public ICryptoTransform Decryptor; private void DisposeIfExists(IDisposable d) { if (d != null) d.Dispose(); } public void Dispose() { DisposeIfExists(Decryptor); DisposeIfExists(Encryptor); DisposeIfExists(LocalHasher); DisposeIfExists(RemoteHasher); } } public class TLSCipherImplementation { public Func getBulkFunc; public Func getHashFunc; public Func createHMACFunc; public Func verifyHashFunc; public TLSCipherImplementation(Func _getBulkFunction, Func _getHashFunction, Func _createHMACFunc, Func _verifyHashFunc) { this.getBulkFunc = _getBulkFunction; this.getHashFunc = _getHashFunction; this.createHMACFunc = _createHMACFunc; this.verifyHashFunc = _verifyHashFunc; } public SymmetricAlgorithm GetBulker() => getBulkFunc.Invoke(); public HashAlgorithm GetHasher() => getHashFunc.Invoke(); public HMAC CreateHMAC(byte[] key) => createHMACFunc.Invoke(key); public bool VerifyHash(byte[] hash, byte[] sig, X509Cert cert) => verifyHashFunc.Invoke(hash, sig, cert); } public struct TLSCipherParameters { public int CipherSuite; public string BulkCipherAlgorithmName; public int BlockSize; public int HashSize; public int BulkKeySize; public int BulkIVSize; public CipherMode cipherMode; public KeyExchangeAlgorithm keyExchangeAlgorithm; } public class TLSCipherSuite { public TLSCipherParameters tlsparams; TLSCipherImplementation implementation; public byte[] clWriteKey; public byte[] clWriteMAC; public TLSCipherSuite(TLSCipherImplementation impl, TLSCipherParameters _tlsparams) { this.implementation = impl; this.tlsparams = _tlsparams; } public SymmetricAlgorithm GetBulker() { SymmetricAlgorithm bulker = implementation.GetBulker(); bulker.Mode = tlsparams.cipherMode; bulker.Padding = PaddingMode.None; return bulker; } public HashAlgorithm GetHasher() => implementation.GetHasher(); public HMAC CreateHMAC(byte[] key) => implementation.CreateHMAC(key); public bool VerifyHash(byte[] hash, byte[] sig, X509Cert cert) => implementation.VerifyHash(hash, sig, cert); public TLSEncryptionProvider InitializeEncryption(KeyDerivation.KeyExpansionResult keyring) { clWriteKey = keyring.clientWriteKey; clWriteMAC = keyring.clientWriteMac; SymmetricAlgorithm localBulker = GetBulker(); localBulker.Key = keyring.clientWriteKey; SymmetricAlgorithm remoteBulker = GetBulker(); remoteBulker.Key = keyring.serverWriteKey; KeyedHashAlgorithm localHasher = new HMACSHA1(keyring.clientWriteMac); KeyedHashAlgorithm remoteHasher = new HMACSHA1(keyring.serverWriteMac); return new TLSEncryptionProvider { tcs = this, AuthenticationTagSize = 0, bulkAlgorithmType = BulkAlgorithmType.Block, BlockSize = tlsparams.BlockSize, IVSize = tlsparams.BulkIVSize, HashSize = tlsparams.HashSize, Encryptor = localBulker.CreateEncryptor(), Decryptor = remoteBulker.CreateDecryptor(), LocalHasher = localHasher, RemoteHasher = remoteHasher }; } } private static bool VerifyHashEDCSA(byte[] hash, byte[] sig, X509Cert publicCert) { using (ECDsa ecd = ECDsaCertificateExtensions.GetECDsaPublicKey(new X509Certificate2(publicCert.sourceData))) { bool valid = ecd.VerifyHash(hash, sig, DSASignatureFormat.Rfc3279DerSequence); return valid; } } private static bool VerifyHashRSA(byte[] hash, byte[] sig, X509Cert publicCert) { RSAPublicKey rpk = publicCert.GetRSAPublicKey(); byte[] decrypted = rpk.DecryptSignature(sig); byte[] actualhash; if (decrypted.Length == 36) { actualhash = decrypted; } else { actualhash = Asn1Tools.ParseHash(decrypted); } if (Asn1Tools.HashesEqual(hash, actualhash)) { return true; } return false; } private static HashAlgorithm CreateSha1() { return SHA1.Create(); } private static HashAlgorithm CreateSha256() { return SHA256.Create(); } private static SymmetricAlgorithm CreateAes() { AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider { BlockSize = 128, KeySize = 128, Padding = PaddingMode.None, Mode = CipherMode.CBC, }; return aesProvider; } private static HMAC CreateSha1Hmac(byte[] key) { return new HMACSHA1(key); } private static HMAC CreateSha256Hmac(byte[] key) { return new HMACSHA256(key); } public static ushort[] GetSupportedCipherSuites() { CipherSuiteValue[] cipherSuiteValues = SupportedSuites.Keys.ToList().ToArray(); List usv = new List(); foreach (var cipherSuiteValue in cipherSuiteValues) usv.Add((ushort)cipherSuiteValue); return usv.ToArray(); } public static TLSCipherSuite InitializeCipherSuite(ushort ciphersuitevalue) { CipherSuiteValue key = (CipherSuiteValue)ciphersuitevalue; return SupportedSuites[key].Invoke(); } public static Dictionary> SupportedSuites = new Dictionary> { //TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA { CipherSuiteValue.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, ()=>{ return new TLSCipherSuite( new TLSCipherImplementation(CreateAes,CreateSha1,CreateSha256Hmac,VerifyHashRSA), new TLSCipherParameters() { BlockSize = 16, BulkCipherAlgorithmName = "AES", BulkIVSize = 16, BulkKeySize = 16, HashSize = 20, cipherMode = CipherMode.CBC, CipherSuite = (int)CipherSuiteValue.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, keyExchangeAlgorithm = KeyExchangeAlgorithm.ECDHE_RSA } ); } }, //TLS_RSA_WITH_AES_128_CBC_SHA { CipherSuiteValue.TLS_RSA_WITH_AES_128_CBC_SHA, ()=>{ return new TLSCipherSuite( new TLSCipherImplementation(CreateAes,CreateSha1,CreateSha256Hmac,VerifyHashRSA), new TLSCipherParameters() { BlockSize = 16, BulkCipherAlgorithmName = "AES", BulkIVSize = 16, BulkKeySize = 16, HashSize = 20, cipherMode = CipherMode.CBC, CipherSuite = (int)CipherSuiteValue.TLS_RSA_WITH_AES_128_CBC_SHA, keyExchangeAlgorithm = KeyExchangeAlgorithm.RSA } ); } }, { CipherSuiteValue.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, ()=>{ return new TLSCipherSuite( new TLSCipherImplementation(CreateAes,CreateSha1,CreateSha256Hmac,VerifyHashEDCSA), new TLSCipherParameters() { BlockSize = 16, BulkCipherAlgorithmName = "AES", BulkIVSize = 16, BulkKeySize = 16, HashSize = 20, cipherMode = CipherMode.CBC, CipherSuite = (int)CipherSuiteValue.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, keyExchangeAlgorithm = KeyExchangeAlgorithm.ECDHE_ECDSA } ); } } }; public enum CipherSuiteValue { TLS_RSA_WITH_AES_128_CBC_SHA = 47, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 49171, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 49161 } } }