init commit

This commit is contained in:
2025-10-09 09:57:24 +09:00
commit 4d551bd74f
6636 changed files with 1218703 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Modes;
public class CbcBlockCipher : IBlockCipher
{
private byte[] IV;
private byte[] cbcV;
private byte[] cbcNextV;
private int blockSize;
private IBlockCipher cipher;
private bool encrypting;
public string AlgorithmName => cipher.AlgorithmName + "/CBC";
public bool IsPartialBlockOkay => false;
public CbcBlockCipher(IBlockCipher cipher)
{
this.cipher = cipher;
blockSize = cipher.GetBlockSize();
IV = new byte[blockSize];
cbcV = new byte[blockSize];
cbcNextV = new byte[blockSize];
}
public IBlockCipher GetUnderlyingCipher()
{
return cipher;
}
public void Init(bool forEncryption, ICipherParameters parameters)
{
bool flag = encrypting;
encrypting = forEncryption;
if (parameters is ParametersWithIV)
{
ParametersWithIV parametersWithIV = (ParametersWithIV)parameters;
byte[] iV = parametersWithIV.GetIV();
if (iV.Length != blockSize)
{
throw new ArgumentException("initialisation vector must be the same length as block size");
}
Array.Copy(iV, 0, IV, 0, iV.Length);
parameters = parametersWithIV.Parameters;
}
Reset();
if (parameters != null)
{
cipher.Init(encrypting, parameters);
}
else if (flag != encrypting)
{
throw new ArgumentException("cannot change encrypting state without providing key.");
}
}
public int GetBlockSize()
{
return cipher.GetBlockSize();
}
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (!encrypting)
{
return DecryptBlock(input, inOff, output, outOff);
}
return EncryptBlock(input, inOff, output, outOff);
}
public void Reset()
{
Array.Copy(IV, 0, cbcV, 0, IV.Length);
Array.Clear(cbcNextV, 0, cbcNextV.Length);
cipher.Reset();
}
private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
if (inOff + blockSize > input.Length)
{
throw new DataLengthException("input buffer too short");
}
for (int i = 0; i < blockSize; i++)
{
byte[] array2;
byte[] array = (array2 = cbcV);
int num = i;
nint num2 = num;
array[num] = (byte)(array2[num2] ^ input[inOff + i]);
}
int result = cipher.ProcessBlock(cbcV, 0, outBytes, outOff);
Array.Copy(outBytes, outOff, cbcV, 0, cbcV.Length);
return result;
}
private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
if (inOff + blockSize > input.Length)
{
throw new DataLengthException("input buffer too short");
}
Array.Copy(input, inOff, cbcNextV, 0, blockSize);
int result = cipher.ProcessBlock(input, inOff, outBytes, outOff);
for (int i = 0; i < blockSize; i++)
{
byte[] array2;
byte[] array = (array2 = outBytes);
int num = outOff + i;
nint num2 = num;
array[num] = (byte)(array2[num2] ^ cbcV[i]);
}
byte[] array3 = cbcV;
cbcV = cbcNextV;
cbcNextV = array3;
return result;
}
}

View File

@@ -0,0 +1,319 @@
using System;
using System.IO;
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes;
public class CcmBlockCipher : IAeadBlockCipher
{
private static readonly int BlockSize = 16;
private readonly IBlockCipher cipher;
private readonly byte[] macBlock;
private bool forEncryption;
private byte[] nonce;
private byte[] initialAssociatedText;
private int macSize;
private ICipherParameters keyParam;
private readonly MemoryStream associatedText = new MemoryStream();
private readonly MemoryStream data = new MemoryStream();
public virtual string AlgorithmName => cipher.AlgorithmName + "/CCM";
public CcmBlockCipher(IBlockCipher cipher)
{
this.cipher = cipher;
macBlock = new byte[BlockSize];
if (cipher.GetBlockSize() != BlockSize)
{
throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
}
}
public virtual IBlockCipher GetUnderlyingCipher()
{
return cipher;
}
public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
this.forEncryption = forEncryption;
ICipherParameters cipherParameters;
if (parameters is AeadParameters)
{
AeadParameters aeadParameters = (AeadParameters)parameters;
nonce = aeadParameters.GetNonce();
initialAssociatedText = aeadParameters.GetAssociatedText();
macSize = aeadParameters.MacSize / 8;
cipherParameters = aeadParameters.Key;
}
else
{
if (!(parameters is ParametersWithIV))
{
throw new ArgumentException("invalid parameters passed to CCM");
}
ParametersWithIV parametersWithIV = (ParametersWithIV)parameters;
nonce = parametersWithIV.GetIV();
initialAssociatedText = null;
macSize = macBlock.Length / 2;
cipherParameters = parametersWithIV.Parameters;
}
if (cipherParameters != null)
{
keyParam = cipherParameters;
}
if (nonce == null || nonce.Length < 7 || nonce.Length > 13)
{
throw new ArgumentException("nonce must have length from 7 to 13 octets");
}
Reset();
}
public virtual int GetBlockSize()
{
return cipher.GetBlockSize();
}
public virtual void ProcessAadByte(byte input)
{
associatedText.WriteByte(input);
}
public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
{
associatedText.Write(inBytes, inOff, len);
}
public virtual int ProcessByte(byte input, byte[] outBytes, int outOff)
{
data.WriteByte(input);
return 0;
}
public virtual int ProcessBytes(byte[] inBytes, int inOff, int inLen, byte[] outBytes, int outOff)
{
Check.DataLength(inBytes, inOff, inLen, "Input buffer too short");
data.Write(inBytes, inOff, inLen);
return 0;
}
public virtual int DoFinal(byte[] outBytes, int outOff)
{
byte[] buffer = data.GetBuffer();
int inLen = (int)data.Position;
int result = ProcessPacket(buffer, 0, inLen, outBytes, outOff);
Reset();
return result;
}
public virtual void Reset()
{
cipher.Reset();
associatedText.SetLength(0L);
data.SetLength(0L);
}
public virtual byte[] GetMac()
{
return Arrays.CopyOfRange(macBlock, 0, macSize);
}
public virtual int GetUpdateOutputSize(int len)
{
return 0;
}
public virtual int GetOutputSize(int len)
{
int num = (int)data.Length + len;
if (forEncryption)
{
return num + macSize;
}
if (num >= macSize)
{
return num - macSize;
}
return 0;
}
public virtual byte[] ProcessPacket(byte[] input, int inOff, int inLen)
{
byte[] array;
if (forEncryption)
{
array = new byte[inLen + macSize];
}
else
{
if (inLen < macSize)
{
throw new InvalidCipherTextException("data too short");
}
array = new byte[inLen - macSize];
}
ProcessPacket(input, inOff, inLen, array, 0);
return array;
}
public virtual int ProcessPacket(byte[] input, int inOff, int inLen, byte[] output, int outOff)
{
if (keyParam == null)
{
throw new InvalidOperationException("CCM cipher unitialized.");
}
int num = nonce.Length;
int num2 = 15 - num;
if (num2 < 4)
{
int num3 = 1 << 8 * num2;
if (inLen >= num3)
{
throw new InvalidOperationException("CCM packet too large for choice of q.");
}
}
byte[] array = new byte[BlockSize];
array[0] = (byte)((num2 - 1) & 7);
nonce.CopyTo(array, 1);
IBlockCipher blockCipher = new SicBlockCipher(cipher);
blockCipher.Init(forEncryption, new ParametersWithIV(keyParam, array));
int i = inOff;
int num4 = outOff;
int num5;
if (forEncryption)
{
num5 = inLen + macSize;
Check.OutputLength(output, outOff, num5, "Output buffer too short.");
CalculateMac(input, inOff, inLen, macBlock);
byte[] array2 = new byte[BlockSize];
blockCipher.ProcessBlock(macBlock, 0, array2, 0);
for (; i < inOff + inLen - BlockSize; i += BlockSize)
{
blockCipher.ProcessBlock(input, i, output, num4);
num4 += BlockSize;
}
byte[] array3 = new byte[BlockSize];
Array.Copy(input, i, array3, 0, inLen + inOff - i);
blockCipher.ProcessBlock(array3, 0, array3, 0);
Array.Copy(array3, 0, output, num4, inLen + inOff - i);
Array.Copy(array2, 0, output, outOff + inLen, macSize);
}
else
{
if (inLen < macSize)
{
throw new InvalidCipherTextException("data too short");
}
num5 = inLen - macSize;
Check.OutputLength(output, outOff, num5, "Output buffer too short.");
Array.Copy(input, inOff + num5, macBlock, 0, macSize);
blockCipher.ProcessBlock(macBlock, 0, macBlock, 0);
for (int j = macSize; j != macBlock.Length; j++)
{
macBlock[j] = 0;
}
for (; i < inOff + num5 - BlockSize; i += BlockSize)
{
blockCipher.ProcessBlock(input, i, output, num4);
num4 += BlockSize;
}
byte[] array4 = new byte[BlockSize];
Array.Copy(input, i, array4, 0, num5 - (i - inOff));
blockCipher.ProcessBlock(array4, 0, array4, 0);
Array.Copy(array4, 0, output, num4, num5 - (i - inOff));
byte[] b = new byte[BlockSize];
CalculateMac(output, outOff, num5, b);
if (!Arrays.ConstantTimeAreEqual(macBlock, b))
{
throw new InvalidCipherTextException("mac check in CCM failed");
}
}
return num5;
}
private int CalculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
{
IMac mac = new CbcBlockCipherMac(cipher, macSize * 8);
mac.Init(keyParam);
byte[] array = new byte[16];
byte[] array2;
if (HasAssociatedText())
{
(array2 = array)[0] = (byte)(array2[0] | 0x40);
}
(array2 = array)[0] = (byte)(array2[0] | (byte)((((mac.GetMacSize() - 2) / 2) & 7) << 3));
(array2 = array)[0] = (byte)(array2[0] | (byte)((15 - nonce.Length - 1) & 7));
Array.Copy(nonce, 0, array, 1, nonce.Length);
int num = dataLen;
int num2 = 1;
while (num > 0)
{
array[^num2] = (byte)(num & 0xFF);
num >>= 8;
num2++;
}
mac.BlockUpdate(array, 0, array.Length);
if (HasAssociatedText())
{
int associatedTextLength = GetAssociatedTextLength();
int num3;
if (associatedTextLength < 65280)
{
mac.Update((byte)(associatedTextLength >> 8));
mac.Update((byte)associatedTextLength);
num3 = 2;
}
else
{
mac.Update(byte.MaxValue);
mac.Update(254);
mac.Update((byte)(associatedTextLength >> 24));
mac.Update((byte)(associatedTextLength >> 16));
mac.Update((byte)(associatedTextLength >> 8));
mac.Update((byte)associatedTextLength);
num3 = 6;
}
if (initialAssociatedText != null)
{
mac.BlockUpdate(initialAssociatedText, 0, initialAssociatedText.Length);
}
if (associatedText.Position > 0)
{
byte[] buffer = associatedText.GetBuffer();
int len = (int)associatedText.Position;
mac.BlockUpdate(buffer, 0, len);
}
num3 = (num3 + associatedTextLength) % 16;
if (num3 != 0)
{
for (int i = num3; i < 16; i++)
{
mac.Update(0);
}
}
}
mac.BlockUpdate(data, dataOff, dataLen);
return mac.DoFinal(macBlock, 0);
}
private int GetAssociatedTextLength()
{
return (int)associatedText.Length + ((initialAssociatedText != null) ? initialAssociatedText.Length : 0);
}
private bool HasAssociatedText()
{
return GetAssociatedTextLength() > 0;
}
}

View File

@@ -0,0 +1,116 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Modes;
public class CfbBlockCipher : IBlockCipher
{
private byte[] IV;
private byte[] cfbV;
private byte[] cfbOutV;
private bool encrypting;
private readonly int blockSize;
private readonly IBlockCipher cipher;
public string AlgorithmName => cipher.AlgorithmName + "/CFB" + blockSize * 8;
public bool IsPartialBlockOkay => true;
public CfbBlockCipher(IBlockCipher cipher, int bitBlockSize)
{
this.cipher = cipher;
blockSize = bitBlockSize / 8;
IV = new byte[cipher.GetBlockSize()];
cfbV = new byte[cipher.GetBlockSize()];
cfbOutV = new byte[cipher.GetBlockSize()];
}
public IBlockCipher GetUnderlyingCipher()
{
return cipher;
}
public void Init(bool forEncryption, ICipherParameters parameters)
{
encrypting = forEncryption;
if (parameters is ParametersWithIV)
{
ParametersWithIV parametersWithIV = (ParametersWithIV)parameters;
byte[] iV = parametersWithIV.GetIV();
int num = IV.Length - iV.Length;
Array.Copy(iV, 0, IV, num, iV.Length);
Array.Clear(IV, 0, num);
parameters = parametersWithIV.Parameters;
}
Reset();
if (parameters != null)
{
cipher.Init(forEncryption: true, parameters);
}
}
public int GetBlockSize()
{
return blockSize;
}
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (!encrypting)
{
return DecryptBlock(input, inOff, output, outOff);
}
return EncryptBlock(input, inOff, output, outOff);
}
public int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
if (inOff + blockSize > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if (outOff + blockSize > outBytes.Length)
{
throw new DataLengthException("output buffer too short");
}
cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
for (int i = 0; i < blockSize; i++)
{
outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
}
Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
Array.Copy(outBytes, outOff, cfbV, cfbV.Length - blockSize, blockSize);
return blockSize;
}
public int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
if (inOff + blockSize > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if (outOff + blockSize > outBytes.Length)
{
throw new DataLengthException("output buffer too short");
}
cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
Array.Copy(input, inOff, cfbV, cfbV.Length - blockSize, blockSize);
for (int i = 0; i < blockSize; i++)
{
outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
}
return blockSize;
}
public void Reset()
{
Array.Copy(IV, 0, cfbV, 0, IV.Length);
cipher.Reset();
}
}

View File

@@ -0,0 +1,135 @@
using System;
namespace Org.BouncyCastle.Crypto.Modes;
public class CtsBlockCipher : BufferedBlockCipher
{
private readonly int blockSize;
public CtsBlockCipher(IBlockCipher cipher)
{
if (cipher is OfbBlockCipher || cipher is CfbBlockCipher)
{
throw new ArgumentException("CtsBlockCipher can only accept ECB, or CBC ciphers");
}
base.cipher = cipher;
blockSize = cipher.GetBlockSize();
buf = new byte[blockSize * 2];
bufOff = 0;
}
public override int GetUpdateOutputSize(int length)
{
int num = length + bufOff;
int num2 = num % buf.Length;
if (num2 == 0)
{
return num - buf.Length;
}
return num - num2;
}
public override int GetOutputSize(int length)
{
return length + bufOff;
}
public override int ProcessByte(byte input, byte[] output, int outOff)
{
int result = 0;
if (bufOff == buf.Length)
{
result = cipher.ProcessBlock(buf, 0, output, outOff);
Array.Copy(buf, blockSize, buf, 0, blockSize);
bufOff = blockSize;
}
buf[bufOff++] = input;
return result;
}
public override int ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff)
{
if (length < 0)
{
throw new ArgumentException("Can't have a negative input outLength!");
}
int num = GetBlockSize();
int updateOutputSize = GetUpdateOutputSize(length);
if (updateOutputSize > 0 && outOff + updateOutputSize > output.Length)
{
throw new DataLengthException("output buffer too short");
}
int num2 = 0;
int num3 = buf.Length - bufOff;
if (length > num3)
{
Array.Copy(input, inOff, buf, bufOff, num3);
num2 += cipher.ProcessBlock(buf, 0, output, outOff);
Array.Copy(buf, num, buf, 0, num);
bufOff = num;
length -= num3;
inOff += num3;
while (length > num)
{
Array.Copy(input, inOff, buf, bufOff, num);
num2 += cipher.ProcessBlock(buf, 0, output, outOff + num2);
Array.Copy(buf, num, buf, 0, num);
length -= num;
inOff += num;
}
}
Array.Copy(input, inOff, buf, bufOff, length);
bufOff += length;
return num2;
}
public override int DoFinal(byte[] output, int outOff)
{
if (bufOff + outOff > output.Length)
{
throw new DataLengthException("output buffer too small in doFinal");
}
int num = cipher.GetBlockSize();
int length = bufOff - num;
byte[] array = new byte[num];
if (forEncryption)
{
cipher.ProcessBlock(buf, 0, array, 0);
if (bufOff < num)
{
throw new DataLengthException("need at least one block of input for CTS");
}
for (int i = bufOff; i != buf.Length; i++)
{
buf[i] = array[i - num];
}
for (int j = num; j != bufOff; j++)
{
byte[] array3;
byte[] array2 = (array3 = buf);
int num2 = j;
nint num3 = num2;
array2[num2] = (byte)(array3[num3] ^ array[j - num]);
}
IBlockCipher blockCipher = ((cipher is CbcBlockCipher) ? ((CbcBlockCipher)cipher).GetUnderlyingCipher() : cipher);
blockCipher.ProcessBlock(buf, num, output, outOff);
Array.Copy(array, 0, output, outOff + num, length);
}
else
{
byte[] array4 = new byte[num];
IBlockCipher blockCipher2 = ((cipher is CbcBlockCipher) ? ((CbcBlockCipher)cipher).GetUnderlyingCipher() : cipher);
blockCipher2.ProcessBlock(buf, 0, array, 0);
for (int k = num; k != bufOff; k++)
{
array4[k - num] = (byte)(array[k - num] ^ buf[k]);
}
Array.Copy(buf, num, array, 0, length);
cipher.ProcessBlock(array, 0, output, outOff);
Array.Copy(array4, 0, output, outOff + num, length);
}
int result = bufOff;
Reset();
return result;
}
}

View File

@@ -0,0 +1,289 @@
using System;
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Modes;
public class EaxBlockCipher : IAeadBlockCipher
{
private enum Tag : byte
{
N,
H,
C
}
private SicBlockCipher cipher;
private bool forEncryption;
private int blockSize;
private IMac mac;
private byte[] nonceMac;
private byte[] associatedTextMac;
private byte[] macBlock;
private int macSize;
private byte[] bufBlock;
private int bufOff;
private bool cipherInitialized;
private byte[] initialAssociatedText;
public virtual string AlgorithmName => cipher.GetUnderlyingCipher().AlgorithmName + "/EAX";
public EaxBlockCipher(IBlockCipher cipher)
{
blockSize = cipher.GetBlockSize();
mac = new CMac(cipher);
macBlock = new byte[blockSize];
associatedTextMac = new byte[mac.GetMacSize()];
nonceMac = new byte[mac.GetMacSize()];
this.cipher = new SicBlockCipher(cipher);
}
public virtual IBlockCipher GetUnderlyingCipher()
{
return cipher;
}
public virtual int GetBlockSize()
{
return cipher.GetBlockSize();
}
public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
this.forEncryption = forEncryption;
byte[] array;
ICipherParameters parameters2;
if (parameters is AeadParameters)
{
AeadParameters aeadParameters = (AeadParameters)parameters;
array = aeadParameters.GetNonce();
initialAssociatedText = aeadParameters.GetAssociatedText();
macSize = aeadParameters.MacSize / 8;
parameters2 = aeadParameters.Key;
}
else
{
if (!(parameters is ParametersWithIV))
{
throw new ArgumentException("invalid parameters passed to EAX");
}
ParametersWithIV parametersWithIV = (ParametersWithIV)parameters;
array = parametersWithIV.GetIV();
initialAssociatedText = null;
macSize = mac.GetMacSize() / 2;
parameters2 = parametersWithIV.Parameters;
}
bufBlock = new byte[forEncryption ? blockSize : (blockSize + macSize)];
byte[] array2 = new byte[blockSize];
mac.Init(parameters2);
array2[blockSize - 1] = 0;
mac.BlockUpdate(array2, 0, blockSize);
mac.BlockUpdate(array, 0, array.Length);
mac.DoFinal(nonceMac, 0);
cipher.Init(forEncryption: true, new ParametersWithIV(null, nonceMac));
Reset();
}
private void InitCipher()
{
if (!cipherInitialized)
{
cipherInitialized = true;
mac.DoFinal(associatedTextMac, 0);
byte[] array = new byte[blockSize];
array[blockSize - 1] = 2;
mac.BlockUpdate(array, 0, blockSize);
}
}
private void CalculateMac()
{
byte[] array = new byte[blockSize];
mac.DoFinal(array, 0);
for (int i = 0; i < macBlock.Length; i++)
{
macBlock[i] = (byte)(nonceMac[i] ^ associatedTextMac[i] ^ array[i]);
}
}
public virtual void Reset()
{
Reset(clearMac: true);
}
private void Reset(bool clearMac)
{
cipher.Reset();
mac.Reset();
bufOff = 0;
Array.Clear(bufBlock, 0, bufBlock.Length);
if (clearMac)
{
Array.Clear(macBlock, 0, macBlock.Length);
}
byte[] array = new byte[blockSize];
array[blockSize - 1] = 1;
mac.BlockUpdate(array, 0, blockSize);
cipherInitialized = false;
if (initialAssociatedText != null)
{
ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
}
}
public virtual void ProcessAadByte(byte input)
{
if (cipherInitialized)
{
throw new InvalidOperationException("AAD data cannot be added after encryption/decryption processing has begun.");
}
mac.Update(input);
}
public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
{
if (cipherInitialized)
{
throw new InvalidOperationException("AAD data cannot be added after encryption/decryption processing has begun.");
}
mac.BlockUpdate(inBytes, inOff, len);
}
public virtual int ProcessByte(byte input, byte[] outBytes, int outOff)
{
InitCipher();
return Process(input, outBytes, outOff);
}
public virtual int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff)
{
InitCipher();
int num = 0;
for (int i = 0; i != len; i++)
{
num += Process(inBytes[inOff + i], outBytes, outOff + num);
}
return num;
}
public virtual int DoFinal(byte[] outBytes, int outOff)
{
InitCipher();
int num = bufOff;
byte[] array = new byte[bufBlock.Length];
bufOff = 0;
if (forEncryption)
{
Check.OutputLength(outBytes, outOff, num + macSize, "Output buffer too short");
cipher.ProcessBlock(bufBlock, 0, array, 0);
Array.Copy(array, 0, outBytes, outOff, num);
mac.BlockUpdate(array, 0, num);
CalculateMac();
Array.Copy(macBlock, 0, outBytes, outOff + num, macSize);
Reset(clearMac: false);
return num + macSize;
}
if (num < macSize)
{
throw new InvalidCipherTextException("data too short");
}
Check.OutputLength(outBytes, outOff, num - macSize, "Output buffer too short");
if (num > macSize)
{
mac.BlockUpdate(bufBlock, 0, num - macSize);
cipher.ProcessBlock(bufBlock, 0, array, 0);
Array.Copy(array, 0, outBytes, outOff, num - macSize);
}
CalculateMac();
if (!VerifyMac(bufBlock, num - macSize))
{
throw new InvalidCipherTextException("mac check in EAX failed");
}
Reset(clearMac: false);
return num - macSize;
}
public virtual byte[] GetMac()
{
byte[] array = new byte[macSize];
Array.Copy(macBlock, 0, array, 0, macSize);
return array;
}
public virtual int GetUpdateOutputSize(int len)
{
int num = len + bufOff;
if (!forEncryption)
{
if (num < macSize)
{
return 0;
}
num -= macSize;
}
return num - num % blockSize;
}
public virtual int GetOutputSize(int len)
{
int num = len + bufOff;
if (forEncryption)
{
return num + macSize;
}
if (num >= macSize)
{
return num - macSize;
}
return 0;
}
private int Process(byte b, byte[] outBytes, int outOff)
{
bufBlock[bufOff++] = b;
if (bufOff == bufBlock.Length)
{
Check.OutputLength(outBytes, outOff, blockSize, "Output buffer is too short");
int result;
if (forEncryption)
{
result = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
mac.BlockUpdate(outBytes, outOff, blockSize);
}
else
{
mac.BlockUpdate(bufBlock, 0, blockSize);
result = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
}
bufOff = 0;
if (!forEncryption)
{
Array.Copy(bufBlock, blockSize, bufBlock, 0, macSize);
bufOff = macSize;
}
return result;
}
return 0;
}
private bool VerifyMac(byte[] mac, int off)
{
int num = 0;
for (int i = 0; i < macSize; i++)
{
num |= macBlock[i] ^ mac[off + i];
}
return num == 0;
}
}

View File

@@ -0,0 +1,138 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Modes;
public class GOfbBlockCipher : IBlockCipher
{
private const int C1 = 16843012;
private const int C2 = 16843009;
private byte[] IV;
private byte[] ofbV;
private byte[] ofbOutV;
private readonly int blockSize;
private readonly IBlockCipher cipher;
private bool firstStep = true;
private int N3;
private int N4;
public string AlgorithmName => cipher.AlgorithmName + "/GCTR";
public bool IsPartialBlockOkay => true;
public GOfbBlockCipher(IBlockCipher cipher)
{
this.cipher = cipher;
blockSize = cipher.GetBlockSize();
if (blockSize != 8)
{
throw new ArgumentException("GCTR only for 64 bit block ciphers");
}
IV = new byte[cipher.GetBlockSize()];
ofbV = new byte[cipher.GetBlockSize()];
ofbOutV = new byte[cipher.GetBlockSize()];
}
public IBlockCipher GetUnderlyingCipher()
{
return cipher;
}
public void Init(bool forEncryption, ICipherParameters parameters)
{
firstStep = true;
N3 = 0;
N4 = 0;
if (parameters is ParametersWithIV)
{
ParametersWithIV parametersWithIV = (ParametersWithIV)parameters;
byte[] iV = parametersWithIV.GetIV();
if (iV.Length < IV.Length)
{
Array.Copy(iV, 0, IV, IV.Length - iV.Length, iV.Length);
for (int i = 0; i < IV.Length - iV.Length; i++)
{
IV[i] = 0;
}
}
else
{
Array.Copy(iV, 0, IV, 0, IV.Length);
}
parameters = parametersWithIV.Parameters;
}
Reset();
if (parameters != null)
{
cipher.Init(forEncryption: true, parameters);
}
}
public int GetBlockSize()
{
return blockSize;
}
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (inOff + blockSize > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if (outOff + blockSize > output.Length)
{
throw new DataLengthException("output buffer too short");
}
if (firstStep)
{
firstStep = false;
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
N3 = bytesToint(ofbOutV, 0);
N4 = bytesToint(ofbOutV, 4);
}
N3 += 16843009;
N4 += 16843012;
if (N4 < 16843012 && N4 > 0)
{
N4++;
}
intTobytes(N3, ofbV, 0);
intTobytes(N4, ofbV, 4);
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
for (int i = 0; i < blockSize; i++)
{
output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]);
}
Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
return blockSize;
}
public void Reset()
{
Array.Copy(IV, 0, ofbV, 0, IV.Length);
cipher.Reset();
}
private int bytesToint(byte[] inBytes, int inOff)
{
return (int)((inBytes[inOff + 3] << 24) & 0xFF000000u) + ((inBytes[inOff + 2] << 16) & 0xFF0000) + ((inBytes[inOff + 1] << 8) & 0xFF00) + (inBytes[inOff] & 0xFF);
}
private void intTobytes(int num, byte[] outBytes, int outOff)
{
outBytes[outOff + 3] = (byte)(num >> 24);
outBytes[outOff + 2] = (byte)(num >> 16);
outBytes[outOff + 1] = (byte)(num >> 8);
outBytes[outOff] = (byte)num;
}
}

View File

@@ -0,0 +1,33 @@
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes.Gcm;
public class BasicGcmExponentiator : IGcmExponentiator
{
private uint[] x;
public void Init(byte[] x)
{
this.x = GcmUtilities.AsUints(x);
}
public void ExponentiateX(long pow, byte[] output)
{
uint[] array = GcmUtilities.OneAsUints();
if (pow > 0)
{
uint[] y = Arrays.Clone(x);
do
{
if ((pow & 1) != 0)
{
GcmUtilities.Multiply(array, y);
}
GcmUtilities.Multiply(y, y);
pow >>= 1;
}
while (pow > 0);
}
GcmUtilities.AsBytes(array, output);
}
}

View File

@@ -0,0 +1,18 @@
namespace Org.BouncyCastle.Crypto.Modes.Gcm;
public class BasicGcmMultiplier : IGcmMultiplier
{
private uint[] H;
public void Init(byte[] H)
{
this.H = GcmUtilities.AsUints(H);
}
public void MultiplyH(byte[] x)
{
uint[] x2 = GcmUtilities.AsUints(x);
GcmUtilities.Multiply(x2, H);
GcmUtilities.AsBytes(x2, x);
}
}

View File

@@ -0,0 +1,403 @@
using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Modes.Gcm;
internal abstract class GcmUtilities
{
private const uint E1 = 3774873600u;
private const ulong E1L = 16212958658533785600uL;
private static readonly uint[] LOOKUP = GenerateLookup();
private static uint[] GenerateLookup()
{
uint[] array = new uint[256];
for (int i = 0; i < 256; i++)
{
uint num = 0u;
for (int num2 = 7; num2 >= 0; num2--)
{
if ((i & (1 << num2)) != 0)
{
num ^= (uint)(-520093696 >>> 7 - num2);
}
}
array[i] = num;
}
return array;
}
internal static byte[] OneAsBytes()
{
return new byte[16]
{
128, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0
};
}
internal static uint[] OneAsUints()
{
return new uint[4] { 2147483648u, 0u, 0u, 0u };
}
internal static ulong[] OneAsUlongs()
{
return new ulong[2] { 9223372036854775808uL, 0uL };
}
internal static byte[] AsBytes(uint[] x)
{
return Pack.UInt32_To_BE(x);
}
internal static void AsBytes(uint[] x, byte[] z)
{
Pack.UInt32_To_BE(x, z, 0);
}
internal static byte[] AsBytes(ulong[] x)
{
byte[] array = new byte[16];
Pack.UInt64_To_BE(x, array, 0);
return array;
}
internal static void AsBytes(ulong[] x, byte[] z)
{
Pack.UInt64_To_BE(x, z, 0);
}
internal static uint[] AsUints(byte[] bs)
{
uint[] array = new uint[4];
Pack.BE_To_UInt32(bs, 0, array);
return array;
}
internal static void AsUints(byte[] bs, uint[] output)
{
Pack.BE_To_UInt32(bs, 0, output);
}
internal static ulong[] AsUlongs(byte[] x)
{
ulong[] array = new ulong[2];
Pack.BE_To_UInt64(x, 0, array);
return array;
}
public static void AsUlongs(byte[] x, ulong[] z)
{
Pack.BE_To_UInt64(x, 0, z);
}
internal static void Multiply(byte[] x, byte[] y)
{
uint[] x2 = AsUints(x);
uint[] y2 = AsUints(y);
Multiply(x2, y2);
AsBytes(x2, x);
}
internal static void Multiply(uint[] x, uint[] y)
{
uint num = x[0];
uint num2 = x[1];
uint num3 = x[2];
uint num4 = x[3];
uint num5 = 0u;
uint num6 = 0u;
uint num7 = 0u;
uint num8 = 0u;
for (int i = 0; i < 4; i++)
{
int num9 = (int)y[i];
for (int j = 0; j < 32; j++)
{
uint num10 = (uint)(num9 >> 31);
num9 <<= 1;
num5 ^= num & num10;
num6 ^= num2 & num10;
num7 ^= num3 & num10;
num8 ^= num4 & num10;
uint num11 = (uint)((int)(num4 << 31) >> 8);
num4 = (num4 >> 1) | (num3 << 31);
num3 = (num3 >> 1) | (num2 << 31);
num2 = (num2 >> 1) | (num << 31);
num = (num >> 1) ^ (num11 & 0xE1000000u);
}
}
x[0] = num5;
x[1] = num6;
x[2] = num7;
x[3] = num8;
}
internal static void Multiply(ulong[] x, ulong[] y)
{
ulong num = x[0];
ulong num2 = x[1];
ulong num3 = 0uL;
ulong num4 = 0uL;
for (int i = 0; i < 2; i++)
{
long num5 = (long)y[i];
for (int j = 0; j < 64; j++)
{
ulong num6 = (ulong)(num5 >> 63);
num5 <<= 1;
num3 ^= num & num6;
num4 ^= num2 & num6;
ulong num7 = (ulong)((long)(num2 << 63) >> 8);
num2 = (num2 >> 1) | (num << 63);
num = (num >> 1) ^ (num7 & 0xE100000000000000uL);
}
}
x[0] = num3;
x[1] = num4;
}
internal static void MultiplyP(uint[] x)
{
uint num = (uint)((int)ShiftRight(x) >> 8);
uint[] array;
(array = x)[0] = array[0] ^ (num & 0xE1000000u);
}
internal static void MultiplyP(uint[] x, uint[] z)
{
uint num = (uint)((int)ShiftRight(x, z) >> 8);
uint[] array;
(array = z)[0] = array[0] ^ (num & 0xE1000000u);
}
internal static void MultiplyP8(uint[] x)
{
uint num = ShiftRightN(x, 8);
uint[] array;
(array = x)[0] = array[0] ^ LOOKUP[num >> 24];
}
internal static void MultiplyP8(uint[] x, uint[] y)
{
uint num = ShiftRightN(x, 8, y);
uint[] array;
(array = y)[0] = array[0] ^ LOOKUP[num >> 24];
}
internal static uint ShiftRight(uint[] x)
{
uint num = x[0];
x[0] = num >> 1;
uint num2 = num << 31;
num = x[1];
x[1] = (num >> 1) | num2;
num2 = num << 31;
num = x[2];
x[2] = (num >> 1) | num2;
num2 = num << 31;
num = x[3];
x[3] = (num >> 1) | num2;
return num << 31;
}
internal static uint ShiftRight(uint[] x, uint[] z)
{
uint num = x[0];
z[0] = num >> 1;
uint num2 = num << 31;
num = x[1];
z[1] = (num >> 1) | num2;
num2 = num << 31;
num = x[2];
z[2] = (num >> 1) | num2;
num2 = num << 31;
num = x[3];
z[3] = (num >> 1) | num2;
return num << 31;
}
internal static uint ShiftRightN(uint[] x, int n)
{
uint num = x[0];
int num2 = 32 - n;
x[0] = num >> n;
uint num3 = num << num2;
num = x[1];
x[1] = (num >> n) | num3;
num3 = num << num2;
num = x[2];
x[2] = (num >> n) | num3;
num3 = num << num2;
num = x[3];
x[3] = (num >> n) | num3;
return num << num2;
}
internal static uint ShiftRightN(uint[] x, int n, uint[] z)
{
uint num = x[0];
int num2 = 32 - n;
z[0] = num >> n;
uint num3 = num << num2;
num = x[1];
z[1] = (num >> n) | num3;
num3 = num << num2;
num = x[2];
z[2] = (num >> n) | num3;
num3 = num << num2;
num = x[3];
z[3] = (num >> n) | num3;
return num << num2;
}
internal static void Xor(byte[] x, byte[] y)
{
int num = 0;
do
{
byte[] array2;
byte[] array = (array2 = x);
int num2 = num;
nint num3 = num2;
array[num2] = (byte)(array2[num3] ^ y[num]);
num++;
byte[] array3 = (array2 = x);
int num4 = num;
num3 = num4;
array3[num4] = (byte)(array2[num3] ^ y[num]);
num++;
byte[] array4 = (array2 = x);
int num5 = num;
num3 = num5;
array4[num5] = (byte)(array2[num3] ^ y[num]);
num++;
byte[] array5 = (array2 = x);
int num6 = num;
num3 = num6;
array5[num6] = (byte)(array2[num3] ^ y[num]);
num++;
}
while (num < 16);
}
internal static void Xor(byte[] x, byte[] y, int yOff)
{
int num = 0;
do
{
byte[] array2;
byte[] array = (array2 = x);
int num2 = num;
nint num3 = num2;
array[num2] = (byte)(array2[num3] ^ y[yOff + num]);
num++;
byte[] array3 = (array2 = x);
int num4 = num;
num3 = num4;
array3[num4] = (byte)(array2[num3] ^ y[yOff + num]);
num++;
byte[] array4 = (array2 = x);
int num5 = num;
num3 = num5;
array4[num5] = (byte)(array2[num3] ^ y[yOff + num]);
num++;
byte[] array5 = (array2 = x);
int num6 = num;
num3 = num6;
array5[num6] = (byte)(array2[num3] ^ y[yOff + num]);
num++;
}
while (num < 16);
}
internal static void Xor(byte[] x, int xOff, byte[] y, int yOff, byte[] z, int zOff)
{
int num = 0;
do
{
z[zOff + num] = (byte)(x[xOff + num] ^ y[yOff + num]);
num++;
z[zOff + num] = (byte)(x[xOff + num] ^ y[yOff + num]);
num++;
z[zOff + num] = (byte)(x[xOff + num] ^ y[yOff + num]);
num++;
z[zOff + num] = (byte)(x[xOff + num] ^ y[yOff + num]);
num++;
}
while (num < 16);
}
internal static void Xor(byte[] x, byte[] y, int yOff, int yLen)
{
while (--yLen >= 0)
{
byte[] array2;
byte[] array = (array2 = x);
int num = yLen;
nint num2 = num;
array[num] = (byte)(array2[num2] ^ y[yOff + yLen]);
}
}
internal static void Xor(byte[] x, int xOff, byte[] y, int yOff, int len)
{
while (--len >= 0)
{
byte[] array2;
byte[] array = (array2 = x);
int num = xOff + len;
nint num2 = num;
array[num] = (byte)(array2[num2] ^ y[yOff + len]);
}
}
internal static void Xor(byte[] x, byte[] y, byte[] z)
{
int num = 0;
do
{
z[num] = (byte)(x[num] ^ y[num]);
num++;
z[num] = (byte)(x[num] ^ y[num]);
num++;
z[num] = (byte)(x[num] ^ y[num]);
num++;
z[num] = (byte)(x[num] ^ y[num]);
num++;
}
while (num < 16);
}
internal static void Xor(uint[] x, uint[] y)
{
uint[] array;
(array = x)[0] = array[0] ^ y[0];
(array = x)[1] = array[1] ^ y[1];
(array = x)[2] = array[2] ^ y[2];
(array = x)[3] = array[3] ^ y[3];
}
internal static void Xor(uint[] x, uint[] y, uint[] z)
{
z[0] = x[0] ^ y[0];
z[1] = x[1] ^ y[1];
z[2] = x[2] ^ y[2];
z[3] = x[3] ^ y[3];
}
internal static void Xor(ulong[] x, ulong[] y)
{
ulong[] array;
(array = x)[0] = array[0] ^ y[0];
(array = x)[1] = array[1] ^ y[1];
}
internal static void Xor(ulong[] x, ulong[] y, ulong[] z)
{
z[0] = x[0] ^ y[0];
z[1] = x[1] ^ y[1];
}
}

View File

@@ -0,0 +1,8 @@
namespace Org.BouncyCastle.Crypto.Modes.Gcm;
public interface IGcmExponentiator
{
void Init(byte[] x);
void ExponentiateX(long pow, byte[] output);
}

View File

@@ -0,0 +1,8 @@
namespace Org.BouncyCastle.Crypto.Modes.Gcm;
public interface IGcmMultiplier
{
void Init(byte[] H);
void MultiplyH(byte[] x);
}

View File

@@ -0,0 +1,52 @@
using System.Collections;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes.Gcm;
public class Tables1kGcmExponentiator : IGcmExponentiator
{
private IList lookupPowX2;
public void Init(byte[] x)
{
uint[] array = GcmUtilities.AsUints(x);
if (lookupPowX2 == null || !Arrays.AreEqual(array, (uint[])lookupPowX2[0]))
{
lookupPowX2 = Platform.CreateArrayList(8);
lookupPowX2.Add(array);
}
}
public void ExponentiateX(long pow, byte[] output)
{
uint[] x = GcmUtilities.OneAsUints();
int num = 0;
while (pow > 0)
{
if ((pow & 1) != 0)
{
EnsureAvailable(num);
GcmUtilities.Multiply(x, (uint[])lookupPowX2[num]);
}
num++;
pow >>= 1;
}
GcmUtilities.AsBytes(x, output);
}
private void EnsureAvailable(int bit)
{
int num = lookupPowX2.Count;
if (num <= bit)
{
uint[] array = (uint[])lookupPowX2[num - 1];
do
{
array = Arrays.Clone(array);
GcmUtilities.Multiply(array, array);
lookupPowX2.Add(array);
}
while (++num <= bit);
}
}
}

View File

@@ -0,0 +1,73 @@
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes.Gcm;
public class Tables64kGcmMultiplier : IGcmMultiplier
{
private byte[] H;
private uint[][][] M;
public void Init(byte[] H)
{
if (M == null)
{
M = new uint[16][][];
}
else if (Arrays.AreEqual(this.H, H))
{
return;
}
this.H = Arrays.Clone(H);
M[0] = new uint[256][];
M[0][0] = new uint[4];
M[0][128] = GcmUtilities.AsUints(H);
for (int num = 64; num >= 1; num >>= 1)
{
uint[] array = (uint[])M[0][num + num].Clone();
GcmUtilities.MultiplyP(array);
M[0][num] = array;
}
int num2 = 0;
while (true)
{
for (int i = 2; i < 256; i += i)
{
for (int j = 1; j < i; j++)
{
uint[] array2 = (uint[])M[num2][i].Clone();
GcmUtilities.Xor(array2, M[num2][j]);
M[num2][i + j] = array2;
}
}
if (++num2 == 16)
{
break;
}
M[num2] = new uint[256][];
M[num2][0] = new uint[4];
for (int num3 = 128; num3 > 0; num3 >>= 1)
{
uint[] array3 = (uint[])M[num2 - 1][num3].Clone();
GcmUtilities.MultiplyP8(array3);
M[num2][num3] = array3;
}
}
}
public void MultiplyH(byte[] x)
{
uint[] array = new uint[4];
for (int i = 0; i != 16; i++)
{
uint[] array2 = M[i][x[i]];
uint[] array3;
(array3 = array)[0] = array3[0] ^ array2[0];
(array3 = array)[1] = array3[1] ^ array2[1];
(array3 = array)[2] = array3[2] ^ array2[2];
(array3 = array)[3] = array3[3] ^ array2[3];
}
Pack.UInt32_To_BE(array, x, 0);
}
}

View File

@@ -0,0 +1,92 @@
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes.Gcm;
public class Tables8kGcmMultiplier : IGcmMultiplier
{
private byte[] H;
private uint[][][] M;
public void Init(byte[] H)
{
if (M == null)
{
M = new uint[32][][];
}
else if (Arrays.AreEqual(this.H, H))
{
return;
}
this.H = Arrays.Clone(H);
M[0] = new uint[16][];
M[1] = new uint[16][];
M[0][0] = new uint[4];
M[1][0] = new uint[4];
M[1][8] = GcmUtilities.AsUints(H);
for (int num = 4; num >= 1; num >>= 1)
{
uint[] array = (uint[])M[1][num + num].Clone();
GcmUtilities.MultiplyP(array);
M[1][num] = array;
}
uint[] array2 = (uint[])M[1][1].Clone();
GcmUtilities.MultiplyP(array2);
M[0][8] = array2;
for (int num2 = 4; num2 >= 1; num2 >>= 1)
{
uint[] array3 = (uint[])M[0][num2 + num2].Clone();
GcmUtilities.MultiplyP(array3);
M[0][num2] = array3;
}
int num3 = 0;
while (true)
{
for (int i = 2; i < 16; i += i)
{
for (int j = 1; j < i; j++)
{
uint[] array4 = (uint[])M[num3][i].Clone();
GcmUtilities.Xor(array4, M[num3][j]);
M[num3][i + j] = array4;
}
}
if (++num3 == 32)
{
break;
}
if (num3 > 1)
{
M[num3] = new uint[16][];
M[num3][0] = new uint[4];
for (int num4 = 8; num4 > 0; num4 >>= 1)
{
uint[] array5 = (uint[])M[num3 - 2][num4].Clone();
GcmUtilities.MultiplyP8(array5);
M[num3][num4] = array5;
}
}
}
}
public void MultiplyH(byte[] x)
{
uint[] array = new uint[4];
for (int num = 15; num >= 0; num--)
{
uint[] array2 = M[num + num][x[num] & 0xF];
uint[] array3;
(array3 = array)[0] = array3[0] ^ array2[0];
(array3 = array)[1] = array3[1] ^ array2[1];
(array3 = array)[2] = array3[2] ^ array2[2];
(array3 = array)[3] = array3[3] ^ array2[3];
array2 = M[num + num + 1][(x[num] & 0xF0) >> 4];
(array3 = array)[0] = array3[0] ^ array2[0];
(array3 = array)[1] = array3[1] ^ array2[1];
(array3 = array)[2] = array3[2] ^ array2[2];
(array3 = array)[3] = array3[3] ^ array2[3];
}
Pack.UInt32_To_BE(array, x, 0);
}
}

View File

@@ -0,0 +1,556 @@
using System;
using Org.BouncyCastle.Crypto.Modes.Gcm;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes;
public class GcmBlockCipher : IAeadBlockCipher
{
private const int BlockSize = 16;
private readonly IBlockCipher cipher;
private readonly IGcmMultiplier multiplier;
private IGcmExponentiator exp;
private bool forEncryption;
private bool initialised;
private int macSize;
private byte[] lastKey;
private byte[] nonce;
private byte[] initialAssociatedText;
private byte[] H;
private byte[] J0;
private byte[] bufBlock;
private byte[] macBlock;
private byte[] S;
private byte[] S_at;
private byte[] S_atPre;
private byte[] counter;
private uint blocksRemaining;
private int bufOff;
private ulong totalLength;
private byte[] atBlock;
private int atBlockPos;
private ulong atLength;
private ulong atLengthPre;
public virtual string AlgorithmName => cipher.AlgorithmName + "/GCM";
public GcmBlockCipher(IBlockCipher c)
: this(c, null)
{
}
public GcmBlockCipher(IBlockCipher c, IGcmMultiplier m)
{
if (c.GetBlockSize() != 16)
{
throw new ArgumentException("cipher required with a block size of " + 16 + ".");
}
if (m == null)
{
m = new Tables8kGcmMultiplier();
}
cipher = c;
multiplier = m;
}
public IBlockCipher GetUnderlyingCipher()
{
return cipher;
}
public virtual int GetBlockSize()
{
return 16;
}
public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
this.forEncryption = forEncryption;
macBlock = null;
initialised = true;
byte[] array = null;
KeyParameter keyParameter;
if (parameters is AeadParameters)
{
AeadParameters aeadParameters = (AeadParameters)parameters;
array = aeadParameters.GetNonce();
initialAssociatedText = aeadParameters.GetAssociatedText();
int num = aeadParameters.MacSize;
if (num < 32 || num > 128 || num % 8 != 0)
{
throw new ArgumentException("Invalid value for MAC size: " + num);
}
macSize = num / 8;
keyParameter = aeadParameters.Key;
}
else
{
if (!(parameters is ParametersWithIV))
{
throw new ArgumentException("invalid parameters passed to GCM");
}
ParametersWithIV parametersWithIV = (ParametersWithIV)parameters;
array = parametersWithIV.GetIV();
initialAssociatedText = null;
macSize = 16;
keyParameter = (KeyParameter)parametersWithIV.Parameters;
}
int num2 = (forEncryption ? 16 : (16 + macSize));
bufBlock = new byte[num2];
if (array == null || array.Length < 1)
{
throw new ArgumentException("IV must be at least 1 byte");
}
if (forEncryption && nonce != null && Arrays.AreEqual(nonce, array))
{
if (keyParameter == null)
{
throw new ArgumentException("cannot reuse nonce for GCM encryption");
}
if (lastKey != null && Arrays.AreEqual(lastKey, keyParameter.GetKey()))
{
throw new ArgumentException("cannot reuse nonce for GCM encryption");
}
}
nonce = array;
if (keyParameter != null)
{
lastKey = keyParameter.GetKey();
}
if (keyParameter != null)
{
cipher.Init(forEncryption: true, keyParameter);
H = new byte[16];
cipher.ProcessBlock(H, 0, H, 0);
multiplier.Init(H);
exp = null;
}
else if (H == null)
{
throw new ArgumentException("Key must be specified in initial init");
}
J0 = new byte[16];
if (nonce.Length == 12)
{
Array.Copy(nonce, 0, J0, 0, nonce.Length);
J0[15] = 1;
}
else
{
gHASH(J0, nonce, nonce.Length);
byte[] array2 = new byte[16];
Pack.UInt64_To_BE((ulong)nonce.Length * 8uL, array2, 8);
gHASHBlock(J0, array2);
}
S = new byte[16];
S_at = new byte[16];
S_atPre = new byte[16];
atBlock = new byte[16];
atBlockPos = 0;
atLength = 0uL;
atLengthPre = 0uL;
counter = Arrays.Clone(J0);
blocksRemaining = 4294967294u;
bufOff = 0;
totalLength = 0uL;
if (initialAssociatedText != null)
{
ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
}
}
public virtual byte[] GetMac()
{
if (macBlock != null)
{
return Arrays.Clone(macBlock);
}
return new byte[macSize];
}
public virtual int GetOutputSize(int len)
{
int num = len + bufOff;
if (forEncryption)
{
return num + macSize;
}
if (num >= macSize)
{
return num - macSize;
}
return 0;
}
public virtual int GetUpdateOutputSize(int len)
{
int num = len + bufOff;
if (!forEncryption)
{
if (num < macSize)
{
return 0;
}
num -= macSize;
}
return num - num % 16;
}
public virtual void ProcessAadByte(byte input)
{
CheckStatus();
atBlock[atBlockPos] = input;
if (++atBlockPos == 16)
{
gHASHBlock(S_at, atBlock);
atBlockPos = 0;
atLength += 16uL;
}
}
public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
{
CheckStatus();
for (int i = 0; i < len; i++)
{
atBlock[atBlockPos] = inBytes[inOff + i];
if (++atBlockPos == 16)
{
gHASHBlock(S_at, atBlock);
atBlockPos = 0;
atLength += 16uL;
}
}
}
private void InitCipher()
{
if (atLength != 0)
{
Array.Copy(S_at, 0, S_atPre, 0, 16);
atLengthPre = atLength;
}
if (atBlockPos > 0)
{
gHASHPartial(S_atPre, atBlock, 0, atBlockPos);
atLengthPre += (uint)atBlockPos;
}
if (atLengthPre != 0)
{
Array.Copy(S_atPre, 0, S, 0, 16);
}
}
public virtual int ProcessByte(byte input, byte[] output, int outOff)
{
CheckStatus();
bufBlock[bufOff] = input;
if (++bufOff == bufBlock.Length)
{
ProcessBlock(bufBlock, 0, output, outOff);
if (forEncryption)
{
bufOff = 0;
}
else
{
Array.Copy(bufBlock, 16, bufBlock, 0, macSize);
bufOff = macSize;
}
return 16;
}
return 0;
}
public virtual int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
CheckStatus();
Check.DataLength(input, inOff, len, "input buffer too short");
int num = 0;
if (forEncryption)
{
if (bufOff != 0)
{
while (len > 0)
{
len--;
bufBlock[bufOff] = input[inOff++];
if (++bufOff == 16)
{
ProcessBlock(bufBlock, 0, output, outOff);
bufOff = 0;
num += 16;
break;
}
}
}
while (len >= 16)
{
ProcessBlock(input, inOff, output, outOff + num);
inOff += 16;
len -= 16;
num += 16;
}
if (len > 0)
{
Array.Copy(input, inOff, bufBlock, 0, len);
bufOff = len;
}
}
else
{
for (int i = 0; i < len; i++)
{
bufBlock[bufOff] = input[inOff + i];
if (++bufOff == bufBlock.Length)
{
ProcessBlock(bufBlock, 0, output, outOff + num);
Array.Copy(bufBlock, 16, bufBlock, 0, macSize);
bufOff = macSize;
num += 16;
}
}
}
return num;
}
public int DoFinal(byte[] output, int outOff)
{
CheckStatus();
if (totalLength == 0)
{
InitCipher();
}
int num = bufOff;
if (forEncryption)
{
Check.OutputLength(output, outOff, num + macSize, "Output buffer too short");
}
else
{
if (num < macSize)
{
throw new InvalidCipherTextException("data too short");
}
num -= macSize;
Check.OutputLength(output, outOff, num, "Output buffer too short");
}
if (num > 0)
{
ProcessPartial(bufBlock, 0, num, output, outOff);
}
atLength += (uint)atBlockPos;
if (atLength > atLengthPre)
{
if (atBlockPos > 0)
{
gHASHPartial(S_at, atBlock, 0, atBlockPos);
}
if (atLengthPre != 0)
{
GcmUtilities.Xor(S_at, S_atPre);
}
long pow = (long)(totalLength * 8 + 127 >> 7);
byte[] array = new byte[16];
if (exp == null)
{
exp = new Tables1kGcmExponentiator();
exp.Init(H);
}
exp.ExponentiateX(pow, array);
GcmUtilities.Multiply(S_at, array);
GcmUtilities.Xor(S, S_at);
}
byte[] array2 = new byte[16];
Pack.UInt64_To_BE(atLength * 8, array2, 0);
Pack.UInt64_To_BE(totalLength * 8, array2, 8);
gHASHBlock(S, array2);
byte[] array3 = new byte[16];
cipher.ProcessBlock(J0, 0, array3, 0);
GcmUtilities.Xor(array3, S);
int num2 = num;
macBlock = new byte[macSize];
Array.Copy(array3, 0, macBlock, 0, macSize);
if (forEncryption)
{
Array.Copy(macBlock, 0, output, outOff + bufOff, macSize);
num2 += macSize;
}
else
{
byte[] array4 = new byte[macSize];
Array.Copy(bufBlock, num, array4, 0, macSize);
if (!Arrays.ConstantTimeAreEqual(macBlock, array4))
{
throw new InvalidCipherTextException("mac check in GCM failed");
}
}
Reset(clearMac: false);
return num2;
}
public virtual void Reset()
{
Reset(clearMac: true);
}
private void Reset(bool clearMac)
{
cipher.Reset();
S = new byte[16];
S_at = new byte[16];
S_atPre = new byte[16];
atBlock = new byte[16];
atBlockPos = 0;
atLength = 0uL;
atLengthPre = 0uL;
counter = Arrays.Clone(J0);
blocksRemaining = 4294967294u;
bufOff = 0;
totalLength = 0uL;
if (bufBlock != null)
{
Arrays.Fill(bufBlock, 0);
}
if (clearMac)
{
macBlock = null;
}
if (forEncryption)
{
initialised = false;
}
else if (initialAssociatedText != null)
{
ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
}
}
private void ProcessBlock(byte[] buf, int bufOff, byte[] output, int outOff)
{
Check.OutputLength(output, outOff, 16, "Output buffer too short");
if (totalLength == 0)
{
InitCipher();
}
byte[] array = new byte[16];
GetNextCtrBlock(array);
if (forEncryption)
{
GcmUtilities.Xor(array, buf, bufOff);
gHASHBlock(S, array);
Array.Copy(array, 0, output, outOff, 16);
}
else
{
gHASHBlock(S, buf, bufOff);
GcmUtilities.Xor(array, 0, buf, bufOff, output, outOff);
}
totalLength += 16uL;
}
private void ProcessPartial(byte[] buf, int off, int len, byte[] output, int outOff)
{
byte[] array = new byte[16];
GetNextCtrBlock(array);
if (forEncryption)
{
GcmUtilities.Xor(buf, off, array, 0, len);
gHASHPartial(S, buf, off, len);
}
else
{
gHASHPartial(S, buf, off, len);
GcmUtilities.Xor(buf, off, array, 0, len);
}
Array.Copy(buf, off, output, outOff, len);
totalLength += (uint)len;
}
private void gHASH(byte[] Y, byte[] b, int len)
{
for (int i = 0; i < len; i += 16)
{
int len2 = System.Math.Min(len - i, 16);
gHASHPartial(Y, b, i, len2);
}
}
private void gHASHBlock(byte[] Y, byte[] b)
{
GcmUtilities.Xor(Y, b);
multiplier.MultiplyH(Y);
}
private void gHASHBlock(byte[] Y, byte[] b, int off)
{
GcmUtilities.Xor(Y, b, off);
multiplier.MultiplyH(Y);
}
private void gHASHPartial(byte[] Y, byte[] b, int off, int len)
{
GcmUtilities.Xor(Y, b, off, len);
multiplier.MultiplyH(Y);
}
private void GetNextCtrBlock(byte[] block)
{
if (blocksRemaining == 0)
{
throw new InvalidOperationException("Attempt to process too many blocks");
}
blocksRemaining--;
uint num = 1u;
num += counter[15];
counter[15] = (byte)num;
num >>= 8;
num += counter[14];
counter[14] = (byte)num;
num >>= 8;
num += counter[13];
counter[13] = (byte)num;
num >>= 8;
num += counter[12];
counter[12] = (byte)num;
cipher.ProcessBlock(counter, 0, block, 0);
}
private void CheckStatus()
{
if (!initialised)
{
if (forEncryption)
{
throw new InvalidOperationException("GCM cipher cannot be reused for encryption");
}
throw new InvalidOperationException("GCM cipher needs to be initialised");
}
}
}

View File

@@ -0,0 +1,30 @@
namespace Org.BouncyCastle.Crypto.Modes;
public interface IAeadBlockCipher
{
string AlgorithmName { get; }
IBlockCipher GetUnderlyingCipher();
void Init(bool forEncryption, ICipherParameters parameters);
int GetBlockSize();
void ProcessAadByte(byte input);
void ProcessAadBytes(byte[] inBytes, int inOff, int len);
int ProcessByte(byte input, byte[] outBytes, int outOff);
int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff);
int DoFinal(byte[] outBytes, int outOff);
byte[] GetMac();
int GetUpdateOutputSize(int len);
int GetOutputSize(int len);
void Reset();
}

View File

@@ -0,0 +1,418 @@
using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes;
public class KCcmBlockCipher : IAeadBlockCipher
{
private static readonly int BYTES_IN_INT = 4;
private static readonly int BITS_IN_BYTE = 8;
private static readonly int MAX_MAC_BIT_LENGTH = 512;
private static readonly int MIN_MAC_BIT_LENGTH = 64;
private IBlockCipher engine;
private int macSize;
private bool forEncryption;
private byte[] initialAssociatedText;
private byte[] mac;
private byte[] macBlock;
private byte[] nonce;
private byte[] G1;
private byte[] buffer;
private byte[] s;
private byte[] counter;
private readonly MemoryStream associatedText = new MemoryStream();
private readonly MemoryStream data = new MemoryStream();
private int Nb_ = 4;
public virtual string AlgorithmName => engine.AlgorithmName + "/KCCM";
private void setNb(int Nb)
{
if (Nb == 4 || Nb == 6 || Nb == 8)
{
Nb_ = Nb;
return;
}
throw new ArgumentException("Nb = 4 is recommended by DSTU7624 but can be changed to only 6 or 8 in this implementation");
}
public KCcmBlockCipher(IBlockCipher engine)
: this(engine, 4)
{
}
public KCcmBlockCipher(IBlockCipher engine, int Nb)
{
this.engine = engine;
macSize = engine.GetBlockSize();
nonce = new byte[engine.GetBlockSize()];
initialAssociatedText = new byte[engine.GetBlockSize()];
mac = new byte[engine.GetBlockSize()];
macBlock = new byte[engine.GetBlockSize()];
G1 = new byte[engine.GetBlockSize()];
buffer = new byte[engine.GetBlockSize()];
s = new byte[engine.GetBlockSize()];
counter = new byte[engine.GetBlockSize()];
setNb(Nb);
}
public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
ICipherParameters parameters2;
if (parameters is AeadParameters)
{
AeadParameters aeadParameters = (AeadParameters)parameters;
if (aeadParameters.MacSize > MAX_MAC_BIT_LENGTH || aeadParameters.MacSize < MIN_MAC_BIT_LENGTH || aeadParameters.MacSize % 8 != 0)
{
throw new ArgumentException("Invalid mac size specified");
}
nonce = aeadParameters.GetNonce();
macSize = aeadParameters.MacSize / BITS_IN_BYTE;
initialAssociatedText = aeadParameters.GetAssociatedText();
parameters2 = aeadParameters.Key;
}
else
{
if (!(parameters is ParametersWithIV))
{
throw new ArgumentException("Invalid parameters specified");
}
nonce = ((ParametersWithIV)parameters).GetIV();
macSize = engine.GetBlockSize();
initialAssociatedText = null;
parameters2 = ((ParametersWithIV)parameters).Parameters;
}
mac = new byte[macSize];
this.forEncryption = forEncryption;
engine.Init(forEncryption: true, parameters2);
counter[0] = 1;
if (initialAssociatedText != null)
{
ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
}
}
public virtual int GetBlockSize()
{
return engine.GetBlockSize();
}
public virtual IBlockCipher GetUnderlyingCipher()
{
return engine;
}
public virtual void ProcessAadByte(byte input)
{
associatedText.WriteByte(input);
}
public virtual void ProcessAadBytes(byte[] input, int inOff, int len)
{
associatedText.Write(input, inOff, len);
}
private void ProcessAAD(byte[] assocText, int assocOff, int assocLen, int dataLen)
{
if (assocLen - assocOff < engine.GetBlockSize())
{
throw new ArgumentException("authText buffer too short");
}
if (assocLen % engine.GetBlockSize() != 0)
{
throw new ArgumentException("padding not supported");
}
Array.Copy(nonce, 0, G1, 0, nonce.Length - Nb_ - 1);
intToBytes(dataLen, buffer, 0);
Array.Copy(buffer, 0, G1, nonce.Length - Nb_ - 1, BYTES_IN_INT);
G1[G1.Length - 1] = getFlag(authTextPresents: true, macSize);
engine.ProcessBlock(G1, 0, macBlock, 0);
intToBytes(assocLen, buffer, 0);
if (assocLen <= engine.GetBlockSize() - Nb_)
{
for (int i = 0; i < assocLen; i++)
{
byte[] array2;
byte[] array = (array2 = buffer);
int num = i + Nb_;
nint num2 = num;
array[num] = (byte)(array2[num2] ^ assocText[assocOff + i]);
}
for (int j = 0; j < engine.GetBlockSize(); j++)
{
byte[] array2;
byte[] array3 = (array2 = macBlock);
int num3 = j;
nint num2 = num3;
array3[num3] = (byte)(array2[num2] ^ buffer[j]);
}
engine.ProcessBlock(macBlock, 0, macBlock, 0);
return;
}
for (int k = 0; k < engine.GetBlockSize(); k++)
{
byte[] array2;
byte[] array4 = (array2 = macBlock);
int num4 = k;
nint num2 = num4;
array4[num4] = (byte)(array2[num2] ^ buffer[k]);
}
engine.ProcessBlock(macBlock, 0, macBlock, 0);
for (int num5 = assocLen; num5 != 0; num5 -= engine.GetBlockSize())
{
for (int l = 0; l < engine.GetBlockSize(); l++)
{
byte[] array2;
byte[] array5 = (array2 = macBlock);
int num6 = l;
nint num2 = num6;
array5[num6] = (byte)(array2[num2] ^ assocText[l + assocOff]);
}
engine.ProcessBlock(macBlock, 0, macBlock, 0);
assocOff += engine.GetBlockSize();
}
}
public virtual int ProcessByte(byte input, byte[] output, int outOff)
{
data.WriteByte(input);
return 0;
}
public virtual int ProcessBytes(byte[] input, int inOff, int inLen, byte[] output, int outOff)
{
Check.DataLength(input, inOff, inLen, "input buffer too short");
data.Write(input, inOff, inLen);
return 0;
}
public int ProcessPacket(byte[] input, int inOff, int len, byte[] output, int outOff)
{
Check.DataLength(input, inOff, len, "input buffer too short");
Check.OutputLength(output, outOff, len, "output buffer too short");
if (associatedText.Length > 0)
{
byte[] assocText = associatedText.GetBuffer();
int assocLen = (int)associatedText.Length;
int dataLen = (int)(forEncryption ? data.Length : ((int)data.Length - macSize));
ProcessAAD(assocText, 0, assocLen, dataLen);
}
if (forEncryption)
{
Check.DataLength(len % engine.GetBlockSize() != 0, "partial blocks not supported");
CalculateMac(input, inOff, len);
engine.ProcessBlock(nonce, 0, s, 0);
int num = len;
while (num > 0)
{
ProcessBlock(input, inOff, len, output, outOff);
num -= engine.GetBlockSize();
inOff += engine.GetBlockSize();
outOff += engine.GetBlockSize();
}
for (int i = 0; i < counter.Length; i++)
{
byte[] array2;
byte[] array = (array2 = s);
int num2 = i;
nint num3 = num2;
array[num2] = (byte)(array2[num3] + counter[i]);
}
engine.ProcessBlock(s, 0, buffer, 0);
for (int j = 0; j < macSize; j++)
{
output[outOff + j] = (byte)(buffer[j] ^ macBlock[j]);
}
Array.Copy(macBlock, 0, mac, 0, macSize);
Reset();
return len + macSize;
}
Check.DataLength((len - macSize) % engine.GetBlockSize() != 0, "partial blocks not supported");
engine.ProcessBlock(nonce, 0, s, 0);
int num4 = len / engine.GetBlockSize();
for (int k = 0; k < num4; k++)
{
ProcessBlock(input, inOff, len, output, outOff);
inOff += engine.GetBlockSize();
outOff += engine.GetBlockSize();
}
if (len > inOff)
{
for (int l = 0; l < counter.Length; l++)
{
byte[] array2;
byte[] array3 = (array2 = s);
int num5 = l;
nint num3 = num5;
array3[num5] = (byte)(array2[num3] + counter[l]);
}
engine.ProcessBlock(s, 0, buffer, 0);
for (int m = 0; m < macSize; m++)
{
output[outOff + m] = (byte)(buffer[m] ^ input[inOff + m]);
}
outOff += macSize;
}
for (int n = 0; n < counter.Length; n++)
{
byte[] array2;
byte[] array4 = (array2 = s);
int num6 = n;
nint num3 = num6;
array4[num6] = (byte)(array2[num3] + counter[n]);
}
engine.ProcessBlock(s, 0, buffer, 0);
Array.Copy(output, outOff - macSize, buffer, 0, macSize);
CalculateMac(output, 0, outOff - macSize);
Array.Copy(macBlock, 0, mac, 0, macSize);
byte[] array5 = new byte[macSize];
Array.Copy(buffer, 0, array5, 0, macSize);
if (!Arrays.ConstantTimeAreEqual(mac, array5))
{
throw new InvalidCipherTextException("mac check failed");
}
Reset();
return len - macSize;
}
private void ProcessBlock(byte[] input, int inOff, int len, byte[] output, int outOff)
{
for (int i = 0; i < counter.Length; i++)
{
byte[] array2;
byte[] array = (array2 = s);
int num = i;
nint num2 = num;
array[num] = (byte)(array2[num2] + counter[i]);
}
engine.ProcessBlock(s, 0, buffer, 0);
for (int j = 0; j < engine.GetBlockSize(); j++)
{
output[outOff + j] = (byte)(buffer[j] ^ input[inOff + j]);
}
}
private void CalculateMac(byte[] authText, int authOff, int len)
{
int num = len;
while (num > 0)
{
for (int i = 0; i < engine.GetBlockSize(); i++)
{
byte[] array2;
byte[] array = (array2 = macBlock);
int num2 = i;
nint num3 = num2;
array[num2] = (byte)(array2[num3] ^ authText[authOff + i]);
}
engine.ProcessBlock(macBlock, 0, macBlock, 0);
num -= engine.GetBlockSize();
authOff += engine.GetBlockSize();
}
}
public virtual int DoFinal(byte[] output, int outOff)
{
byte[] input = data.GetBuffer();
int len = (int)data.Length;
int result = ProcessPacket(input, 0, len, output, outOff);
Reset();
return result;
}
public virtual byte[] GetMac()
{
return Arrays.Clone(mac);
}
public virtual int GetUpdateOutputSize(int len)
{
return len;
}
public virtual int GetOutputSize(int len)
{
return len + macSize;
}
public virtual void Reset()
{
Arrays.Fill(G1, 0);
Arrays.Fill(buffer, 0);
Arrays.Fill(counter, 0);
Arrays.Fill(macBlock, 0);
counter[0] = 1;
data.SetLength(0L);
associatedText.SetLength(0L);
if (initialAssociatedText != null)
{
ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
}
}
private void intToBytes(int num, byte[] outBytes, int outOff)
{
outBytes[outOff + 3] = (byte)(num >> 24);
outBytes[outOff + 2] = (byte)(num >> 16);
outBytes[outOff + 1] = (byte)(num >> 8);
outBytes[outOff] = (byte)num;
}
private byte getFlag(bool authTextPresents, int macSize)
{
StringBuilder stringBuilder = new StringBuilder();
if (authTextPresents)
{
stringBuilder.Append("1");
}
else
{
stringBuilder.Append("0");
}
switch (macSize)
{
case 8:
stringBuilder.Append("010");
break;
case 16:
stringBuilder.Append("011");
break;
case 32:
stringBuilder.Append("100");
break;
case 48:
stringBuilder.Append("101");
break;
case 64:
stringBuilder.Append("110");
break;
}
string text = Convert.ToString(Nb_ - 1, 2);
while (text.Length < 4)
{
text = new StringBuilder(text).Insert(0, "0").ToString();
}
stringBuilder.Append(text);
return (byte)Convert.ToInt32(stringBuilder.ToString(), 2);
}
}

View File

@@ -0,0 +1,150 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Modes;
public class KCtrBlockCipher : IStreamCipher, IBlockCipher
{
private byte[] IV;
private byte[] ofbV;
private byte[] ofbOutV;
private bool initialised;
private int byteCount;
private readonly int blockSize;
private readonly IBlockCipher cipher;
public string AlgorithmName => cipher.AlgorithmName + "/KCTR";
public bool IsPartialBlockOkay => true;
public KCtrBlockCipher(IBlockCipher cipher)
{
this.cipher = cipher;
IV = new byte[cipher.GetBlockSize()];
blockSize = cipher.GetBlockSize();
ofbV = new byte[cipher.GetBlockSize()];
ofbOutV = new byte[cipher.GetBlockSize()];
}
public IBlockCipher GetUnderlyingCipher()
{
return cipher;
}
public void Init(bool forEncryption, ICipherParameters parameters)
{
initialised = true;
if (parameters is ParametersWithIV)
{
ParametersWithIV parametersWithIV = (ParametersWithIV)parameters;
byte[] iV = parametersWithIV.GetIV();
int destinationIndex = IV.Length - iV.Length;
Array.Clear(IV, 0, IV.Length);
Array.Copy(iV, 0, IV, destinationIndex, iV.Length);
parameters = parametersWithIV.Parameters;
if (parameters != null)
{
cipher.Init(forEncryption: true, parameters);
}
Reset();
return;
}
throw new ArgumentException("Invalid parameter passed");
}
public int GetBlockSize()
{
return cipher.GetBlockSize();
}
public byte ReturnByte(byte input)
{
return CalculateByte(input);
}
public void ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
if (outOff + len > output.Length)
{
throw new DataLengthException("Output buffer too short");
}
if (inOff + len > input.Length)
{
throw new DataLengthException("Input buffer too small");
}
int num = inOff;
int num2 = inOff + len;
int num3 = outOff;
while (num < num2)
{
output[num3++] = CalculateByte(input[num++]);
}
}
protected byte CalculateByte(byte b)
{
if (byteCount == 0)
{
incrementCounterAt(0);
checkCounter();
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
return (byte)(ofbOutV[byteCount++] ^ b);
}
byte result = (byte)(ofbOutV[byteCount++] ^ b);
if (byteCount == ofbV.Length)
{
byteCount = 0;
}
return result;
}
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (input.Length - inOff < GetBlockSize())
{
throw new DataLengthException("Input buffer too short");
}
if (output.Length - outOff < GetBlockSize())
{
throw new DataLengthException("Output buffer too short");
}
ProcessBytes(input, inOff, GetBlockSize(), output, outOff);
return GetBlockSize();
}
public void Reset()
{
if (initialised)
{
cipher.ProcessBlock(IV, 0, ofbV, 0);
}
cipher.Reset();
byteCount = 0;
}
private void incrementCounterAt(int pos)
{
int num = pos;
while (num < ofbV.Length)
{
byte[] array2;
byte[] array = (array2 = ofbV);
int num2 = num++;
nint num3 = num2;
if ((array[num2] = (byte)(array2[num3] + 1)) != 0)
{
break;
}
}
}
private void checkCounter()
{
}
}

View File

@@ -0,0 +1,488 @@
using System;
using System.Collections;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes;
public class OcbBlockCipher : IAeadBlockCipher
{
private const int BLOCK_SIZE = 16;
private readonly IBlockCipher hashCipher;
private readonly IBlockCipher mainCipher;
private bool forEncryption;
private int macSize;
private byte[] initialAssociatedText;
private IList L;
private byte[] L_Asterisk;
private byte[] L_Dollar;
private byte[] KtopInput = null;
private byte[] Stretch = new byte[24];
private byte[] OffsetMAIN_0 = new byte[16];
private byte[] hashBlock;
private byte[] mainBlock;
private int hashBlockPos;
private int mainBlockPos;
private long hashBlockCount;
private long mainBlockCount;
private byte[] OffsetHASH;
private byte[] Sum;
private byte[] OffsetMAIN = new byte[16];
private byte[] Checksum;
private byte[] macBlock;
public virtual string AlgorithmName => mainCipher.AlgorithmName + "/OCB";
public OcbBlockCipher(IBlockCipher hashCipher, IBlockCipher mainCipher)
{
if (hashCipher == null)
{
throw new ArgumentNullException("hashCipher");
}
if (hashCipher.GetBlockSize() != 16)
{
throw new ArgumentException("must have a block size of " + 16, "hashCipher");
}
if (mainCipher == null)
{
throw new ArgumentNullException("mainCipher");
}
if (mainCipher.GetBlockSize() != 16)
{
throw new ArgumentException("must have a block size of " + 16, "mainCipher");
}
if (!hashCipher.AlgorithmName.Equals(mainCipher.AlgorithmName))
{
throw new ArgumentException("'hashCipher' and 'mainCipher' must be the same algorithm");
}
this.hashCipher = hashCipher;
this.mainCipher = mainCipher;
}
public virtual IBlockCipher GetUnderlyingCipher()
{
return mainCipher;
}
public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
bool flag = this.forEncryption;
this.forEncryption = forEncryption;
macBlock = null;
byte[] array;
KeyParameter keyParameter;
if (parameters is AeadParameters)
{
AeadParameters aeadParameters = (AeadParameters)parameters;
array = aeadParameters.GetNonce();
initialAssociatedText = aeadParameters.GetAssociatedText();
int num = aeadParameters.MacSize;
if (num < 64 || num > 128 || num % 8 != 0)
{
throw new ArgumentException("Invalid value for MAC size: " + num);
}
macSize = num / 8;
keyParameter = aeadParameters.Key;
}
else
{
if (!(parameters is ParametersWithIV))
{
throw new ArgumentException("invalid parameters passed to OCB");
}
ParametersWithIV parametersWithIV = (ParametersWithIV)parameters;
array = parametersWithIV.GetIV();
initialAssociatedText = null;
macSize = 16;
keyParameter = (KeyParameter)parametersWithIV.Parameters;
}
hashBlock = new byte[16];
mainBlock = new byte[forEncryption ? 16 : (16 + macSize)];
if (array == null)
{
array = new byte[0];
}
if (array.Length > 15)
{
throw new ArgumentException("IV must be no more than 15 bytes");
}
if (keyParameter != null)
{
hashCipher.Init(forEncryption: true, keyParameter);
mainCipher.Init(forEncryption, keyParameter);
KtopInput = null;
}
else if (flag != forEncryption)
{
throw new ArgumentException("cannot change encrypting state without providing key.");
}
L_Asterisk = new byte[16];
hashCipher.ProcessBlock(L_Asterisk, 0, L_Asterisk, 0);
L_Dollar = OCB_double(L_Asterisk);
L = Platform.CreateArrayList();
L.Add(OCB_double(L_Dollar));
int num2 = ProcessNonce(array);
int num3 = num2 % 8;
int num4 = num2 / 8;
if (num3 == 0)
{
Array.Copy(Stretch, num4, OffsetMAIN_0, 0, 16);
}
else
{
for (int i = 0; i < 16; i++)
{
uint num5 = Stretch[num4];
uint num6 = Stretch[++num4];
OffsetMAIN_0[i] = (byte)((num5 << num3) | (num6 >> 8 - num3));
}
}
hashBlockPos = 0;
mainBlockPos = 0;
hashBlockCount = 0L;
mainBlockCount = 0L;
OffsetHASH = new byte[16];
Sum = new byte[16];
Array.Copy(OffsetMAIN_0, 0, OffsetMAIN, 0, 16);
Checksum = new byte[16];
if (initialAssociatedText != null)
{
ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
}
}
protected virtual int ProcessNonce(byte[] N)
{
byte[] array = new byte[16];
Array.Copy(N, 0, array, array.Length - N.Length, N.Length);
array[0] = (byte)(macSize << 4);
byte[] array3;
byte[] array2 = (array3 = array);
int num = 15 - N.Length;
nint num2 = num;
array2[num] = (byte)(array3[num2] | 1);
int result = array[15] & 0x3F;
(array3 = array)[15] = (byte)(array3[15] & 0xC0);
if (KtopInput == null || !Arrays.AreEqual(array, KtopInput))
{
byte[] array4 = new byte[16];
KtopInput = array;
hashCipher.ProcessBlock(KtopInput, 0, array4, 0);
Array.Copy(array4, 0, Stretch, 0, 16);
for (int i = 0; i < 8; i++)
{
Stretch[16 + i] = (byte)(array4[i] ^ array4[i + 1]);
}
}
return result;
}
public virtual int GetBlockSize()
{
return 16;
}
public virtual byte[] GetMac()
{
if (macBlock != null)
{
return Arrays.Clone(macBlock);
}
return new byte[macSize];
}
public virtual int GetOutputSize(int len)
{
int num = len + mainBlockPos;
if (forEncryption)
{
return num + macSize;
}
if (num >= macSize)
{
return num - macSize;
}
return 0;
}
public virtual int GetUpdateOutputSize(int len)
{
int num = len + mainBlockPos;
if (!forEncryption)
{
if (num < macSize)
{
return 0;
}
num -= macSize;
}
return num - num % 16;
}
public virtual void ProcessAadByte(byte input)
{
hashBlock[hashBlockPos] = input;
if (++hashBlockPos == hashBlock.Length)
{
ProcessHashBlock();
}
}
public virtual void ProcessAadBytes(byte[] input, int off, int len)
{
for (int i = 0; i < len; i++)
{
hashBlock[hashBlockPos] = input[off + i];
if (++hashBlockPos == hashBlock.Length)
{
ProcessHashBlock();
}
}
}
public virtual int ProcessByte(byte input, byte[] output, int outOff)
{
mainBlock[mainBlockPos] = input;
if (++mainBlockPos == mainBlock.Length)
{
ProcessMainBlock(output, outOff);
return 16;
}
return 0;
}
public virtual int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
int num = 0;
for (int i = 0; i < len; i++)
{
mainBlock[mainBlockPos] = input[inOff + i];
if (++mainBlockPos == mainBlock.Length)
{
ProcessMainBlock(output, outOff + num);
num += 16;
}
}
return num;
}
public virtual int DoFinal(byte[] output, int outOff)
{
byte[] array = null;
if (!forEncryption)
{
if (mainBlockPos < macSize)
{
throw new InvalidCipherTextException("data too short");
}
mainBlockPos -= macSize;
array = new byte[macSize];
Array.Copy(mainBlock, mainBlockPos, array, 0, macSize);
}
if (hashBlockPos > 0)
{
OCB_extend(hashBlock, hashBlockPos);
UpdateHASH(L_Asterisk);
}
if (mainBlockPos > 0)
{
if (forEncryption)
{
OCB_extend(mainBlock, mainBlockPos);
Xor(Checksum, mainBlock);
}
Xor(OffsetMAIN, L_Asterisk);
byte[] array2 = new byte[16];
hashCipher.ProcessBlock(OffsetMAIN, 0, array2, 0);
Xor(mainBlock, array2);
Check.OutputLength(output, outOff, mainBlockPos, "Output buffer too short");
Array.Copy(mainBlock, 0, output, outOff, mainBlockPos);
if (!forEncryption)
{
OCB_extend(mainBlock, mainBlockPos);
Xor(Checksum, mainBlock);
}
}
Xor(Checksum, OffsetMAIN);
Xor(Checksum, L_Dollar);
hashCipher.ProcessBlock(Checksum, 0, Checksum, 0);
Xor(Checksum, Sum);
macBlock = new byte[macSize];
Array.Copy(Checksum, 0, macBlock, 0, macSize);
int num = mainBlockPos;
if (forEncryption)
{
Check.OutputLength(output, outOff, num + macSize, "Output buffer too short");
Array.Copy(macBlock, 0, output, outOff + num, macSize);
num += macSize;
}
else if (!Arrays.ConstantTimeAreEqual(macBlock, array))
{
throw new InvalidCipherTextException("mac check in OCB failed");
}
Reset(clearMac: false);
return num;
}
public virtual void Reset()
{
Reset(clearMac: true);
}
protected virtual void Clear(byte[] bs)
{
if (bs != null)
{
Array.Clear(bs, 0, bs.Length);
}
}
protected virtual byte[] GetLSub(int n)
{
while (n >= L.Count)
{
L.Add(OCB_double((byte[])L[L.Count - 1]));
}
return (byte[])L[n];
}
protected virtual void ProcessHashBlock()
{
UpdateHASH(GetLSub(OCB_ntz(++hashBlockCount)));
hashBlockPos = 0;
}
protected virtual void ProcessMainBlock(byte[] output, int outOff)
{
Check.DataLength(output, outOff, 16, "Output buffer too short");
if (forEncryption)
{
Xor(Checksum, mainBlock);
mainBlockPos = 0;
}
Xor(OffsetMAIN, GetLSub(OCB_ntz(++mainBlockCount)));
Xor(mainBlock, OffsetMAIN);
mainCipher.ProcessBlock(mainBlock, 0, mainBlock, 0);
Xor(mainBlock, OffsetMAIN);
Array.Copy(mainBlock, 0, output, outOff, 16);
if (!forEncryption)
{
Xor(Checksum, mainBlock);
Array.Copy(mainBlock, 16, mainBlock, 0, macSize);
mainBlockPos = macSize;
}
}
protected virtual void Reset(bool clearMac)
{
hashCipher.Reset();
mainCipher.Reset();
Clear(hashBlock);
Clear(mainBlock);
hashBlockPos = 0;
mainBlockPos = 0;
hashBlockCount = 0L;
mainBlockCount = 0L;
Clear(OffsetHASH);
Clear(Sum);
Array.Copy(OffsetMAIN_0, 0, OffsetMAIN, 0, 16);
Clear(Checksum);
if (clearMac)
{
macBlock = null;
}
if (initialAssociatedText != null)
{
ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
}
}
protected virtual void UpdateHASH(byte[] LSub)
{
Xor(OffsetHASH, LSub);
Xor(hashBlock, OffsetHASH);
hashCipher.ProcessBlock(hashBlock, 0, hashBlock, 0);
Xor(Sum, hashBlock);
}
protected static byte[] OCB_double(byte[] block)
{
byte[] array = new byte[16];
int num = ShiftLeft(block, array);
byte[] array2;
(array2 = array)[15] = (byte)(array2[15] ^ (byte)(135 >> (1 - num << 3)));
return array;
}
protected static void OCB_extend(byte[] block, int pos)
{
block[pos] = 128;
while (++pos < 16)
{
block[pos] = 0;
}
}
protected static int OCB_ntz(long x)
{
if (x == 0)
{
return 64;
}
int num = 0;
ulong num2 = (ulong)x;
while ((num2 & 1) == 0)
{
num++;
num2 >>= 1;
}
return num;
}
protected static int ShiftLeft(byte[] block, byte[] output)
{
int num = 16;
uint num2 = 0u;
while (--num >= 0)
{
uint num3 = block[num];
output[num] = (byte)((num3 << 1) | num2);
num2 = (num3 >> 7) & 1;
}
return (int)num2;
}
protected static void Xor(byte[] block, byte[] val)
{
for (int num = 15; num >= 0; num--)
{
byte[] array2;
byte[] array = (array2 = block);
int num2 = num;
nint num3 = num2;
array[num2] = (byte)(array2[num3] ^ val[num]);
}
}
}

View File

@@ -0,0 +1,93 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Modes;
public class OfbBlockCipher : IBlockCipher
{
private byte[] IV;
private byte[] ofbV;
private byte[] ofbOutV;
private readonly int blockSize;
private readonly IBlockCipher cipher;
public string AlgorithmName => cipher.AlgorithmName + "/OFB" + blockSize * 8;
public bool IsPartialBlockOkay => true;
public OfbBlockCipher(IBlockCipher cipher, int blockSize)
{
this.cipher = cipher;
this.blockSize = blockSize / 8;
IV = new byte[cipher.GetBlockSize()];
ofbV = new byte[cipher.GetBlockSize()];
ofbOutV = new byte[cipher.GetBlockSize()];
}
public IBlockCipher GetUnderlyingCipher()
{
return cipher;
}
public void Init(bool forEncryption, ICipherParameters parameters)
{
if (parameters is ParametersWithIV)
{
ParametersWithIV parametersWithIV = (ParametersWithIV)parameters;
byte[] iV = parametersWithIV.GetIV();
if (iV.Length < IV.Length)
{
Array.Copy(iV, 0, IV, IV.Length - iV.Length, iV.Length);
for (int i = 0; i < IV.Length - iV.Length; i++)
{
IV[i] = 0;
}
}
else
{
Array.Copy(iV, 0, IV, 0, IV.Length);
}
parameters = parametersWithIV.Parameters;
}
Reset();
if (parameters != null)
{
cipher.Init(forEncryption: true, parameters);
}
}
public int GetBlockSize()
{
return blockSize;
}
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (inOff + blockSize > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if (outOff + blockSize > output.Length)
{
throw new DataLengthException("output buffer too short");
}
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
for (int i = 0; i < blockSize; i++)
{
output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]);
}
Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
return blockSize;
}
public void Reset()
{
Array.Copy(IV, 0, ofbV, 0, IV.Length);
cipher.Reset();
}
}

View File

@@ -0,0 +1,194 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Modes;
public class OpenPgpCfbBlockCipher : IBlockCipher
{
private byte[] IV;
private byte[] FR;
private byte[] FRE;
private readonly IBlockCipher cipher;
private readonly int blockSize;
private int count;
private bool forEncryption;
public string AlgorithmName => cipher.AlgorithmName + "/OpenPGPCFB";
public bool IsPartialBlockOkay => true;
public OpenPgpCfbBlockCipher(IBlockCipher cipher)
{
this.cipher = cipher;
blockSize = cipher.GetBlockSize();
IV = new byte[blockSize];
FR = new byte[blockSize];
FRE = new byte[blockSize];
}
public IBlockCipher GetUnderlyingCipher()
{
return cipher;
}
public int GetBlockSize()
{
return cipher.GetBlockSize();
}
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (!forEncryption)
{
return DecryptBlock(input, inOff, output, outOff);
}
return EncryptBlock(input, inOff, output, outOff);
}
public void Reset()
{
count = 0;
Array.Copy(IV, 0, FR, 0, FR.Length);
cipher.Reset();
}
public void Init(bool forEncryption, ICipherParameters parameters)
{
this.forEncryption = forEncryption;
if (parameters is ParametersWithIV)
{
ParametersWithIV parametersWithIV = (ParametersWithIV)parameters;
byte[] iV = parametersWithIV.GetIV();
if (iV.Length < IV.Length)
{
Array.Copy(iV, 0, IV, IV.Length - iV.Length, iV.Length);
for (int i = 0; i < IV.Length - iV.Length; i++)
{
IV[i] = 0;
}
}
else
{
Array.Copy(iV, 0, IV, 0, IV.Length);
}
parameters = parametersWithIV.Parameters;
}
Reset();
cipher.Init(forEncryption: true, parameters);
}
private byte EncryptByte(byte data, int blockOff)
{
return (byte)(FRE[blockOff] ^ data);
}
private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
if (inOff + blockSize > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if (outOff + blockSize > outBytes.Length)
{
throw new DataLengthException("output buffer too short");
}
if (count > blockSize)
{
FR[blockSize - 2] = (outBytes[outOff] = EncryptByte(input[inOff], blockSize - 2));
FR[blockSize - 1] = (outBytes[outOff + 1] = EncryptByte(input[inOff + 1], blockSize - 1));
cipher.ProcessBlock(FR, 0, FRE, 0);
for (int i = 2; i < blockSize; i++)
{
FR[i - 2] = (outBytes[outOff + i] = EncryptByte(input[inOff + i], i - 2));
}
}
else if (count == 0)
{
cipher.ProcessBlock(FR, 0, FRE, 0);
for (int j = 0; j < blockSize; j++)
{
FR[j] = (outBytes[outOff + j] = EncryptByte(input[inOff + j], j));
}
count += blockSize;
}
else if (count == blockSize)
{
cipher.ProcessBlock(FR, 0, FRE, 0);
outBytes[outOff] = EncryptByte(input[inOff], 0);
outBytes[outOff + 1] = EncryptByte(input[inOff + 1], 1);
Array.Copy(FR, 2, FR, 0, blockSize - 2);
Array.Copy(outBytes, outOff, FR, blockSize - 2, 2);
cipher.ProcessBlock(FR, 0, FRE, 0);
for (int k = 2; k < blockSize; k++)
{
FR[k - 2] = (outBytes[outOff + k] = EncryptByte(input[inOff + k], k - 2));
}
count += blockSize;
}
return blockSize;
}
private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
if (inOff + blockSize > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if (outOff + blockSize > outBytes.Length)
{
throw new DataLengthException("output buffer too short");
}
if (count > blockSize)
{
byte b = input[inOff];
FR[blockSize - 2] = b;
outBytes[outOff] = EncryptByte(b, blockSize - 2);
b = input[inOff + 1];
FR[blockSize - 1] = b;
outBytes[outOff + 1] = EncryptByte(b, blockSize - 1);
cipher.ProcessBlock(FR, 0, FRE, 0);
for (int i = 2; i < blockSize; i++)
{
b = input[inOff + i];
FR[i - 2] = b;
outBytes[outOff + i] = EncryptByte(b, i - 2);
}
}
else if (count == 0)
{
cipher.ProcessBlock(FR, 0, FRE, 0);
for (int j = 0; j < blockSize; j++)
{
FR[j] = input[inOff + j];
outBytes[j] = EncryptByte(input[inOff + j], j);
}
count += blockSize;
}
else if (count == blockSize)
{
cipher.ProcessBlock(FR, 0, FRE, 0);
byte b2 = input[inOff];
byte b3 = input[inOff + 1];
outBytes[outOff] = EncryptByte(b2, 0);
outBytes[outOff + 1] = EncryptByte(b3, 1);
Array.Copy(FR, 2, FR, 0, blockSize - 2);
FR[blockSize - 2] = b2;
FR[blockSize - 1] = b3;
cipher.ProcessBlock(FR, 0, FRE, 0);
for (int k = 2; k < blockSize; k++)
{
byte b4 = input[inOff + k];
FR[k - 2] = b4;
outBytes[outOff + k] = EncryptByte(b4, k - 2);
}
count += blockSize;
}
return blockSize;
}
}

View File

@@ -0,0 +1,93 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes;
public class SicBlockCipher : IBlockCipher
{
private readonly IBlockCipher cipher;
private readonly int blockSize;
private readonly byte[] counter;
private readonly byte[] counterOut;
private byte[] IV;
public virtual string AlgorithmName => cipher.AlgorithmName + "/SIC";
public virtual bool IsPartialBlockOkay => true;
public SicBlockCipher(IBlockCipher cipher)
{
this.cipher = cipher;
blockSize = cipher.GetBlockSize();
counter = new byte[blockSize];
counterOut = new byte[blockSize];
IV = new byte[blockSize];
}
public virtual IBlockCipher GetUnderlyingCipher()
{
return cipher;
}
public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
if (!(parameters is ParametersWithIV parametersWithIV))
{
throw new ArgumentException("CTR/SIC mode requires ParametersWithIV", "parameters");
}
IV = Arrays.Clone(parametersWithIV.GetIV());
if (blockSize < IV.Length)
{
throw new ArgumentException("CTR/SIC mode requires IV no greater than: " + blockSize + " bytes.");
}
int num = System.Math.Min(8, blockSize / 2);
if (blockSize - IV.Length > num)
{
throw new ArgumentException("CTR/SIC mode requires IV of at least: " + (blockSize - num) + " bytes.");
}
if (parametersWithIV.Parameters != null)
{
cipher.Init(forEncryption: true, parametersWithIV.Parameters);
}
Reset();
}
public virtual int GetBlockSize()
{
return cipher.GetBlockSize();
}
public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
cipher.ProcessBlock(counter, 0, counterOut, 0);
for (int i = 0; i < counterOut.Length; i++)
{
output[outOff + i] = (byte)(counterOut[i] ^ input[inOff + i]);
}
int num = counter.Length;
while (--num >= 0)
{
byte[] array2;
byte[] array = (array2 = counter);
int num2 = num;
nint num3 = num2;
if ((array[num2] = (byte)(array2[num3] + 1)) != 0)
{
break;
}
}
return counter.Length;
}
public virtual void Reset()
{
Arrays.Fill(counter, 0);
Array.Copy(IV, 0, counter, 0, IV.Length);
cipher.Reset();
}
}