125 lines
3.8 KiB
C#
125 lines
3.8 KiB
C#
using Org.BouncyCastle.Crypto.Parameters;
|
|
using Org.BouncyCastle.Utilities;
|
|
|
|
namespace Org.BouncyCastle.Crypto.Tls;
|
|
|
|
public class TlsStreamCipher : TlsCipher
|
|
{
|
|
protected readonly TlsContext context;
|
|
|
|
protected readonly IStreamCipher encryptCipher;
|
|
|
|
protected readonly IStreamCipher decryptCipher;
|
|
|
|
protected readonly TlsMac writeMac;
|
|
|
|
protected readonly TlsMac readMac;
|
|
|
|
protected readonly bool usesNonce;
|
|
|
|
public TlsStreamCipher(TlsContext context, IStreamCipher clientWriteCipher, IStreamCipher serverWriteCipher, IDigest clientWriteDigest, IDigest serverWriteDigest, int cipherKeySize, bool usesNonce)
|
|
{
|
|
bool isServer = context.IsServer;
|
|
this.context = context;
|
|
this.usesNonce = usesNonce;
|
|
encryptCipher = clientWriteCipher;
|
|
decryptCipher = serverWriteCipher;
|
|
int num = 2 * cipherKeySize + clientWriteDigest.GetDigestSize() + serverWriteDigest.GetDigestSize();
|
|
byte[] key = TlsUtilities.CalculateKeyBlock(context, num);
|
|
int num2 = 0;
|
|
TlsMac tlsMac = new TlsMac(context, clientWriteDigest, key, num2, clientWriteDigest.GetDigestSize());
|
|
num2 += clientWriteDigest.GetDigestSize();
|
|
TlsMac tlsMac2 = new TlsMac(context, serverWriteDigest, key, num2, serverWriteDigest.GetDigestSize());
|
|
num2 += serverWriteDigest.GetDigestSize();
|
|
KeyParameter keyParameter = new KeyParameter(key, num2, cipherKeySize);
|
|
num2 += cipherKeySize;
|
|
KeyParameter keyParameter2 = new KeyParameter(key, num2, cipherKeySize);
|
|
num2 += cipherKeySize;
|
|
if (num2 != num)
|
|
{
|
|
throw new TlsFatalAlert(80);
|
|
}
|
|
ICipherParameters parameters;
|
|
ICipherParameters parameters2;
|
|
if (isServer)
|
|
{
|
|
writeMac = tlsMac2;
|
|
readMac = tlsMac;
|
|
encryptCipher = serverWriteCipher;
|
|
decryptCipher = clientWriteCipher;
|
|
parameters = keyParameter2;
|
|
parameters2 = keyParameter;
|
|
}
|
|
else
|
|
{
|
|
writeMac = tlsMac;
|
|
readMac = tlsMac2;
|
|
encryptCipher = clientWriteCipher;
|
|
decryptCipher = serverWriteCipher;
|
|
parameters = keyParameter;
|
|
parameters2 = keyParameter2;
|
|
}
|
|
if (usesNonce)
|
|
{
|
|
byte[] iv = new byte[8];
|
|
parameters = new ParametersWithIV(parameters, iv);
|
|
parameters2 = new ParametersWithIV(parameters2, iv);
|
|
}
|
|
encryptCipher.Init(forEncryption: true, parameters);
|
|
decryptCipher.Init(forEncryption: false, parameters2);
|
|
}
|
|
|
|
public virtual int GetPlaintextLimit(int ciphertextLimit)
|
|
{
|
|
return ciphertextLimit - writeMac.Size;
|
|
}
|
|
|
|
public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
|
|
{
|
|
if (usesNonce)
|
|
{
|
|
UpdateIV(encryptCipher, forEncryption: true, seqNo);
|
|
}
|
|
byte[] array = new byte[len + writeMac.Size];
|
|
encryptCipher.ProcessBytes(plaintext, offset, len, array, 0);
|
|
byte[] array2 = writeMac.CalculateMac(seqNo, type, plaintext, offset, len);
|
|
encryptCipher.ProcessBytes(array2, 0, array2.Length, array, len);
|
|
return array;
|
|
}
|
|
|
|
public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
|
|
{
|
|
if (usesNonce)
|
|
{
|
|
UpdateIV(decryptCipher, forEncryption: false, seqNo);
|
|
}
|
|
int size = readMac.Size;
|
|
if (len < size)
|
|
{
|
|
throw new TlsFatalAlert(50);
|
|
}
|
|
int num = len - size;
|
|
byte[] array = new byte[len];
|
|
decryptCipher.ProcessBytes(ciphertext, offset, len, array, 0);
|
|
CheckMac(seqNo, type, array, num, len, array, 0, num);
|
|
return Arrays.CopyOfRange(array, 0, num);
|
|
}
|
|
|
|
protected virtual void CheckMac(long seqNo, byte type, byte[] recBuf, int recStart, int recEnd, byte[] calcBuf, int calcOff, int calcLen)
|
|
{
|
|
byte[] a = Arrays.CopyOfRange(recBuf, recStart, recEnd);
|
|
byte[] b = readMac.CalculateMac(seqNo, type, calcBuf, calcOff, calcLen);
|
|
if (!Arrays.ConstantTimeAreEqual(a, b))
|
|
{
|
|
throw new TlsFatalAlert(20);
|
|
}
|
|
}
|
|
|
|
protected virtual void UpdateIV(IStreamCipher cipher, bool forEncryption, long seqNo)
|
|
{
|
|
byte[] array = new byte[8];
|
|
TlsUtilities.WriteUint64(seqNo, array, 0);
|
|
cipher.Init(forEncryption, new ParametersWithIV(null, array));
|
|
}
|
|
}
|