public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
{
if (GetPlaintextLimit(len) < 0)
throw new TlsFatalAlert(AlertDescription.decode_error);
byte[] nonce = new byte[decryptImplicitNonce.Length + record_iv_length];
switch (nonceMode)
{
case NONCE_RFC5288:
Array.Copy(decryptImplicitNonce, 0, nonce, 0, decryptImplicitNonce.Length);
Array.Copy(ciphertext, offset, nonce, nonce.Length - record_iv_length, record_iv_length);
break;
case NONCE_DRAFT_CHACHA20_POLY1305:
TlsUtilities.WriteUint64(seqNo, nonce, nonce.Length - 8);
for (int i = 0; i < decryptImplicitNonce.Length; ++i)
{
nonce[i] ^= decryptImplicitNonce[i];
}
break;
default:
throw new TlsFatalAlert(AlertDescription.internal_error);
}
int ciphertextOffset = offset + record_iv_length;
int ciphertextLength = len - record_iv_length;
int plaintextLength = decryptCipher.GetOutputSize(ciphertextLength);
byte[] output = new byte[plaintextLength];
int outputPos = 0;
byte[] additionalData = GetAdditionalData(seqNo, type, plaintextLength);
AeadParameters parameters = new AeadParameters(null, 8 * macSize, nonce, additionalData);
try
{
decryptCipher.Init(false, parameters);
outputPos += decryptCipher.ProcessBytes(ciphertext, ciphertextOffset, ciphertextLength, output, outputPos);
outputPos += decryptCipher.DoFinal(output, outputPos);
}
catch (Exception e)
{
throw new TlsFatalAlert(AlertDescription.bad_record_mac, e);
}
if (outputPos != output.Length)
{
// NOTE: Existing AEAD cipher implementations all give exact output lengths
throw new TlsFatalAlert(AlertDescription.internal_error);
}
return output;
}