ChaCha20Poly1305Cipher
ChaCha20Poly1305 cipher implementation.
.
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Transport;
using System;
using System.Buffers.Binary;
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
internal sealed class ChaCha20Poly1305Cipher : SymmetricCipher
{
private readonly byte[] _iv;
private readonly int _aadLength;
private readonly KeyParameter _aadKeyParameter;
private readonly KeyParameter _keyParameter;
private readonly ChaCha7539Engine _aadCipher;
private readonly ChaCha7539Engine _cipher;
private readonly Poly1305 _mac;
public override byte MinimumSize => 16;
public override int TagSize => 16;
public ChaCha20Poly1305Cipher(byte[] key, int aadLength)
: base(key)
{
_iv = new byte[12];
_aadLength = aadLength;
_keyParameter = new KeyParameter(key, 0, 32);
_cipher = new ChaCha7539Engine();
if (aadLength > 0) {
_aadKeyParameter = new KeyParameter(key, 32, 32);
_aadCipher = new ChaCha7539Engine();
}
_mac = new Poly1305();
}
public override byte[] Encrypt(byte[] input, int offset, int length)
{
ChaCha7539Engine aadCipher = _aadCipher;
if (aadCipher != null)
aadCipher.Init(true, new ParametersWithIV(_aadKeyParameter, _iv));
_cipher.Init(true, new ParametersWithIV(_keyParameter, _iv));
byte[] array = new byte[64];
_cipher.ProcessBytes(array, 0, array.Length, array, 0);
_mac.Init(new KeyParameter(array, 0, 32));
byte[] array2 = new byte[length + TagSize];
ChaCha7539Engine aadCipher2 = _aadCipher;
if (aadCipher2 != null)
aadCipher2.ProcessBytes(input, offset, _aadLength, array2, 0);
_cipher.ProcessBytes(input, offset + _aadLength, length - _aadLength, array2, _aadLength);
_mac.BlockUpdate(array2, 0, length);
_mac.DoFinal(array2, length);
return array2;
}
public override byte[] Decrypt(byte[] input)
{
_aadCipher.Init(false, new ParametersWithIV(_aadKeyParameter, _iv));
byte[] array = new byte[input.Length];
_aadCipher.ProcessBytes(input, 0, input.Length, array, 0);
return array;
}
public override byte[] Decrypt(byte[] input, int offset, int length)
{
_cipher.Init(false, new ParametersWithIV(_keyParameter, _iv));
byte[] array = new byte[64];
_cipher.ProcessBytes(array, 0, array.Length, array, 0);
_mac.Init(new KeyParameter(array, 0, 32));
byte[] array2 = new byte[TagSize];
_mac.BlockUpdate(input, offset - _aadLength, length + _aadLength);
_mac.DoFinal(array2, 0);
if (!Arrays.FixedTimeEquals(TagSize, array2, 0, input, offset + length))
throw new SshConnectionException("MAC error", DisconnectReason.MacError);
byte[] array3 = new byte[length];
_cipher.ProcessBytes(input, offset, length, array3, 0);
return array3;
}
internal override void SetSequenceNumber(uint sequenceNumber)
{
BinaryPrimitives.WriteUInt64BigEndian(_iv.AsSpan(4), sequenceNumber);
}
}
}