init commit
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Org.BouncyCastle.Crypto.Modes.Gcm;
|
||||
|
||||
public interface IGcmExponentiator
|
||||
{
|
||||
void Init(byte[] x);
|
||||
|
||||
void ExponentiateX(long pow, byte[] output);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Org.BouncyCastle.Crypto.Modes.Gcm;
|
||||
|
||||
public interface IGcmMultiplier
|
||||
{
|
||||
void Init(byte[] H);
|
||||
|
||||
void MultiplyH(byte[] x);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user