SecuCore/TLS/CipherSuites.cs

375 lines
12 KiB
C#
Raw Normal View History

2026-03-03 23:53:04 -05:00
/*
* 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<SymmetricAlgorithm> getBulkFunc;
public Func<HashAlgorithm> getHashFunc;
public Func<byte[], HMAC> createHMACFunc;
public Func<byte[], byte[], X509Cert, bool> verifyHashFunc;
public TLSCipherImplementation(Func<SymmetricAlgorithm> _getBulkFunction, Func<HashAlgorithm> _getHashFunction, Func<byte[], HMAC> _createHMACFunc, Func<byte[], byte[], X509Cert, bool> _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<ushort> usv = new List<ushort>();
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<CipherSuiteValue, Func<TLSCipherSuite>> SupportedSuites = new Dictionary<CipherSuiteValue, Func<TLSCipherSuite>>
{
//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
}
}
}