public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
{
byte[] nonce = new byte[encryptImplicitNonce.Length + record_iv_length];
switch (nonceMode)
{
case NONCE_RFC5288:
Array.Copy(encryptImplicitNonce, 0, nonce, 0, encryptImplicitNonce.Length);
// RFC 5288/6655: The nonce_explicit MAY be the 64-bit sequence number.
TlsUtilities.WriteUint64(seqNo, nonce, encryptImplicitNonce.Length);
break;
case NONCE_DRAFT_CHACHA20_POLY1305:
TlsUtilities.WriteUint64(seqNo, nonce, nonce.Length - 8);
for (int i = 0; i < encryptImplicitNonce.Length; ++i)
{
nonce[i] ^= encryptImplicitNonce[i];
}
break;
default:
throw new TlsFatalAlert(AlertDescription.internal_error);
}
int plaintextOffset = offset;
int plaintextLength = len;
int ciphertextLength = encryptCipher.GetOutputSize(plaintextLength);
byte[] output = new byte[record_iv_length + ciphertextLength];
if (record_iv_length != 0)
{
Array.Copy(nonce, nonce.Length - record_iv_length, output, 0, record_iv_length);
}
int outputPos = record_iv_length;
byte[] additionalData = GetAdditionalData(seqNo, type, plaintextLength);
AeadParameters parameters = new AeadParameters(null, 8 * macSize, nonce, additionalData);
try
{
encryptCipher.Init(true, parameters);
outputPos += encryptCipher.ProcessBytes(plaintext, plaintextOffset, plaintextLength, output, outputPos);
outputPos += encryptCipher.DoFinal(output, outputPos);
}
catch (Exception e)
{
throw new TlsFatalAlert(AlertDescription.internal_error, e);
}
if (outputPos != output.Length)
{
// NOTE: Existing AEAD cipher implementations all give exact output lengths
throw new TlsFatalAlert(AlertDescription.internal_error);
}
return output;
}