add all
This commit is contained in:
221
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CbcBlockCipher.cs
vendored
Normal file
221
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CbcBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
|
||||
*/
|
||||
public sealed class CbcBlockCipher
|
||||
: IBlockCipherMode
|
||||
{
|
||||
private byte[] IV, cbcV, cbcNextV;
|
||||
private int blockSize;
|
||||
private IBlockCipher cipher;
|
||||
private bool encrypting;
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used as the basis of chaining.
|
||||
*/
|
||||
public CbcBlockCipher(
|
||||
IBlockCipher cipher)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.blockSize = cipher.GetBlockSize();
|
||||
|
||||
this.IV = new byte[blockSize];
|
||||
this.cbcV = new byte[blockSize];
|
||||
this.cbcNextV = new byte[blockSize];
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public IBlockCipher UnderlyingCipher => cipher;
|
||||
|
||||
/**
|
||||
* Initialise the cipher and, possibly, the initialisation vector (IV).
|
||||
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
|
||||
*
|
||||
* @param forEncryption if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param param the key and other data required by the cipher.
|
||||
* @exception ArgumentException if the parameters argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void Init(bool forEncryption, ICipherParameters parameters)
|
||||
{
|
||||
bool oldEncrypting = this.encrypting;
|
||||
|
||||
this.encrypting = forEncryption;
|
||||
|
||||
if (parameters is ParametersWithIV ivParam)
|
||||
{
|
||||
byte[] iv = ivParam.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 = ivParam.Parameters;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
// if null it's an IV changed only.
|
||||
if (parameters != null)
|
||||
{
|
||||
cipher.Init(encrypting, parameters);
|
||||
}
|
||||
else if (oldEncrypting != encrypting)
|
||||
{
|
||||
throw new ArgumentException("cannot change encrypting state without providing key.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the algorithm name and mode.
|
||||
*
|
||||
* @return the name of the underlying algorithm followed by "/CBC".
|
||||
*/
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/CBC"; }
|
||||
}
|
||||
|
||||
public bool IsPartialBlockOkay
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block size of the underlying cipher.
|
||||
*
|
||||
* @return the block size of the underlying cipher.
|
||||
*/
|
||||
public int GetBlockSize()
|
||||
{
|
||||
return cipher.GetBlockSize();
|
||||
}
|
||||
|
||||
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
|
||||
{
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return encrypting
|
||||
? EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff))
|
||||
: DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
|
||||
#else
|
||||
return encrypting
|
||||
? EncryptBlock(input, inOff, output, outOff)
|
||||
: DecryptBlock(input, inOff, output, outOff);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
return encrypting
|
||||
? EncryptBlock(input, output)
|
||||
: DecryptBlock(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* reset the chaining vector back to the IV and reset the underlying
|
||||
* cipher.
|
||||
*/
|
||||
public void Reset()
|
||||
{
|
||||
Array.Copy(IV, 0, cbcV, 0, IV.Length);
|
||||
Array.Clear(cbcNextV, 0, cbcNextV.Length);
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
Check.DataLength(input, blockSize, "input buffer too short");
|
||||
Check.OutputLength(output, blockSize, "output buffer too short");
|
||||
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
cbcV[i] ^= input[i];
|
||||
}
|
||||
|
||||
int length = cipher.ProcessBlock(cbcV, output);
|
||||
|
||||
output[..blockSize].CopyTo(cbcV);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
Check.DataLength(input, blockSize, "input buffer too short");
|
||||
Check.OutputLength(output, blockSize, "output buffer too short");
|
||||
|
||||
input[..blockSize].CopyTo(cbcNextV);
|
||||
|
||||
int length = cipher.ProcessBlock(input, output);
|
||||
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
output[i] ^= cbcV[i];
|
||||
}
|
||||
|
||||
byte[] tmp = cbcV;
|
||||
cbcV = cbcNextV;
|
||||
cbcNextV = tmp;
|
||||
|
||||
return length;
|
||||
}
|
||||
#else
|
||||
private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
|
||||
{
|
||||
Check.DataLength(input, inOff, blockSize, "input buffer too short");
|
||||
Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
|
||||
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
cbcV[i] ^= input[inOff + i];
|
||||
}
|
||||
|
||||
int length = cipher.ProcessBlock(cbcV, 0, outBytes, outOff);
|
||||
|
||||
Array.Copy(outBytes, outOff, cbcV, 0, cbcV.Length);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
|
||||
{
|
||||
Check.DataLength(input, inOff, blockSize, "input buffer too short");
|
||||
Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
|
||||
|
||||
Array.Copy(input, inOff, cbcNextV, 0, blockSize);
|
||||
|
||||
int length = cipher.ProcessBlock(input, inOff, outBytes, outOff);
|
||||
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
outBytes[outOff + i] ^= cbcV[i];
|
||||
}
|
||||
|
||||
byte[] tmp = cbcV;
|
||||
cbcV = cbcNextV;
|
||||
cbcNextV = tmp;
|
||||
|
||||
return length;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CbcBlockCipher.cs.meta
vendored
Normal file
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CbcBlockCipher.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81829f4c01d07fb4e9361e5200b2ff07
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
659
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CcmBlockCipher.cs
vendored
Normal file
659
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CcmBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,659 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
|
||||
* NIST Special Publication 800-38C.
|
||||
* <p>
|
||||
* <b>Note</b>: this mode is a packet mode - it needs all the data up front.
|
||||
* </p>
|
||||
*/
|
||||
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();
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used.
|
||||
*/
|
||||
public CcmBlockCipher(
|
||||
IBlockCipher cipher)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.macBlock = new byte[BlockSize];
|
||||
|
||||
if (cipher.GetBlockSize() != BlockSize)
|
||||
throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public virtual IBlockCipher UnderlyingCipher => cipher;
|
||||
|
||||
public virtual void Init(bool forEncryption, ICipherParameters parameters)
|
||||
{
|
||||
this.forEncryption = forEncryption;
|
||||
|
||||
ICipherParameters cipherParameters;
|
||||
if (parameters is AeadParameters aeadParameters)
|
||||
{
|
||||
nonce = aeadParameters.GetNonce();
|
||||
initialAssociatedText = aeadParameters.GetAssociatedText();
|
||||
macSize = GetMacSize(forEncryption, aeadParameters.MacSize);
|
||||
cipherParameters = aeadParameters.Key;
|
||||
}
|
||||
else if (parameters is ParametersWithIV parametersWithIV)
|
||||
{
|
||||
nonce = parametersWithIV.GetIV();
|
||||
initialAssociatedText = null;
|
||||
macSize = GetMacSize(forEncryption, 64);
|
||||
cipherParameters = parametersWithIV.Parameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("invalid parameters passed to CCM");
|
||||
}
|
||||
|
||||
// NOTE: Very basic support for key re-use, but no performance gain from it
|
||||
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 string AlgorithmName => cipher.AlgorithmName + "/CCM";
|
||||
|
||||
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)
|
||||
{
|
||||
// TODO: Process AAD online
|
||||
associatedText.Write(inBytes, inOff, len);
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
|
||||
{
|
||||
// TODO: Process AAD online
|
||||
associatedText.Write(input);
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual int ProcessByte(byte input, byte[] outBytes, int outOff)
|
||||
{
|
||||
data.WriteByte(input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int ProcessByte(byte input, Span<byte> output)
|
||||
{
|
||||
data.WriteByte(input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
data.Write(input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual int DoFinal(byte[] outBytes, int outOff)
|
||||
{
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return DoFinal(outBytes.AsSpan(outOff));
|
||||
#else
|
||||
byte[] input = data.GetBuffer();
|
||||
int inLen = Convert.ToInt32(data.Length);
|
||||
|
||||
int len = ProcessPacket(input, 0, inLen, outBytes, outOff);
|
||||
|
||||
Reset();
|
||||
|
||||
return len;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int DoFinal(Span<byte> output)
|
||||
{
|
||||
byte[] input = data.GetBuffer();
|
||||
int inLen = Convert.ToInt32(data.Length);
|
||||
|
||||
int len = ProcessPacket(input.AsSpan(0, inLen), output);
|
||||
|
||||
Reset();
|
||||
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
associatedText.SetLength(0);
|
||||
data.SetLength(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte array containing the mac calculated as part of the
|
||||
* last encrypt or decrypt operation.
|
||||
*
|
||||
* @return the last mac calculated.
|
||||
*/
|
||||
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 totalData = Convert.ToInt32(data.Length) + len;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
return totalData + macSize;
|
||||
}
|
||||
|
||||
return totalData < macSize ? 0 : totalData - macSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a packet of data for either CCM decryption or encryption.
|
||||
*
|
||||
* @param in data for processing.
|
||||
* @param inOff offset at which data starts in the input array.
|
||||
* @param inLen length of the data in the input array.
|
||||
* @return a byte array containing the processed input..
|
||||
* @throws IllegalStateException if the cipher is not appropriately set up.
|
||||
* @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
|
||||
*/
|
||||
public virtual byte[] ProcessPacket(byte[] input, int inOff, int inLen)
|
||||
{
|
||||
byte[] output;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
output = new byte[inLen + macSize];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inLen < macSize)
|
||||
throw new InvalidCipherTextException("data too short");
|
||||
|
||||
output = new byte[inLen - macSize];
|
||||
}
|
||||
|
||||
ProcessPacket(input, inOff, inLen, output, 0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a packet of data for either CCM decryption or encryption.
|
||||
*
|
||||
* @param in data for processing.
|
||||
* @param inOff offset at which data starts in the input array.
|
||||
* @param inLen length of the data in the input array.
|
||||
* @param output output array.
|
||||
* @param outOff offset into output array to start putting processed bytes.
|
||||
* @return the number of bytes added to output.
|
||||
* @throws IllegalStateException if the cipher is not appropriately set up.
|
||||
* @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
|
||||
* @throws DataLengthException if output buffer too short.
|
||||
*/
|
||||
public virtual int ProcessPacket(byte[] input, int inOff, int inLen, byte[] output, int outOff)
|
||||
{
|
||||
// TODO: handle null keyParam (e.g. via RepeatedKeySpec)
|
||||
// Need to keep the CTR and CBC Mac parts around and reset
|
||||
if (keyParam == null)
|
||||
throw new InvalidOperationException("CCM cipher unitialized.");
|
||||
|
||||
int n = nonce.Length;
|
||||
int q = 15 - n;
|
||||
if (q < 4)
|
||||
{
|
||||
int limitLen = 1 << (8 * q);
|
||||
if (inLen >= limitLen)
|
||||
throw new InvalidOperationException("CCM packet too large for choice of q.");
|
||||
}
|
||||
|
||||
byte[] iv = new byte[BlockSize];
|
||||
iv[0] = (byte)((q - 1) & 0x7);
|
||||
nonce.CopyTo(iv, 1);
|
||||
|
||||
IBlockCipher ctrCipher = new SicBlockCipher(cipher);
|
||||
ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
|
||||
|
||||
int outputLen;
|
||||
int inIndex = inOff;
|
||||
int outIndex = outOff;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
outputLen = inLen + macSize;
|
||||
Check.OutputLength(output, outOff, outputLen, "Output buffer too short.");
|
||||
|
||||
CalculateMac(input, inOff, inLen, macBlock);
|
||||
|
||||
byte[] encMac = new byte[BlockSize];
|
||||
ctrCipher.ProcessBlock(macBlock, 0, encMac, 0); // S0
|
||||
|
||||
while (inIndex < (inOff + inLen - BlockSize)) // S1...
|
||||
{
|
||||
ctrCipher.ProcessBlock(input, inIndex, output, outIndex);
|
||||
outIndex += BlockSize;
|
||||
inIndex += BlockSize;
|
||||
}
|
||||
|
||||
byte[] block = new byte[BlockSize];
|
||||
|
||||
Array.Copy(input, inIndex, block, 0, inLen + inOff - inIndex);
|
||||
|
||||
ctrCipher.ProcessBlock(block, 0, block, 0);
|
||||
|
||||
Array.Copy(block, 0, output, outIndex, inLen + inOff - inIndex);
|
||||
|
||||
Array.Copy(encMac, 0, output, outOff + inLen, macSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inLen < macSize)
|
||||
throw new InvalidCipherTextException("data too short");
|
||||
|
||||
outputLen = inLen - macSize;
|
||||
Check.OutputLength(output, outOff, outputLen, "Output buffer too short.");
|
||||
|
||||
Array.Copy(input, inOff + outputLen, macBlock, 0, macSize);
|
||||
|
||||
ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0);
|
||||
|
||||
for (int i = macSize; i != macBlock.Length; i++)
|
||||
{
|
||||
macBlock[i] = 0;
|
||||
}
|
||||
|
||||
while (inIndex < (inOff + outputLen - BlockSize))
|
||||
{
|
||||
ctrCipher.ProcessBlock(input, inIndex, output, outIndex);
|
||||
outIndex += BlockSize;
|
||||
inIndex += BlockSize;
|
||||
}
|
||||
|
||||
byte[] block = new byte[BlockSize];
|
||||
|
||||
Array.Copy(input, inIndex, block, 0, outputLen - (inIndex - inOff));
|
||||
|
||||
ctrCipher.ProcessBlock(block, 0, block, 0);
|
||||
|
||||
Array.Copy(block, 0, output, outIndex, outputLen - (inIndex - inOff));
|
||||
|
||||
byte[] calculatedMacBlock = new byte[BlockSize];
|
||||
|
||||
CalculateMac(output, outOff, outputLen, calculatedMacBlock);
|
||||
|
||||
if (!Arrays.ConstantTimeAreEqual(macBlock, calculatedMacBlock))
|
||||
throw new InvalidCipherTextException("mac check in CCM failed");
|
||||
}
|
||||
|
||||
return outputLen;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int ProcessPacket(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
int inLen = input.Length;
|
||||
|
||||
// TODO: handle null keyParam (e.g. via RepeatedKeySpec)
|
||||
// Need to keep the CTR and CBC Mac parts around and reset
|
||||
if (keyParam == null)
|
||||
throw new InvalidOperationException("CCM cipher unitialized.");
|
||||
|
||||
int n = nonce.Length;
|
||||
int q = 15 - n;
|
||||
if (q < 4)
|
||||
{
|
||||
int limitLen = 1 << (8 * q);
|
||||
if (inLen >= limitLen)
|
||||
throw new InvalidOperationException("CCM packet too large for choice of q.");
|
||||
}
|
||||
|
||||
byte[] iv = new byte[BlockSize];
|
||||
iv[0] = (byte)((q - 1) & 0x7);
|
||||
nonce.CopyTo(iv, 1);
|
||||
|
||||
IBlockCipher ctrCipher = new SicBlockCipher(cipher);
|
||||
ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
|
||||
|
||||
int outputLen;
|
||||
int index = 0;
|
||||
Span<byte> block = stackalloc byte[BlockSize];
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
outputLen = inLen + macSize;
|
||||
Check.OutputLength(output, outputLen, "output buffer too short");
|
||||
|
||||
CalculateMac(input, macBlock);
|
||||
|
||||
byte[] encMac = new byte[BlockSize];
|
||||
ctrCipher.ProcessBlock(macBlock, encMac); // S0
|
||||
|
||||
while (index < (inLen - BlockSize)) // S1...
|
||||
{
|
||||
ctrCipher.ProcessBlock(input[index..], output[index..]);
|
||||
index += BlockSize;
|
||||
}
|
||||
|
||||
input[index..].CopyTo(block);
|
||||
|
||||
ctrCipher.ProcessBlock(block, block);
|
||||
|
||||
block[..(inLen - index)].CopyTo(output[index..]);
|
||||
|
||||
encMac.AsSpan(0, macSize).CopyTo(output[inLen..]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inLen < macSize)
|
||||
throw new InvalidCipherTextException("data too short");
|
||||
|
||||
outputLen = inLen - macSize;
|
||||
Check.OutputLength(output, outputLen, "output buffer too short");
|
||||
|
||||
input[outputLen..].CopyTo(macBlock);
|
||||
|
||||
ctrCipher.ProcessBlock(macBlock, macBlock);
|
||||
|
||||
for (int i = macSize; i != macBlock.Length; i++)
|
||||
{
|
||||
macBlock[i] = 0;
|
||||
}
|
||||
|
||||
while (index < (outputLen - BlockSize))
|
||||
{
|
||||
ctrCipher.ProcessBlock(input[index..], output[index..]);
|
||||
index += BlockSize;
|
||||
}
|
||||
|
||||
input[index..outputLen].CopyTo(block);
|
||||
|
||||
ctrCipher.ProcessBlock(block, block);
|
||||
|
||||
block[..(outputLen - index)].CopyTo(output[index..]);
|
||||
|
||||
Span<byte> calculatedMacBlock = stackalloc byte[BlockSize];
|
||||
|
||||
CalculateMac(output[..outputLen], calculatedMacBlock);
|
||||
|
||||
if (!Arrays.ConstantTimeAreEqual(macBlock, calculatedMacBlock))
|
||||
throw new InvalidCipherTextException("mac check in CCM failed");
|
||||
}
|
||||
|
||||
return outputLen;
|
||||
}
|
||||
#endif
|
||||
|
||||
private int CalculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
|
||||
{
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return CalculateMac(data.AsSpan(dataOff, dataLen), macBlock);
|
||||
#else
|
||||
IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8);
|
||||
|
||||
cMac.Init(keyParam);
|
||||
|
||||
//
|
||||
// build b0
|
||||
//
|
||||
byte[] b0 = new byte[16];
|
||||
|
||||
if (HasAssociatedText())
|
||||
{
|
||||
b0[0] |= 0x40;
|
||||
}
|
||||
|
||||
b0[0] |= (byte)((((cMac.GetMacSize() - 2) / 2) & 0x7) << 3);
|
||||
|
||||
b0[0] |= (byte)(((15 - nonce.Length) - 1) & 0x7);
|
||||
|
||||
Array.Copy(nonce, 0, b0, 1, nonce.Length);
|
||||
|
||||
int q = dataLen;
|
||||
int count = 1;
|
||||
while (q > 0)
|
||||
{
|
||||
b0[b0.Length - count] = (byte)(q & 0xff);
|
||||
q >>= 8;
|
||||
count++;
|
||||
}
|
||||
|
||||
cMac.BlockUpdate(b0, 0, b0.Length);
|
||||
|
||||
//
|
||||
// process associated text
|
||||
//
|
||||
if (HasAssociatedText())
|
||||
{
|
||||
int extra;
|
||||
|
||||
int textLength = GetAssociatedTextLength();
|
||||
if (textLength < ((1 << 16) - (1 << 8)))
|
||||
{
|
||||
cMac.Update((byte)(textLength >> 8));
|
||||
cMac.Update((byte)textLength);
|
||||
|
||||
extra = 2;
|
||||
}
|
||||
else // can't go any higher than 2^32
|
||||
{
|
||||
cMac.Update((byte)0xff);
|
||||
cMac.Update((byte)0xfe);
|
||||
cMac.Update((byte)(textLength >> 24));
|
||||
cMac.Update((byte)(textLength >> 16));
|
||||
cMac.Update((byte)(textLength >> 8));
|
||||
cMac.Update((byte)textLength);
|
||||
|
||||
extra = 6;
|
||||
}
|
||||
|
||||
if (initialAssociatedText != null)
|
||||
{
|
||||
cMac.BlockUpdate(initialAssociatedText, 0, initialAssociatedText.Length);
|
||||
}
|
||||
if (associatedText.Length > 0)
|
||||
{
|
||||
byte[] input = associatedText.GetBuffer();
|
||||
int len = Convert.ToInt32(associatedText.Length);
|
||||
|
||||
cMac.BlockUpdate(input, 0, len);
|
||||
}
|
||||
|
||||
extra = (extra + textLength) % 16;
|
||||
if (extra != 0)
|
||||
{
|
||||
for (int i = extra; i < 16; ++i)
|
||||
{
|
||||
cMac.Update((byte)0x00);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// add the text
|
||||
//
|
||||
cMac.BlockUpdate(data, dataOff, dataLen);
|
||||
|
||||
return cMac.DoFinal(macBlock, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
private int CalculateMac(ReadOnlySpan<byte> data, Span<byte> macBlock)
|
||||
{
|
||||
IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8);
|
||||
|
||||
cMac.Init(keyParam);
|
||||
|
||||
//
|
||||
// build b0
|
||||
//
|
||||
byte[] b0 = new byte[16];
|
||||
|
||||
if (HasAssociatedText())
|
||||
{
|
||||
b0[0] |= 0x40;
|
||||
}
|
||||
|
||||
b0[0] |= (byte)((((cMac.GetMacSize() - 2) / 2) & 0x7) << 3);
|
||||
|
||||
b0[0] |= (byte)(((15 - nonce.Length) - 1) & 0x7);
|
||||
|
||||
Array.Copy(nonce, 0, b0, 1, nonce.Length);
|
||||
|
||||
int q = data.Length;
|
||||
int count = 1;
|
||||
while (q > 0)
|
||||
{
|
||||
b0[b0.Length - count] = (byte)(q & 0xff);
|
||||
q >>= 8;
|
||||
count++;
|
||||
}
|
||||
|
||||
cMac.BlockUpdate(b0, 0, b0.Length);
|
||||
|
||||
//
|
||||
// process associated text
|
||||
//
|
||||
if (HasAssociatedText())
|
||||
{
|
||||
int extra;
|
||||
|
||||
int textLength = GetAssociatedTextLength();
|
||||
if (textLength < ((1 << 16) - (1 << 8)))
|
||||
{
|
||||
cMac.Update((byte)(textLength >> 8));
|
||||
cMac.Update((byte)textLength);
|
||||
|
||||
extra = 2;
|
||||
}
|
||||
else // can't go any higher than 2^32
|
||||
{
|
||||
cMac.Update((byte)0xff);
|
||||
cMac.Update((byte)0xfe);
|
||||
cMac.Update((byte)(textLength >> 24));
|
||||
cMac.Update((byte)(textLength >> 16));
|
||||
cMac.Update((byte)(textLength >> 8));
|
||||
cMac.Update((byte)textLength);
|
||||
|
||||
extra = 6;
|
||||
}
|
||||
|
||||
if (initialAssociatedText != null)
|
||||
{
|
||||
cMac.BlockUpdate(initialAssociatedText, 0, initialAssociatedText.Length);
|
||||
}
|
||||
if (associatedText.Length > 0)
|
||||
{
|
||||
byte[] input = associatedText.GetBuffer();
|
||||
int len = Convert.ToInt32(associatedText.Length);
|
||||
|
||||
cMac.BlockUpdate(input, 0, len);
|
||||
}
|
||||
|
||||
extra = (extra + textLength) % 16;
|
||||
if (extra != 0)
|
||||
{
|
||||
for (int i = extra; i < 16; ++i)
|
||||
{
|
||||
cMac.Update((byte)0x00);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// add the text
|
||||
//
|
||||
cMac.BlockUpdate(data);
|
||||
|
||||
return cMac.DoFinal(macBlock);
|
||||
}
|
||||
#endif
|
||||
|
||||
private int GetMacSize(bool forEncryption, int requestedMacBits)
|
||||
{
|
||||
if (forEncryption && (requestedMacBits < 32 || requestedMacBits > 128 || 0 != (requestedMacBits & 15)))
|
||||
throw new ArgumentException("tag length in octets must be one of {4,6,8,10,12,14,16}");
|
||||
|
||||
return requestedMacBits >> 3;
|
||||
}
|
||||
|
||||
private int GetAssociatedTextLength()
|
||||
{
|
||||
return Convert.ToInt32(associatedText.Length) +
|
||||
(initialAssociatedText == null ? 0 : initialAssociatedText.Length);
|
||||
}
|
||||
|
||||
private bool HasAssociatedText()
|
||||
{
|
||||
return GetAssociatedTextLength() > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CcmBlockCipher.cs.meta
vendored
Normal file
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CcmBlockCipher.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8187e045871283546af80d98e405ac4a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
230
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CfbBlockCipher.cs
vendored
Normal file
230
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CfbBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
|
||||
*/
|
||||
public class CfbBlockCipher
|
||||
: IBlockCipherMode
|
||||
{
|
||||
private byte[] IV;
|
||||
private byte[] cfbV;
|
||||
private byte[] cfbOutV;
|
||||
private bool encrypting;
|
||||
|
||||
private readonly int blockSize;
|
||||
private readonly IBlockCipher cipher;
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used as the basis of the
|
||||
* feedback mode.
|
||||
* @param blockSize the block size in bits (note: a multiple of 8)
|
||||
*/
|
||||
public CfbBlockCipher(
|
||||
IBlockCipher cipher,
|
||||
int bitBlockSize)
|
||||
{
|
||||
if (bitBlockSize < 8 || (bitBlockSize & 7) != 0)
|
||||
throw new ArgumentException("CFB" + bitBlockSize + " not supported", "bitBlockSize");
|
||||
|
||||
this.cipher = cipher;
|
||||
this.blockSize = bitBlockSize / 8;
|
||||
this.IV = new byte[cipher.GetBlockSize()];
|
||||
this.cfbV = new byte[cipher.GetBlockSize()];
|
||||
this.cfbOutV = new byte[cipher.GetBlockSize()];
|
||||
}
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public IBlockCipher UnderlyingCipher => cipher;
|
||||
|
||||
/**
|
||||
* Initialise the cipher and, possibly, the initialisation vector (IV).
|
||||
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
|
||||
* An IV which is too short is handled in FIPS compliant fashion.
|
||||
*
|
||||
* @param forEncryption if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param param the key and other data required by the cipher.
|
||||
* @exception ArgumentException if the parameters argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void Init(
|
||||
bool forEncryption,
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
this.encrypting = forEncryption;
|
||||
if (parameters is ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV ivParam = (ParametersWithIV) parameters;
|
||||
byte[] iv = ivParam.GetIV();
|
||||
int diff = IV.Length - iv.Length;
|
||||
Array.Copy(iv, 0, IV, diff, iv.Length);
|
||||
Array.Clear(IV, 0, diff);
|
||||
|
||||
parameters = ivParam.Parameters;
|
||||
}
|
||||
Reset();
|
||||
|
||||
// if it's null, key is to be reused.
|
||||
if (parameters != null)
|
||||
{
|
||||
cipher.Init(true, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the algorithm name and mode.
|
||||
*
|
||||
* @return the name of the underlying algorithm followed by "/CFB"
|
||||
* and the block size in bits.
|
||||
*/
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/CFB" + (blockSize * 8); }
|
||||
}
|
||||
|
||||
public bool IsPartialBlockOkay
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block size we are operating at.
|
||||
*
|
||||
* @return the block size we are operating at (in bytes).
|
||||
*/
|
||||
public int GetBlockSize()
|
||||
{
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
|
||||
{
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return encrypting
|
||||
? EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff))
|
||||
: DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
|
||||
#else
|
||||
return encrypting
|
||||
? EncryptBlock(input, inOff, output, outOff)
|
||||
: DecryptBlock(input, inOff, output, outOff);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
return encrypting
|
||||
? EncryptBlock(input, output)
|
||||
: DecryptBlock(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
Check.DataLength(input, blockSize, "input buffer too short");
|
||||
Check.OutputLength(output, blockSize, "output buffer too short");
|
||||
|
||||
cipher.ProcessBlock(cfbV, cfbOutV);
|
||||
//
|
||||
// XOR the cfbV with the plaintext producing the ciphertext
|
||||
//
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
output[i] = (byte)(cfbOutV[i] ^ input[i]);
|
||||
}
|
||||
//
|
||||
// change over the input block.
|
||||
//
|
||||
Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
|
||||
output[..blockSize].CopyTo(cfbV.AsSpan(cfbV.Length - blockSize));
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
Check.DataLength(input, blockSize, "input buffer too short");
|
||||
Check.OutputLength(output, blockSize, "output buffer too short");
|
||||
|
||||
cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
|
||||
//
|
||||
// change over the input block.
|
||||
//
|
||||
Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
|
||||
input[..blockSize].CopyTo(cfbV.AsSpan(cfbV.Length - blockSize));
|
||||
//
|
||||
// XOR the cfbV with the ciphertext producing the plaintext
|
||||
//
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
output[i] = (byte)(cfbOutV[i] ^ input[i]);
|
||||
}
|
||||
return blockSize;
|
||||
}
|
||||
#else
|
||||
private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
|
||||
{
|
||||
Check.DataLength(input, inOff, blockSize, "input buffer too short");
|
||||
Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
|
||||
|
||||
cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
|
||||
//
|
||||
// XOR the cfbV with the plaintext producing the ciphertext
|
||||
//
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
|
||||
}
|
||||
//
|
||||
// change over the input block.
|
||||
//
|
||||
Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
|
||||
Array.Copy(outBytes, outOff, cfbV, cfbV.Length - blockSize, blockSize);
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
|
||||
{
|
||||
Check.DataLength(input, inOff, blockSize, "input buffer too short");
|
||||
Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
|
||||
|
||||
cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
|
||||
//
|
||||
// change over the input block.
|
||||
//
|
||||
Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
|
||||
Array.Copy(input, inOff, cfbV, cfbV.Length - blockSize, blockSize);
|
||||
//
|
||||
// XOR the cfbV with the ciphertext producing the plaintext
|
||||
//
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
|
||||
}
|
||||
return blockSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* reset the chaining vector back to the IV and reset the underlying
|
||||
* cipher.
|
||||
*/
|
||||
public void Reset()
|
||||
{
|
||||
Array.Copy(IV, 0, cfbV, 0, IV.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CfbBlockCipher.cs.meta
vendored
Normal file
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CfbBlockCipher.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8bbdd28dbb8de4d458aa27f9def26c73
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
905
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/ChaCha20Poly1305.cs
vendored
Normal file
905
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/ChaCha20Poly1305.cs
vendored
Normal file
@@ -0,0 +1,905 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
public class ChaCha20Poly1305
|
||||
: IAeadCipher
|
||||
{
|
||||
private enum State
|
||||
{
|
||||
Uninitialized = 0,
|
||||
EncInit = 1,
|
||||
EncAad = 2,
|
||||
EncData = 3,
|
||||
EncFinal = 4,
|
||||
DecInit = 5,
|
||||
DecAad = 6,
|
||||
DecData = 7,
|
||||
DecFinal = 8,
|
||||
}
|
||||
|
||||
private const int BufSize = 64;
|
||||
private const int KeySize = 32;
|
||||
private const int NonceSize = 12;
|
||||
private const int MacSize = 16;
|
||||
private static readonly byte[] Zeroes = new byte[MacSize - 1];
|
||||
|
||||
private const ulong AadLimit = ulong.MaxValue;
|
||||
private const ulong DataLimit = ((1UL << 32) - 1) * 64;
|
||||
|
||||
private readonly ChaCha7539Engine mChacha20;
|
||||
private readonly IMac mPoly1305;
|
||||
|
||||
private readonly byte[] mKey = new byte[KeySize];
|
||||
private readonly byte[] mNonce = new byte[NonceSize];
|
||||
private readonly byte[] mBuf = new byte[BufSize + MacSize];
|
||||
private readonly byte[] mMac = new byte[MacSize];
|
||||
|
||||
private byte[] mInitialAad;
|
||||
|
||||
private ulong mAadCount;
|
||||
private ulong mDataCount;
|
||||
private State mState = State.Uninitialized;
|
||||
private int mBufPos;
|
||||
|
||||
public ChaCha20Poly1305()
|
||||
: this(new Poly1305())
|
||||
{
|
||||
}
|
||||
|
||||
public ChaCha20Poly1305(IMac poly1305)
|
||||
{
|
||||
if (null == poly1305)
|
||||
throw new ArgumentNullException("poly1305");
|
||||
if (MacSize != poly1305.GetMacSize())
|
||||
throw new ArgumentException("must be a 128-bit MAC", "poly1305");
|
||||
|
||||
this.mChacha20 = new ChaCha7539Engine();
|
||||
this.mPoly1305 = poly1305;
|
||||
}
|
||||
|
||||
public virtual string AlgorithmName
|
||||
{
|
||||
get { return "ChaCha20Poly1305"; }
|
||||
}
|
||||
|
||||
public virtual void Init(bool forEncryption, ICipherParameters parameters)
|
||||
{
|
||||
KeyParameter initKeyParam;
|
||||
byte[] initNonce;
|
||||
ICipherParameters chacha20Params;
|
||||
|
||||
if (parameters is AeadParameters)
|
||||
{
|
||||
AeadParameters aeadParams = (AeadParameters)parameters;
|
||||
|
||||
int macSizeBits = aeadParams.MacSize;
|
||||
if ((MacSize * 8) != macSizeBits)
|
||||
throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
|
||||
|
||||
initKeyParam = aeadParams.Key;
|
||||
initNonce = aeadParams.GetNonce();
|
||||
chacha20Params = new ParametersWithIV(initKeyParam, initNonce);
|
||||
|
||||
this.mInitialAad = aeadParams.GetAssociatedText();
|
||||
}
|
||||
else if (parameters is ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV ivParams = (ParametersWithIV)parameters;
|
||||
|
||||
initKeyParam = (KeyParameter)ivParams.Parameters;
|
||||
initNonce = ivParams.GetIV();
|
||||
chacha20Params = ivParams;
|
||||
|
||||
this.mInitialAad = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("invalid parameters passed to ChaCha20Poly1305", "parameters");
|
||||
}
|
||||
|
||||
// Validate key
|
||||
if (null == initKeyParam)
|
||||
{
|
||||
if (State.Uninitialized == mState)
|
||||
throw new ArgumentException("Key must be specified in initial init");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (KeySize != initKeyParam.GetKey().Length)
|
||||
throw new ArgumentException("Key must be 256 bits");
|
||||
}
|
||||
|
||||
// Validate nonce
|
||||
if (null == initNonce || NonceSize != initNonce.Length)
|
||||
throw new ArgumentException("Nonce must be 96 bits");
|
||||
|
||||
// Check for encryption with reused nonce
|
||||
if (State.Uninitialized != mState && forEncryption && Arrays.AreEqual(mNonce, initNonce))
|
||||
{
|
||||
if (null == initKeyParam || Arrays.AreEqual(mKey, initKeyParam.GetKey()))
|
||||
throw new ArgumentException("cannot reuse nonce for ChaCha20Poly1305 encryption");
|
||||
}
|
||||
|
||||
if (null != initKeyParam)
|
||||
{
|
||||
Array.Copy(initKeyParam.GetKey(), 0, mKey, 0, KeySize);
|
||||
}
|
||||
|
||||
Array.Copy(initNonce, 0, mNonce, 0, NonceSize);
|
||||
|
||||
mChacha20.Init(true, chacha20Params);
|
||||
|
||||
this.mState = forEncryption ? State.EncInit : State.DecInit;
|
||||
|
||||
Reset(true, false);
|
||||
}
|
||||
|
||||
public virtual int GetOutputSize(int len)
|
||||
{
|
||||
int total = System.Math.Max(0, len) + mBufPos;
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case State.DecInit:
|
||||
case State.DecAad:
|
||||
case State.DecData:
|
||||
return System.Math.Max(0, total - MacSize);
|
||||
case State.EncInit:
|
||||
case State.EncAad:
|
||||
case State.EncData:
|
||||
return total + MacSize;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual int GetUpdateOutputSize(int len)
|
||||
{
|
||||
int total = System.Math.Max(0, len) + mBufPos;
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case State.DecInit:
|
||||
case State.DecAad:
|
||||
case State.DecData:
|
||||
total = System.Math.Max(0, total - MacSize);
|
||||
break;
|
||||
case State.EncInit:
|
||||
case State.EncAad:
|
||||
case State.EncData:
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return total - (total % BufSize);
|
||||
}
|
||||
|
||||
public virtual void ProcessAadByte(byte input)
|
||||
{
|
||||
CheckAad();
|
||||
|
||||
this.mAadCount = IncrementCount(mAadCount, 1, AadLimit);
|
||||
mPoly1305.Update(input);
|
||||
}
|
||||
|
||||
public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
|
||||
{
|
||||
if (null == inBytes)
|
||||
throw new ArgumentNullException("inBytes");
|
||||
if (inOff < 0)
|
||||
throw new ArgumentException("cannot be negative", "inOff");
|
||||
if (len < 0)
|
||||
throw new ArgumentException("cannot be negative", "len");
|
||||
Check.DataLength(inBytes, inOff, len, "input buffer too short");
|
||||
|
||||
CheckAad();
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
this.mAadCount = IncrementCount(mAadCount, (uint)len, AadLimit);
|
||||
mPoly1305.BlockUpdate(inBytes, inOff, len);
|
||||
}
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
|
||||
{
|
||||
CheckAad();
|
||||
|
||||
if (!input.IsEmpty)
|
||||
{
|
||||
this.mAadCount = IncrementCount(mAadCount, (uint)input.Length, AadLimit);
|
||||
mPoly1305.BlockUpdate(input);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual int ProcessByte(byte input, byte[] outBytes, int outOff)
|
||||
{
|
||||
CheckData();
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case State.DecData:
|
||||
{
|
||||
mBuf[mBufPos] = input;
|
||||
if (++mBufPos == mBuf.Length)
|
||||
{
|
||||
mPoly1305.BlockUpdate(mBuf, 0, BufSize);
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
ProcessBlock(mBuf, outBytes.AsSpan(outOff));
|
||||
#else
|
||||
ProcessBlock(mBuf, 0, outBytes, outOff);
|
||||
#endif
|
||||
Array.Copy(mBuf, BufSize, mBuf, 0, MacSize);
|
||||
this.mBufPos = MacSize;
|
||||
return BufSize;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
case State.EncData:
|
||||
{
|
||||
mBuf[mBufPos] = input;
|
||||
if (++mBufPos == BufSize)
|
||||
{
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
ProcessBlock(mBuf, outBytes.AsSpan(outOff));
|
||||
#else
|
||||
ProcessBlock(mBuf, 0, outBytes, outOff);
|
||||
#endif
|
||||
mPoly1305.BlockUpdate(outBytes, outOff, BufSize);
|
||||
this.mBufPos = 0;
|
||||
return BufSize;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int ProcessByte(byte input, Span<byte> output)
|
||||
{
|
||||
CheckData();
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case State.DecData:
|
||||
{
|
||||
mBuf[mBufPos] = input;
|
||||
if (++mBufPos == mBuf.Length)
|
||||
{
|
||||
mPoly1305.BlockUpdate(mBuf.AsSpan(0, BufSize));
|
||||
ProcessBlock(mBuf, output);
|
||||
Array.Copy(mBuf, BufSize, mBuf, 0, MacSize);
|
||||
this.mBufPos = MacSize;
|
||||
return BufSize;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
case State.EncData:
|
||||
{
|
||||
mBuf[mBufPos] = input;
|
||||
if (++mBufPos == BufSize)
|
||||
{
|
||||
ProcessBlock(mBuf, output);
|
||||
mPoly1305.BlockUpdate(output[..BufSize]);
|
||||
this.mBufPos = 0;
|
||||
return BufSize;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff)
|
||||
{
|
||||
if (null == inBytes)
|
||||
throw new ArgumentNullException("inBytes");
|
||||
/*
|
||||
* Following bc-java, we allow null when no output is expected (e.g. based on a
|
||||
* GetUpdateOutputSize call).
|
||||
*/
|
||||
if (null == outBytes)
|
||||
{
|
||||
//throw new ArgumentNullException("outBytes");
|
||||
}
|
||||
if (inOff < 0)
|
||||
throw new ArgumentException("cannot be negative", "inOff");
|
||||
if (len < 0)
|
||||
throw new ArgumentException("cannot be negative", "len");
|
||||
Check.DataLength(inBytes, inOff, len, "input buffer too short");
|
||||
if (outOff < 0)
|
||||
throw new ArgumentException("cannot be negative", "outOff");
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return ProcessBytes(inBytes.AsSpan(inOff, len), Spans.FromNullable(outBytes, outOff));
|
||||
#else
|
||||
CheckData();
|
||||
|
||||
int resultLen = 0;
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case State.DecData:
|
||||
{
|
||||
int available = mBuf.Length - mBufPos;
|
||||
if (len < available)
|
||||
{
|
||||
Array.Copy(inBytes, inOff, mBuf, mBufPos, len);
|
||||
mBufPos += len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mBufPos >= BufSize)
|
||||
{
|
||||
mPoly1305.BlockUpdate(mBuf, 0, BufSize);
|
||||
ProcessBlock(mBuf, 0, outBytes, outOff);
|
||||
Array.Copy(mBuf, BufSize, mBuf, 0, mBufPos -= BufSize);
|
||||
resultLen = BufSize;
|
||||
|
||||
available += BufSize;
|
||||
if (len < available)
|
||||
{
|
||||
Array.Copy(inBytes, inOff, mBuf, mBufPos, len);
|
||||
mBufPos += len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int inLimit1 = inOff + len - mBuf.Length;
|
||||
int inLimit2 = inLimit1 - BufSize;
|
||||
|
||||
available = BufSize - mBufPos;
|
||||
Array.Copy(inBytes, inOff, mBuf, mBufPos, available);
|
||||
mPoly1305.BlockUpdate(mBuf, 0, BufSize);
|
||||
ProcessBlock(mBuf, 0, outBytes, outOff + resultLen);
|
||||
inOff += available;
|
||||
resultLen += BufSize;
|
||||
|
||||
while (inOff <= inLimit2)
|
||||
{
|
||||
mPoly1305.BlockUpdate(inBytes, inOff, BufSize * 2);
|
||||
ProcessBlocks2(inBytes, inOff, outBytes, outOff + resultLen);
|
||||
inOff += BufSize * 2;
|
||||
resultLen += BufSize * 2;
|
||||
}
|
||||
|
||||
if (inOff <= inLimit1)
|
||||
{
|
||||
mPoly1305.BlockUpdate(inBytes, inOff, BufSize);
|
||||
ProcessBlock(inBytes, inOff, outBytes, outOff + resultLen);
|
||||
inOff += BufSize;
|
||||
resultLen += BufSize;
|
||||
}
|
||||
|
||||
mBufPos = mBuf.Length + inLimit1 - inOff;
|
||||
Array.Copy(inBytes, inOff, mBuf, 0, mBufPos);
|
||||
break;
|
||||
}
|
||||
case State.EncData:
|
||||
{
|
||||
int available = BufSize - mBufPos;
|
||||
if (len < available)
|
||||
{
|
||||
Array.Copy(inBytes, inOff, mBuf, mBufPos, len);
|
||||
mBufPos += len;
|
||||
break;
|
||||
}
|
||||
|
||||
int inLimit1 = inOff + len - BufSize;
|
||||
int inLimit2 = inLimit1 - BufSize;
|
||||
|
||||
if (mBufPos > 0)
|
||||
{
|
||||
Array.Copy(inBytes, inOff, mBuf, mBufPos, available);
|
||||
ProcessBlock(mBuf, 0, outBytes, outOff);
|
||||
inOff += available;
|
||||
resultLen = BufSize;
|
||||
}
|
||||
|
||||
while (inOff <= inLimit2)
|
||||
{
|
||||
ProcessBlocks2(inBytes, inOff, outBytes, outOff + resultLen);
|
||||
inOff += BufSize * 2;
|
||||
resultLen += BufSize * 2;
|
||||
}
|
||||
|
||||
if (inOff <= inLimit1)
|
||||
{
|
||||
ProcessBlock(inBytes, inOff, outBytes, outOff + resultLen);
|
||||
inOff += BufSize;
|
||||
resultLen += BufSize;
|
||||
}
|
||||
|
||||
mPoly1305.BlockUpdate(outBytes, outOff, resultLen);
|
||||
|
||||
mBufPos = BufSize + inLimit1 - inOff;
|
||||
Array.Copy(inBytes, inOff, mBuf, 0, mBufPos);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return resultLen;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
CheckData();
|
||||
|
||||
int resultLen = 0;
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case State.DecData:
|
||||
{
|
||||
int available = mBuf.Length - mBufPos;
|
||||
if (input.Length < available)
|
||||
{
|
||||
input.CopyTo(mBuf.AsSpan(mBufPos));
|
||||
mBufPos += input.Length;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mBufPos >= BufSize)
|
||||
{
|
||||
mPoly1305.BlockUpdate(mBuf.AsSpan(0, BufSize));
|
||||
ProcessBlock(mBuf, output);
|
||||
Array.Copy(mBuf, BufSize, mBuf, 0, mBufPos -= BufSize);
|
||||
resultLen = BufSize;
|
||||
|
||||
available += BufSize;
|
||||
if (input.Length < available)
|
||||
{
|
||||
input.CopyTo(mBuf.AsSpan(mBufPos));
|
||||
mBufPos += input.Length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int inLimit1 = mBuf.Length;
|
||||
int inLimit2 = inLimit1 + BufSize;
|
||||
|
||||
available = BufSize - mBufPos;
|
||||
input[..available].CopyTo(mBuf.AsSpan(mBufPos));
|
||||
mPoly1305.BlockUpdate(mBuf.AsSpan(0, BufSize));
|
||||
ProcessBlock(mBuf, output[resultLen..]);
|
||||
input = input[available..];
|
||||
resultLen += BufSize;
|
||||
|
||||
while (input.Length >= inLimit2)
|
||||
{
|
||||
mPoly1305.BlockUpdate(input[..(BufSize * 2)]);
|
||||
ProcessBlocks2(input, output[resultLen..]);
|
||||
input = input[(BufSize * 2)..];
|
||||
resultLen += BufSize * 2;
|
||||
}
|
||||
|
||||
if (input.Length >= inLimit1)
|
||||
{
|
||||
mPoly1305.BlockUpdate(input[..BufSize]);
|
||||
ProcessBlock(input, output[resultLen..]);
|
||||
input = input[BufSize..];
|
||||
resultLen += BufSize;
|
||||
}
|
||||
|
||||
mBufPos = input.Length;
|
||||
input.CopyTo(mBuf);
|
||||
break;
|
||||
}
|
||||
case State.EncData:
|
||||
{
|
||||
int available = BufSize - mBufPos;
|
||||
if (input.Length < available)
|
||||
{
|
||||
input.CopyTo(mBuf.AsSpan(mBufPos));
|
||||
mBufPos += input.Length;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mBufPos > 0)
|
||||
{
|
||||
input[..available].CopyTo(mBuf.AsSpan(mBufPos));
|
||||
ProcessBlock(mBuf, output);
|
||||
input = input[available..];
|
||||
resultLen = BufSize;
|
||||
}
|
||||
|
||||
while (input.Length >= BufSize * 2)
|
||||
{
|
||||
ProcessBlocks2(input, output[resultLen..]);
|
||||
input = input[(BufSize * 2)..];
|
||||
resultLen += BufSize * 2;
|
||||
}
|
||||
|
||||
if (input.Length >= BufSize)
|
||||
{
|
||||
ProcessBlock(input, output[resultLen..]);
|
||||
input = input[BufSize..];
|
||||
resultLen += BufSize;
|
||||
}
|
||||
|
||||
mPoly1305.BlockUpdate(output[..resultLen]);
|
||||
|
||||
mBufPos = input.Length;
|
||||
input.CopyTo(mBuf);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual int DoFinal(byte[] outBytes, int outOff)
|
||||
{
|
||||
if (null == outBytes)
|
||||
throw new ArgumentNullException("outBytes");
|
||||
if (outOff < 0)
|
||||
throw new ArgumentException("cannot be negative", "outOff");
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return DoFinal(outBytes.AsSpan(outOff));
|
||||
#else
|
||||
CheckData();
|
||||
|
||||
Array.Clear(mMac, 0, MacSize);
|
||||
|
||||
int resultLen = 0;
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case State.DecData:
|
||||
{
|
||||
if (mBufPos < MacSize)
|
||||
throw new InvalidCipherTextException("data too short");
|
||||
|
||||
resultLen = mBufPos - MacSize;
|
||||
|
||||
Check.OutputLength(outBytes, outOff, resultLen, "output buffer too short");
|
||||
|
||||
if (resultLen > 0)
|
||||
{
|
||||
mPoly1305.BlockUpdate(mBuf, 0, resultLen);
|
||||
ProcessData(mBuf, 0, resultLen, outBytes, outOff);
|
||||
}
|
||||
|
||||
FinishData(State.DecFinal);
|
||||
|
||||
if (!Arrays.ConstantTimeAreEqual(MacSize, mMac, 0, mBuf, resultLen))
|
||||
throw new InvalidCipherTextException("mac check in ChaCha20Poly1305 failed");
|
||||
|
||||
break;
|
||||
}
|
||||
case State.EncData:
|
||||
{
|
||||
resultLen = mBufPos + MacSize;
|
||||
|
||||
Check.OutputLength(outBytes, outOff, resultLen, "output buffer too short");
|
||||
|
||||
if (mBufPos > 0)
|
||||
{
|
||||
ProcessData(mBuf, 0, mBufPos, outBytes, outOff);
|
||||
mPoly1305.BlockUpdate(outBytes, outOff, mBufPos);
|
||||
}
|
||||
|
||||
FinishData(State.EncFinal);
|
||||
|
||||
Array.Copy(mMac, 0, outBytes, outOff + mBufPos, MacSize);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Reset(false, true);
|
||||
|
||||
return resultLen;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int DoFinal(Span<byte> output)
|
||||
{
|
||||
CheckData();
|
||||
|
||||
Array.Clear(mMac, 0, MacSize);
|
||||
|
||||
int resultLen = 0;
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case State.DecData:
|
||||
{
|
||||
if (mBufPos < MacSize)
|
||||
throw new InvalidCipherTextException("data too short");
|
||||
|
||||
resultLen = mBufPos - MacSize;
|
||||
|
||||
Check.OutputLength(output, resultLen, "output buffer too short");
|
||||
|
||||
if (resultLen > 0)
|
||||
{
|
||||
mPoly1305.BlockUpdate(mBuf, 0, resultLen);
|
||||
ProcessData(mBuf.AsSpan(0, resultLen), output);
|
||||
}
|
||||
|
||||
FinishData(State.DecFinal);
|
||||
|
||||
if (!Arrays.ConstantTimeAreEqual(MacSize, mMac, 0, mBuf, resultLen))
|
||||
throw new InvalidCipherTextException("mac check in ChaCha20Poly1305 failed");
|
||||
|
||||
break;
|
||||
}
|
||||
case State.EncData:
|
||||
{
|
||||
resultLen = mBufPos + MacSize;
|
||||
|
||||
Check.OutputLength(output, resultLen, "output buffer too short");
|
||||
|
||||
if (mBufPos > 0)
|
||||
{
|
||||
ProcessData(mBuf.AsSpan(0, mBufPos), output);
|
||||
mPoly1305.BlockUpdate(output[..mBufPos]);
|
||||
}
|
||||
|
||||
FinishData(State.EncFinal);
|
||||
|
||||
mMac.AsSpan(0, MacSize).CopyTo(output[mBufPos..]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Reset(false, true);
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual byte[] GetMac()
|
||||
{
|
||||
return Arrays.Clone(mMac);
|
||||
}
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
Reset(true, true);
|
||||
}
|
||||
|
||||
private void CheckAad()
|
||||
{
|
||||
switch (mState)
|
||||
{
|
||||
case State.DecInit:
|
||||
this.mState = State.DecAad;
|
||||
break;
|
||||
case State.EncInit:
|
||||
this.mState = State.EncAad;
|
||||
break;
|
||||
case State.DecAad:
|
||||
case State.EncAad:
|
||||
break;
|
||||
case State.EncFinal:
|
||||
throw new InvalidOperationException("ChaCha20Poly1305 cannot be reused for encryption");
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckData()
|
||||
{
|
||||
switch (mState)
|
||||
{
|
||||
case State.DecInit:
|
||||
case State.DecAad:
|
||||
FinishAad(State.DecData);
|
||||
break;
|
||||
case State.EncInit:
|
||||
case State.EncAad:
|
||||
FinishAad(State.EncData);
|
||||
break;
|
||||
case State.DecData:
|
||||
case State.EncData:
|
||||
break;
|
||||
case State.EncFinal:
|
||||
throw new InvalidOperationException("ChaCha20Poly1305 cannot be reused for encryption");
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private void FinishAad(State nextState)
|
||||
{
|
||||
PadMac(mAadCount);
|
||||
|
||||
this.mState = nextState;
|
||||
}
|
||||
|
||||
private void FinishData(State nextState)
|
||||
{
|
||||
PadMac(mDataCount);
|
||||
|
||||
byte[] lengths = new byte[16];
|
||||
Pack.UInt64_To_LE(mAadCount, lengths, 0);
|
||||
Pack.UInt64_To_LE(mDataCount, lengths, 8);
|
||||
mPoly1305.BlockUpdate(lengths, 0, 16);
|
||||
|
||||
mPoly1305.DoFinal(mMac, 0);
|
||||
|
||||
this.mState = nextState;
|
||||
}
|
||||
|
||||
private ulong IncrementCount(ulong count, uint increment, ulong limit)
|
||||
{
|
||||
if (count > (limit - increment))
|
||||
throw new InvalidOperationException ("Limit exceeded");
|
||||
|
||||
return count + increment;
|
||||
}
|
||||
|
||||
private void InitMac()
|
||||
{
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
Span<byte> firstBlock = stackalloc byte[64];
|
||||
try
|
||||
{
|
||||
mChacha20.ProcessBytes(firstBlock, firstBlock);
|
||||
mPoly1305.Init(new KeyParameter(firstBlock[..32]));
|
||||
}
|
||||
finally
|
||||
{
|
||||
firstBlock.Fill(0x00);
|
||||
}
|
||||
#else
|
||||
byte[] firstBlock = new byte[64];
|
||||
try
|
||||
{
|
||||
mChacha20.ProcessBytes(firstBlock, 0, 64, firstBlock, 0);
|
||||
mPoly1305.Init(new KeyParameter(firstBlock, 0, 32));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Array.Clear(firstBlock, 0, 64);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private void PadMac(ulong count)
|
||||
{
|
||||
int partial = (int)count & (MacSize - 1);
|
||||
if (0 != partial)
|
||||
{
|
||||
mPoly1305.BlockUpdate(Zeroes, 0, MacSize - partial);
|
||||
}
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
private void ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
Check.OutputLength(output, 64, "output buffer too short");
|
||||
|
||||
mChacha20.ProcessBlock(input, output);
|
||||
|
||||
this.mDataCount = IncrementCount(mDataCount, 64U, DataLimit);
|
||||
}
|
||||
|
||||
private void ProcessBlocks2(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
Check.OutputLength(output, 128, "output buffer too short");
|
||||
|
||||
mChacha20.ProcessBlocks2(input, output);
|
||||
|
||||
this.mDataCount = IncrementCount(mDataCount, 128U, DataLimit);
|
||||
}
|
||||
|
||||
private void ProcessData(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
Check.OutputLength(output, input.Length, "output buffer too short");
|
||||
|
||||
mChacha20.ProcessBytes(input, output);
|
||||
|
||||
this.mDataCount = IncrementCount(mDataCount, (uint)input.Length, DataLimit);
|
||||
}
|
||||
#else
|
||||
private void ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
|
||||
{
|
||||
Check.OutputLength(outBytes, outOff, 64, "output buffer too short");
|
||||
|
||||
mChacha20.ProcessBlock(inBytes, inOff, outBytes, outOff);
|
||||
|
||||
this.mDataCount = IncrementCount(mDataCount, 64U, DataLimit);
|
||||
}
|
||||
|
||||
private void ProcessBlocks2(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
|
||||
{
|
||||
Check.OutputLength(outBytes, outOff, 128, "output buffer too short");
|
||||
|
||||
mChacha20.ProcessBlocks2(inBytes, inOff, outBytes, outOff);
|
||||
|
||||
this.mDataCount = IncrementCount(mDataCount, 128U, DataLimit);
|
||||
}
|
||||
|
||||
private void ProcessData(byte[] inBytes, int inOff, int inLen, byte[] outBytes, int outOff)
|
||||
{
|
||||
Check.OutputLength(outBytes, outOff, inLen, "output buffer too short");
|
||||
|
||||
mChacha20.ProcessBytes(inBytes, inOff, inLen, outBytes, outOff);
|
||||
|
||||
this.mDataCount = IncrementCount(mDataCount, (uint)inLen, DataLimit);
|
||||
}
|
||||
#endif
|
||||
|
||||
private void Reset(bool clearMac, bool resetCipher)
|
||||
{
|
||||
Array.Clear(mBuf, 0, mBuf.Length);
|
||||
|
||||
if (clearMac)
|
||||
{
|
||||
Array.Clear(mMac, 0, mMac.Length);
|
||||
}
|
||||
|
||||
this.mAadCount = 0UL;
|
||||
this.mDataCount = 0UL;
|
||||
this.mBufPos = 0;
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case State.DecInit:
|
||||
case State.EncInit:
|
||||
break;
|
||||
case State.DecAad:
|
||||
case State.DecData:
|
||||
case State.DecFinal:
|
||||
this.mState = State.DecInit;
|
||||
break;
|
||||
case State.EncAad:
|
||||
case State.EncData:
|
||||
case State.EncFinal:
|
||||
this.mState = State.EncFinal;
|
||||
return;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (resetCipher)
|
||||
{
|
||||
mChacha20.Reset();
|
||||
}
|
||||
|
||||
InitMac();
|
||||
|
||||
if (null != mInitialAad)
|
||||
{
|
||||
ProcessAadBytes(mInitialAad, 0, mInitialAad.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2cd8d80304a90214292a351a3fe3e2b2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
353
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CtsBlockCipher.cs
vendored
Normal file
353
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CtsBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,353 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to
|
||||
* be used to produce cipher text which is the same outLength as the plain text.
|
||||
*/
|
||||
public class CtsBlockCipher
|
||||
: BufferedBlockCipher
|
||||
{
|
||||
private readonly int blockSize;
|
||||
|
||||
public CtsBlockCipher(IBlockCipher cipher)
|
||||
: this(EcbBlockCipher.GetBlockCipherMode(cipher))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a buffered block cipher that uses Cipher Text Stealing
|
||||
*
|
||||
* @param cipher the underlying block cipher this buffering object wraps.
|
||||
*/
|
||||
public CtsBlockCipher(IBlockCipherMode cipherMode)
|
||||
{
|
||||
if (!(cipherMode is CbcBlockCipher || cipherMode is EcbBlockCipher))
|
||||
throw new ArgumentException("CtsBlockCipher can only accept ECB, or CBC ciphers");
|
||||
|
||||
m_cipherMode = cipherMode;
|
||||
|
||||
blockSize = cipherMode.GetBlockSize();
|
||||
|
||||
buf = new byte[blockSize * 2];
|
||||
bufOff = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the size of the output buffer required for an update of 'length' bytes.
|
||||
*
|
||||
* @param length the outLength of the input.
|
||||
* @return the space required to accommodate a call to update
|
||||
* with length bytes of input.
|
||||
*/
|
||||
public override int GetUpdateOutputSize(
|
||||
int length)
|
||||
{
|
||||
int total = length + bufOff;
|
||||
int leftOver = total % buf.Length;
|
||||
|
||||
if (leftOver == 0)
|
||||
{
|
||||
return total - buf.Length;
|
||||
}
|
||||
|
||||
return total - leftOver;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the size of the output buffer required for an update plus a
|
||||
* doFinal with an input of length bytes.
|
||||
*
|
||||
* @param length the outLength of the input.
|
||||
* @return the space required to accommodate a call to update and doFinal
|
||||
* with length bytes of input.
|
||||
*/
|
||||
public override int GetOutputSize(
|
||||
int length)
|
||||
{
|
||||
return length + bufOff;
|
||||
}
|
||||
|
||||
/**
|
||||
* process a single byte, producing an output block if necessary.
|
||||
*
|
||||
* @param in the input byte.
|
||||
* @param out the space for any output that might be produced.
|
||||
* @param outOff the offset from which the output will be copied.
|
||||
* @return the number of output bytes copied to out.
|
||||
* @exception DataLengthException if there isn't enough space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
*/
|
||||
public override int ProcessByte(byte input, byte[] output, int outOff)
|
||||
{
|
||||
int resultLen = 0;
|
||||
|
||||
if (bufOff == buf.Length)
|
||||
{
|
||||
resultLen = m_cipherMode.ProcessBlock(buf, 0, output, outOff);
|
||||
Debug.Assert(resultLen == blockSize);
|
||||
|
||||
Array.Copy(buf, blockSize, buf, 0, blockSize);
|
||||
bufOff = blockSize;
|
||||
}
|
||||
|
||||
buf[bufOff++] = input;
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public override int ProcessByte(byte input, Span<byte> output)
|
||||
{
|
||||
int resultLen = 0;
|
||||
|
||||
if (bufOff == buf.Length)
|
||||
{
|
||||
resultLen = m_cipherMode.ProcessBlock(buf, output);
|
||||
Debug.Assert(resultLen == blockSize);
|
||||
|
||||
Array.Copy(buf, blockSize, buf, 0, blockSize);
|
||||
bufOff = blockSize;
|
||||
}
|
||||
|
||||
buf[bufOff++] = input;
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* process an array of bytes, producing output if necessary.
|
||||
*
|
||||
* @param in the input byte array.
|
||||
* @param inOff the offset at which the input data starts.
|
||||
* @param length the number of bytes to be copied out of the input array.
|
||||
* @param out the space for any output that might be produced.
|
||||
* @param outOff the offset from which the output will be copied.
|
||||
* @return the number of output bytes copied to out.
|
||||
* @exception DataLengthException if there isn't enough space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
*/
|
||||
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 length!");
|
||||
|
||||
int blockSize = GetBlockSize();
|
||||
int outLength = GetUpdateOutputSize(length);
|
||||
|
||||
if (outLength > 0)
|
||||
{
|
||||
Check.OutputLength(output, outOff, outLength, "output buffer too short");
|
||||
}
|
||||
|
||||
int resultLen = 0;
|
||||
int gapLen = buf.Length - bufOff;
|
||||
|
||||
if (length > gapLen)
|
||||
{
|
||||
Array.Copy(input, inOff, buf, bufOff, gapLen);
|
||||
|
||||
resultLen = m_cipherMode.ProcessBlock(buf, 0, output, outOff);
|
||||
Array.Copy(buf, blockSize, buf, 0, blockSize);
|
||||
|
||||
bufOff = blockSize;
|
||||
|
||||
length -= gapLen;
|
||||
inOff += gapLen;
|
||||
|
||||
while (length > blockSize)
|
||||
{
|
||||
Array.Copy(input, inOff, buf, bufOff, blockSize);
|
||||
resultLen += m_cipherMode.ProcessBlock(buf, 0, output, outOff + resultLen);
|
||||
Array.Copy(buf, blockSize, buf, 0, blockSize);
|
||||
|
||||
length -= blockSize;
|
||||
inOff += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
Array.Copy(input, inOff, buf, bufOff, length);
|
||||
|
||||
bufOff += length;
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public override int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
int blockSize = GetBlockSize();
|
||||
int outLength = GetUpdateOutputSize(input.Length);
|
||||
|
||||
if (outLength > 0)
|
||||
{
|
||||
Check.OutputLength(output, outLength, "output buffer too short");
|
||||
}
|
||||
|
||||
int resultLen = 0;
|
||||
int gapLen = buf.Length - bufOff;
|
||||
|
||||
if (input.Length > gapLen)
|
||||
{
|
||||
input[..gapLen].CopyTo(buf.AsSpan(bufOff));
|
||||
|
||||
resultLen = m_cipherMode.ProcessBlock(buf, output);
|
||||
Array.Copy(buf, blockSize, buf, 0, blockSize);
|
||||
|
||||
bufOff = blockSize;
|
||||
|
||||
input = input[gapLen..];
|
||||
|
||||
while (input.Length > blockSize)
|
||||
{
|
||||
input[..blockSize].CopyTo(buf.AsSpan(bufOff));
|
||||
resultLen += m_cipherMode.ProcessBlock(buf, output[resultLen..]);
|
||||
Array.Copy(buf, blockSize, buf, 0, blockSize);
|
||||
|
||||
input = input[blockSize..];
|
||||
}
|
||||
}
|
||||
|
||||
input.CopyTo(buf.AsSpan(bufOff));
|
||||
|
||||
bufOff += input.Length;
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Process the last block in the buffer.
|
||||
*
|
||||
* @param out the array the block currently being held is copied into.
|
||||
* @param outOff the offset at which the copying starts.
|
||||
* @return the number of output bytes copied to out.
|
||||
* @exception DataLengthException if there is insufficient space in out for
|
||||
* the output.
|
||||
* @exception InvalidOperationException if the underlying cipher is not
|
||||
* initialised.
|
||||
* @exception InvalidCipherTextException if cipher text decrypts wrongly (in
|
||||
* case the exception will never Get thrown).
|
||||
*/
|
||||
public override int DoFinal(byte[] output, int outOff)
|
||||
{
|
||||
if (bufOff + outOff > output.Length)
|
||||
throw new DataLengthException("output buffer too small in DoFinal");
|
||||
|
||||
int blockSize = m_cipherMode.GetBlockSize();
|
||||
int length = bufOff - blockSize;
|
||||
byte[] block = new byte[blockSize];
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
m_cipherMode.ProcessBlock(buf, 0, block, 0);
|
||||
|
||||
if (bufOff < blockSize)
|
||||
throw new DataLengthException("need at least one block of input for CTS");
|
||||
|
||||
for (int i = bufOff; i != buf.Length; i++)
|
||||
{
|
||||
buf[i] = block[i - blockSize];
|
||||
}
|
||||
|
||||
for (int i = blockSize; i != bufOff; i++)
|
||||
{
|
||||
buf[i] ^= block[i - blockSize];
|
||||
}
|
||||
|
||||
m_cipherMode.UnderlyingCipher.ProcessBlock(buf, blockSize, output, outOff);
|
||||
|
||||
Array.Copy(block, 0, output, outOff + blockSize, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] lastBlock = new byte[blockSize];
|
||||
|
||||
m_cipherMode.UnderlyingCipher.ProcessBlock(buf, 0, block, 0);
|
||||
|
||||
for (int i = blockSize; i != bufOff; i++)
|
||||
{
|
||||
lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]);
|
||||
}
|
||||
|
||||
Array.Copy(buf, blockSize, block, 0, length);
|
||||
|
||||
m_cipherMode.ProcessBlock(block, 0, output, outOff);
|
||||
Array.Copy(lastBlock, 0, output, outOff + blockSize, length);
|
||||
}
|
||||
|
||||
int offset = bufOff;
|
||||
|
||||
Reset();
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public override int DoFinal(Span<byte> output)
|
||||
{
|
||||
if (bufOff > output.Length)
|
||||
throw new DataLengthException("output buffer too small in DoFinal");
|
||||
|
||||
int blockSize = m_cipherMode.GetBlockSize();
|
||||
int length = bufOff - blockSize;
|
||||
Span<byte> block = blockSize <= 64
|
||||
? stackalloc byte[blockSize]
|
||||
: new byte[blockSize];
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
m_cipherMode.ProcessBlock(buf, block);
|
||||
|
||||
if (bufOff < blockSize)
|
||||
throw new DataLengthException("need at least one block of input for CTS");
|
||||
|
||||
for (int i = bufOff; i != buf.Length; i++)
|
||||
{
|
||||
buf[i] = block[i - blockSize];
|
||||
}
|
||||
|
||||
for (int i = blockSize; i != bufOff; i++)
|
||||
{
|
||||
buf[i] ^= block[i - blockSize];
|
||||
}
|
||||
|
||||
m_cipherMode.UnderlyingCipher.ProcessBlock(buf.AsSpan(blockSize), output);
|
||||
|
||||
block[..length].CopyTo(output[blockSize..]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Span<byte> lastBlock = blockSize <= 64
|
||||
? stackalloc byte[blockSize]
|
||||
: new byte[blockSize];
|
||||
|
||||
m_cipherMode.UnderlyingCipher.ProcessBlock(buf, block);
|
||||
|
||||
for (int i = blockSize; i != bufOff; i++)
|
||||
{
|
||||
lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]);
|
||||
}
|
||||
|
||||
buf.AsSpan(blockSize, length).CopyTo(block);
|
||||
|
||||
m_cipherMode.ProcessBlock(block, output);
|
||||
lastBlock[..length].CopyTo(output[blockSize..]);
|
||||
}
|
||||
|
||||
int offset = bufOff;
|
||||
|
||||
Reset();
|
||||
|
||||
return offset;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CtsBlockCipher.cs.meta
vendored
Normal file
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/CtsBlockCipher.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e40dd04cc8a1228489faa2810ffae5c3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
506
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/EAXBlockCipher.cs
vendored
Normal file
506
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/EAXBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,506 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and
|
||||
* Efficiency - by M. Bellare, P. Rogaway, D. Wagner.
|
||||
*
|
||||
* http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
|
||||
*
|
||||
* EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block
|
||||
* cipher to encrypt and authenticate data. It's on-line (the length of a
|
||||
* message isn't needed to begin processing it), has good performances, it's
|
||||
* simple and provably secure (provided the underlying block cipher is secure).
|
||||
*
|
||||
* Of course, this implementations is NOT thread-safe.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Constructor that accepts an instance of a block cipher engine.
|
||||
*
|
||||
* @param cipher the engine to use
|
||||
*/
|
||||
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 string AlgorithmName => cipher.UnderlyingCipher.AlgorithmName + "/EAX";
|
||||
|
||||
public virtual IBlockCipher UnderlyingCipher => cipher;
|
||||
|
||||
public virtual int GetBlockSize()
|
||||
{
|
||||
return cipher.GetBlockSize();
|
||||
}
|
||||
|
||||
public virtual void Init(bool forEncryption, ICipherParameters parameters)
|
||||
{
|
||||
this.forEncryption = forEncryption;
|
||||
|
||||
byte[] nonce;
|
||||
ICipherParameters keyParam;
|
||||
|
||||
if (parameters is AeadParameters aeadParameters)
|
||||
{
|
||||
nonce = aeadParameters.GetNonce();
|
||||
initialAssociatedText = aeadParameters.GetAssociatedText();
|
||||
macSize = aeadParameters.MacSize / 8;
|
||||
keyParam = aeadParameters.Key;
|
||||
}
|
||||
else if (parameters is ParametersWithIV parametersWithIV)
|
||||
{
|
||||
nonce = parametersWithIV.GetIV();
|
||||
initialAssociatedText = null;
|
||||
macSize = mac.GetMacSize() / 2;
|
||||
keyParam = parametersWithIV.Parameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("invalid parameters passed to EAX");
|
||||
}
|
||||
|
||||
bufBlock = new byte[forEncryption ? blockSize : (blockSize + macSize)];
|
||||
|
||||
byte[] tag = new byte[blockSize];
|
||||
|
||||
// Key reuse implemented in CBC mode of underlying CMac
|
||||
mac.Init(keyParam);
|
||||
|
||||
tag[blockSize - 1] = (byte)Tag.N;
|
||||
mac.BlockUpdate(tag, 0, blockSize);
|
||||
mac.BlockUpdate(nonce, 0, nonce.Length);
|
||||
mac.DoFinal(nonceMac, 0);
|
||||
|
||||
// Same BlockCipher underlies this and the mac, so reuse last key on cipher
|
||||
cipher.Init(true, new ParametersWithIV(null, nonceMac));
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
private void InitCipher()
|
||||
{
|
||||
if (cipherInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cipherInitialized = true;
|
||||
|
||||
mac.DoFinal(associatedTextMac, 0);
|
||||
|
||||
byte[] tag = new byte[blockSize];
|
||||
tag[blockSize - 1] = (byte)Tag.C;
|
||||
mac.BlockUpdate(tag, 0, blockSize);
|
||||
}
|
||||
|
||||
private void CalculateMac()
|
||||
{
|
||||
byte[] outC = new byte[blockSize];
|
||||
mac.DoFinal(outC, 0);
|
||||
|
||||
for (int i = 0; i < macBlock.Length; i++)
|
||||
{
|
||||
macBlock[i] = (byte)(nonceMac[i] ^ associatedTextMac[i] ^ outC[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
Reset(true);
|
||||
}
|
||||
|
||||
private void Reset(
|
||||
bool clearMac)
|
||||
{
|
||||
cipher.Reset(); // TODO Redundant since the mac will reset it?
|
||||
mac.Reset();
|
||||
|
||||
bufOff = 0;
|
||||
Array.Clear(bufBlock, 0, bufBlock.Length);
|
||||
|
||||
if (clearMac)
|
||||
{
|
||||
Array.Clear(macBlock, 0, macBlock.Length);
|
||||
}
|
||||
|
||||
byte[] tag = new byte[blockSize];
|
||||
tag[blockSize - 1] = (byte)Tag.H;
|
||||
mac.BlockUpdate(tag, 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);
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
|
||||
{
|
||||
if (cipherInitialized)
|
||||
throw new InvalidOperationException("AAD data cannot be added after encryption/decryption processing has begun.");
|
||||
|
||||
mac.BlockUpdate(input);
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual int ProcessByte(byte input, byte[] outBytes, int outOff)
|
||||
{
|
||||
InitCipher();
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return Process(input, Spans.FromNullable(outBytes, outOff));
|
||||
#else
|
||||
return Process(input, outBytes, outOff);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int ProcessByte(byte input, Span<byte> output)
|
||||
{
|
||||
InitCipher();
|
||||
|
||||
return Process(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff)
|
||||
{
|
||||
InitCipher();
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return ProcessBytes(inBytes.AsSpan(inOff, len), Spans.FromNullable(outBytes, outOff));
|
||||
#else
|
||||
int resultLen = 0;
|
||||
|
||||
for (int i = 0; i != len; i++)
|
||||
{
|
||||
resultLen += Process(inBytes[inOff + i], outBytes, outOff + resultLen);
|
||||
}
|
||||
|
||||
return resultLen;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
InitCipher();
|
||||
|
||||
int len = input.Length;
|
||||
int resultLen = 0;
|
||||
|
||||
for (int i = 0; i != len; i++)
|
||||
{
|
||||
resultLen += Process(input[i], output[resultLen..]);
|
||||
}
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual int DoFinal(byte[] outBytes, int outOff)
|
||||
{
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return DoFinal(outBytes.AsSpan(outOff));
|
||||
#else
|
||||
InitCipher();
|
||||
|
||||
int extra = bufOff;
|
||||
byte[] tmp = new byte[bufBlock.Length];
|
||||
|
||||
bufOff = 0;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
Check.OutputLength(outBytes, outOff, extra + macSize, "output buffer too short");
|
||||
|
||||
cipher.ProcessBlock(bufBlock, 0, tmp, 0);
|
||||
|
||||
Array.Copy(tmp, 0, outBytes, outOff, extra);
|
||||
|
||||
mac.BlockUpdate(tmp, 0, extra);
|
||||
|
||||
CalculateMac();
|
||||
|
||||
Array.Copy(macBlock, 0, outBytes, outOff + extra, macSize);
|
||||
|
||||
Reset(false);
|
||||
|
||||
return extra + macSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (extra < macSize)
|
||||
throw new InvalidCipherTextException("data too short");
|
||||
|
||||
Check.OutputLength(outBytes, outOff, extra - macSize, "output buffer too short");
|
||||
|
||||
if (extra > macSize)
|
||||
{
|
||||
mac.BlockUpdate(bufBlock, 0, extra - macSize);
|
||||
|
||||
cipher.ProcessBlock(bufBlock, 0, tmp, 0);
|
||||
|
||||
Array.Copy(tmp, 0, outBytes, outOff, extra - macSize);
|
||||
}
|
||||
|
||||
CalculateMac();
|
||||
|
||||
if (!VerifyMac(bufBlock, extra - macSize))
|
||||
throw new InvalidCipherTextException("mac check in EAX failed");
|
||||
|
||||
Reset(false);
|
||||
|
||||
return extra - macSize;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int DoFinal(Span<byte> output)
|
||||
{
|
||||
InitCipher();
|
||||
|
||||
int extra = bufOff;
|
||||
int tmpLength = bufBlock.Length;
|
||||
|
||||
Span<byte> tmp = tmpLength <= 128
|
||||
? stackalloc byte[tmpLength]
|
||||
: new byte[tmpLength];
|
||||
|
||||
bufOff = 0;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
Check.OutputLength(output, extra + macSize, "output buffer too short");
|
||||
|
||||
cipher.ProcessBlock(bufBlock, tmp);
|
||||
|
||||
tmp[..extra].CopyTo(output);
|
||||
|
||||
mac.BlockUpdate(tmp[..extra]);
|
||||
|
||||
CalculateMac();
|
||||
|
||||
macBlock.AsSpan(0, macSize).CopyTo(output[extra..]);
|
||||
|
||||
Reset(false);
|
||||
|
||||
return extra + macSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (extra < macSize)
|
||||
throw new InvalidCipherTextException("data too short");
|
||||
|
||||
Check.OutputLength(output, extra - macSize, "output buffer too short");
|
||||
|
||||
if (extra > macSize)
|
||||
{
|
||||
mac.BlockUpdate(bufBlock.AsSpan(0, extra - macSize));
|
||||
|
||||
cipher.ProcessBlock(bufBlock, tmp);
|
||||
|
||||
tmp[..(extra - macSize)].CopyTo(output);
|
||||
}
|
||||
|
||||
CalculateMac();
|
||||
|
||||
if (!VerifyMac(bufBlock, extra - macSize))
|
||||
throw new InvalidCipherTextException("mac check in EAX failed");
|
||||
|
||||
Reset(false);
|
||||
|
||||
return extra - macSize;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual byte[] GetMac()
|
||||
{
|
||||
byte[] mac = new byte[macSize];
|
||||
|
||||
Array.Copy(macBlock, 0, mac, 0, macSize);
|
||||
|
||||
return mac;
|
||||
}
|
||||
|
||||
public virtual int GetUpdateOutputSize(
|
||||
int len)
|
||||
{
|
||||
int totalData = len + bufOff;
|
||||
if (!forEncryption)
|
||||
{
|
||||
if (totalData < macSize)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
totalData -= macSize;
|
||||
}
|
||||
return totalData - totalData % blockSize;
|
||||
}
|
||||
|
||||
public virtual int GetOutputSize(
|
||||
int len)
|
||||
{
|
||||
int totalData = len + bufOff;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
return totalData + macSize;
|
||||
}
|
||||
|
||||
return totalData < macSize ? 0 : totalData - macSize;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
private int Process(byte b, Span<byte> output)
|
||||
{
|
||||
bufBlock[bufOff++] = b;
|
||||
|
||||
if (bufOff == bufBlock.Length)
|
||||
{
|
||||
Check.OutputLength(output, blockSize, "output buffer too short");
|
||||
|
||||
// TODO Could move the ProcessByte(s) calls to here
|
||||
//InitCipher();
|
||||
|
||||
int size;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
size = cipher.ProcessBlock(bufBlock, output);
|
||||
|
||||
mac.BlockUpdate(output[..blockSize]);
|
||||
}
|
||||
else
|
||||
{
|
||||
mac.BlockUpdate(bufBlock.AsSpan(0, blockSize));
|
||||
|
||||
size = cipher.ProcessBlock(bufBlock, output);
|
||||
}
|
||||
|
||||
bufOff = 0;
|
||||
if (!forEncryption)
|
||||
{
|
||||
Array.Copy(bufBlock, blockSize, bufBlock, 0, macSize);
|
||||
bufOff = macSize;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
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");
|
||||
|
||||
// TODO Could move the ProcessByte(s) calls to here
|
||||
// InitCipher();
|
||||
|
||||
int size;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
|
||||
|
||||
mac.BlockUpdate(outBytes, outOff, blockSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
mac.BlockUpdate(bufBlock, 0, blockSize);
|
||||
|
||||
size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
|
||||
}
|
||||
|
||||
bufOff = 0;
|
||||
if (!forEncryption)
|
||||
{
|
||||
Array.Copy(bufBlock, blockSize, bufBlock, 0, macSize);
|
||||
bufOff = macSize;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
private bool VerifyMac(byte[] mac, int off)
|
||||
{
|
||||
int nonEqual = 0;
|
||||
|
||||
for (int i = 0; i < macSize; i++)
|
||||
{
|
||||
nonEqual |= (macBlock[i] ^ mac[off + i]);
|
||||
}
|
||||
|
||||
return nonEqual == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/EAXBlockCipher.cs.meta
vendored
Normal file
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/EAXBlockCipher.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 611d91847a15dff4ebc2fe9f3326559f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
62
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/EcbBlockCipher.cs
vendored
Normal file
62
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/EcbBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
public class EcbBlockCipher
|
||||
: IBlockCipherMode
|
||||
{
|
||||
internal static IBlockCipherMode GetBlockCipherMode(IBlockCipher blockCipher)
|
||||
{
|
||||
if (blockCipher is IBlockCipherMode blockCipherMode)
|
||||
return blockCipherMode;
|
||||
|
||||
return new EcbBlockCipher(blockCipher);
|
||||
}
|
||||
|
||||
private readonly IBlockCipher m_cipher;
|
||||
|
||||
public EcbBlockCipher(IBlockCipher cipher)
|
||||
{
|
||||
if (cipher == null)
|
||||
throw new ArgumentNullException(nameof(cipher));
|
||||
|
||||
m_cipher = cipher;
|
||||
}
|
||||
|
||||
public bool IsPartialBlockOkay => false;
|
||||
|
||||
public string AlgorithmName => m_cipher.AlgorithmName + "/ECB";
|
||||
|
||||
public int GetBlockSize()
|
||||
{
|
||||
return m_cipher.GetBlockSize();
|
||||
}
|
||||
|
||||
public IBlockCipher UnderlyingCipher => m_cipher;
|
||||
|
||||
public void Init(bool forEncryption, ICipherParameters parameters)
|
||||
{
|
||||
m_cipher.Init(forEncryption, parameters);
|
||||
}
|
||||
|
||||
public int ProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff)
|
||||
{
|
||||
return m_cipher.ProcessBlock(inBuf, inOff, outBuf, outOff);
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
return m_cipher.ProcessBlock(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/EcbBlockCipher.cs.meta
vendored
Normal file
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/EcbBlockCipher.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50e8f0b9b9ecb034bb7aad3b1fb61e75
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1505
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/GCMBlockCipher.cs
vendored
Normal file
1505
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/GCMBlockCipher.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/GCMBlockCipher.cs.meta
vendored
Normal file
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/GCMBlockCipher.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ab9d7d1ff514d9479d1a3bca307ff13
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
234
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/GOFBBlockCipher.cs
vendored
Normal file
234
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/GOFBBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* implements the GOST 28147 OFB counter mode (GCTR).
|
||||
*/
|
||||
public class GOfbBlockCipher
|
||||
: IBlockCipherMode
|
||||
{
|
||||
private byte[] IV;
|
||||
private byte[] ofbV;
|
||||
private byte[] ofbOutV;
|
||||
|
||||
private readonly int blockSize;
|
||||
private readonly IBlockCipher cipher;
|
||||
|
||||
bool firstStep = true;
|
||||
int N3;
|
||||
int N4;
|
||||
const int C1 = 16843012; //00000001000000010000000100000100
|
||||
const int C2 = 16843009; //00000001000000010000000100000001
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used as the basis of the
|
||||
* counter mode (must have a 64 bit block size).
|
||||
*/
|
||||
public GOfbBlockCipher(
|
||||
IBlockCipher cipher)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.blockSize = cipher.GetBlockSize();
|
||||
|
||||
if (blockSize != 8)
|
||||
{
|
||||
throw new ArgumentException("GCTR only for 64 bit block ciphers");
|
||||
}
|
||||
|
||||
this.IV = new byte[cipher.GetBlockSize()];
|
||||
this.ofbV = new byte[cipher.GetBlockSize()];
|
||||
this.ofbOutV = new byte[cipher.GetBlockSize()];
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public IBlockCipher UnderlyingCipher => cipher;
|
||||
|
||||
/**
|
||||
* Initialise the cipher and, possibly, the initialisation vector (IV).
|
||||
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
|
||||
* An IV which is too short is handled in FIPS compliant fashion.
|
||||
*
|
||||
* @param encrypting if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param parameters the key and other data required by the cipher.
|
||||
* @exception ArgumentException if the parameters argument is inappropriate.
|
||||
*/
|
||||
public void Init(
|
||||
bool forEncryption, //ignored by this CTR mode
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
firstStep = true;
|
||||
N3 = 0;
|
||||
N4 = 0;
|
||||
|
||||
if (parameters is ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV ivParam = (ParametersWithIV)parameters;
|
||||
byte[] iv = ivParam.GetIV();
|
||||
|
||||
if (iv.Length < IV.Length)
|
||||
{
|
||||
// prepend the supplied IV with zeros (per FIPS PUB 81)
|
||||
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 = ivParam.Parameters;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
// if it's null, key is to be reused.
|
||||
if (parameters != null)
|
||||
{
|
||||
cipher.Init(true, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the algorithm name and mode.
|
||||
*
|
||||
* @return the name of the underlying algorithm followed by "/GCTR"
|
||||
* and the block size in bits
|
||||
*/
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/GCTR"; }
|
||||
}
|
||||
|
||||
public bool IsPartialBlockOkay
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block size we are operating at (in bytes).
|
||||
*
|
||||
* @return the block size we are operating at (in bytes).
|
||||
*/
|
||||
public int GetBlockSize()
|
||||
{
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
|
||||
{
|
||||
Check.DataLength(input, inOff, blockSize, "input buffer too short");
|
||||
Check.OutputLength(output, outOff, blockSize, "output buffer too short");
|
||||
|
||||
if (firstStep)
|
||||
{
|
||||
firstStep = false;
|
||||
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
|
||||
N3 = (int)Pack.LE_To_UInt32(ofbOutV, 0);
|
||||
N4 = (int)Pack.LE_To_UInt32(ofbOutV, 4);
|
||||
}
|
||||
N3 += C2;
|
||||
N4 += C1;
|
||||
if (N4 < C1) // addition is mod (2**32 - 1)
|
||||
{
|
||||
if (N4 > 0)
|
||||
{
|
||||
N4++;
|
||||
}
|
||||
}
|
||||
Pack.UInt32_To_LE((uint)N3, ofbV, 0);
|
||||
Pack.UInt32_To_LE((uint)N4, ofbV, 4);
|
||||
|
||||
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
|
||||
|
||||
//
|
||||
// XOR the ofbV with the plaintext producing the cipher text (and
|
||||
// the next input block).
|
||||
//
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]);
|
||||
}
|
||||
|
||||
//
|
||||
// change over the input block.
|
||||
//
|
||||
Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
|
||||
Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
Check.DataLength(input, blockSize, "input buffer too short");
|
||||
Check.OutputLength(output, blockSize, "output buffer too short");
|
||||
|
||||
if (firstStep)
|
||||
{
|
||||
firstStep = false;
|
||||
cipher.ProcessBlock(ofbV, ofbOutV);
|
||||
N3 = (int)Pack.LE_To_UInt32(ofbOutV, 0);
|
||||
N4 = (int)Pack.LE_To_UInt32(ofbOutV, 4);
|
||||
}
|
||||
N3 += C2;
|
||||
N4 += C1;
|
||||
if (N4 < C1) // addition is mod (2**32 - 1)
|
||||
{
|
||||
if (N4 > 0)
|
||||
{
|
||||
N4++;
|
||||
}
|
||||
}
|
||||
Pack.UInt32_To_LE((uint)N3, ofbV, 0);
|
||||
Pack.UInt32_To_LE((uint)N4, ofbV, 4);
|
||||
|
||||
cipher.ProcessBlock(ofbV, ofbOutV);
|
||||
|
||||
//
|
||||
// XOR the ofbV with the plaintext producing the cipher text (and
|
||||
// the next input block).
|
||||
//
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
output[i] = (byte)(ofbOutV[i] ^ input[i]);
|
||||
}
|
||||
|
||||
//
|
||||
// change over the input block.
|
||||
//
|
||||
Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
|
||||
Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* reset the feedback vector back to the IV and reset the underlying
|
||||
* cipher.
|
||||
*/
|
||||
public void Reset()
|
||||
{
|
||||
Array.Copy(IV, 0, ofbV, 0, IV.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bba6a24ff3c75d94eabc433ea5f09f6d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1075
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/GcmSivBlockCipher.cs
vendored
Normal file
1075
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/GcmSivBlockCipher.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bde795fc81d90214ca49145d8d4266c4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
19
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/IAeadBlockCipher.cs
vendored
Normal file
19
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/IAeadBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/// <summary>An IAeadCipher based on an IBlockCipher.</summary>
|
||||
public interface IAeadBlockCipher
|
||||
: IAeadCipher
|
||||
{
|
||||
/// <returns>The block size for this cipher, in bytes.</returns>
|
||||
int GetBlockSize();
|
||||
|
||||
/// <summary>The block cipher underlying this algorithm.</summary>
|
||||
IBlockCipher UnderlyingCipher { get; }
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 721d46b2e82841d418e36512a8e3c356
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
134
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/IAeadCipher.cs
vendored
Normal file
134
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/IAeadCipher.cs
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/// <summary>
|
||||
/// A cipher mode that includes authenticated encryption with a streaming mode and optional
|
||||
/// associated data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Implementations of this interface may operate in a packet mode (where all input data is
|
||||
/// buffered and processed during the call to DoFinal, or in a streaming mode (where output
|
||||
/// data is incrementally produced with each call to ProcessByte or ProcessBytes. This is
|
||||
/// important to consider during decryption: in a streaming mode, unauthenticated plaintext
|
||||
/// data may be output prior to the call to DoFinal that results in an authentication failure.
|
||||
/// The higher level protocol utilising this cipher must ensure the plaintext data is handled
|
||||
/// appropriately until the end of data is reached and the entire ciphertext is authenticated.
|
||||
/// </remarks>
|
||||
/// <see cref="AeadParameters"/>
|
||||
public interface IAeadCipher
|
||||
{
|
||||
/// <summary>The name of the algorithm this cipher implements.</summary>
|
||||
string AlgorithmName { get; }
|
||||
|
||||
/// <summary>Initialise the cipher.</summary>
|
||||
/// <remarks>Parameter can either be an AeadParameters or a ParametersWithIV object.</remarks>
|
||||
/// <param name="forEncryption">Initialise for encryption if true, for decryption if false.</param>
|
||||
/// <param name="parameters">The key or other data required by the cipher.</param>
|
||||
void Init(bool forEncryption, ICipherParameters parameters);
|
||||
|
||||
/// <summary>Add a single byte to the associated data check.</summary>
|
||||
/// <remarks>If the implementation supports it, this will be an online operation and will not retain the associated data.</remarks>
|
||||
/// <param name="input">The byte to be processed.</param>
|
||||
void ProcessAadByte(byte input);
|
||||
|
||||
/// <summary>Add a sequence of bytes to the associated data check.</summary>
|
||||
/// <remarks>If the implementation supports it, this will be an online operation and will not retain the associated data.</remarks>
|
||||
/// <param name="inBytes">The input byte array.</param>
|
||||
/// <param name="inOff">The offset into the input array where the data to be processed starts.</param>
|
||||
/// <param name="len">The number of bytes to be processed.</param>
|
||||
void ProcessAadBytes(byte[] inBytes, int inOff, int len);
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
/// <summary>Add a span of bytes to the associated data check.</summary>
|
||||
/// <remarks>If the implementation supports it, this will be an online operation and will not retain the associated data.</remarks>
|
||||
/// <param name="input">the span containing the data.</param>
|
||||
void ProcessAadBytes(ReadOnlySpan<byte> input);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Encrypt/decrypt a single byte.
|
||||
*
|
||||
* @param input the byte to be processed.
|
||||
* @param outBytes the output buffer the processed byte goes into.
|
||||
* @param outOff the offset into the output byte array the processed data starts at.
|
||||
* @return the number of bytes written to out.
|
||||
* @exception DataLengthException if the output buffer is too small.
|
||||
*/
|
||||
int ProcessByte(byte input, byte[] outBytes, int outOff);
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
int ProcessByte(byte input, Span<byte> output);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Process a block of bytes from in putting the result into out.
|
||||
*
|
||||
* @param inBytes the input byte array.
|
||||
* @param inOff the offset into the in array where the data to be processed starts.
|
||||
* @param len the number of bytes to be processed.
|
||||
* @param outBytes the output buffer the processed bytes go into.
|
||||
* @param outOff the offset into the output byte array the processed data starts at.
|
||||
* @return the number of bytes written to out.
|
||||
* @exception DataLengthException if the output buffer is too small.
|
||||
*/
|
||||
int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff);
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Finish the operation either appending or verifying the MAC at the end of the data.
|
||||
*
|
||||
* @param outBytes space for any resulting output data.
|
||||
* @param outOff offset into out to start copying the data at.
|
||||
* @return number of bytes written into out.
|
||||
* @throws InvalidOperationException if the cipher is in an inappropriate state.
|
||||
* @throws InvalidCipherTextException if the MAC fails to match.
|
||||
*/
|
||||
int DoFinal(byte[] outBytes, int outOff);
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
int DoFinal(Span<byte> output);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Return the value of the MAC associated with the last stream processed.
|
||||
*
|
||||
* @return MAC for plaintext data.
|
||||
*/
|
||||
byte[] GetMac();
|
||||
|
||||
/**
|
||||
* Return the size of the output buffer required for a ProcessBytes
|
||||
* an input of len bytes.
|
||||
*
|
||||
* @param len the length of the input.
|
||||
* @return the space required to accommodate a call to ProcessBytes
|
||||
* with len bytes of input.
|
||||
*/
|
||||
int GetUpdateOutputSize(int len);
|
||||
|
||||
/**
|
||||
* Return the size of the output buffer required for a ProcessBytes plus a
|
||||
* DoFinal with an input of len bytes.
|
||||
*
|
||||
* @param len the length of the input.
|
||||
* @return the space required to accommodate a call to ProcessBytes and DoFinal
|
||||
* with len bytes of input.
|
||||
*/
|
||||
int GetOutputSize(int len);
|
||||
|
||||
/// <summary>
|
||||
/// Reset the cipher to the same state as it was after the last init (if there was one).
|
||||
/// </summary>
|
||||
void Reset();
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/IAeadCipher.cs.meta
vendored
Normal file
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/IAeadCipher.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a148e28c828dee1469495b92e57c9700
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
23
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/IBlockCipherMode.cs
vendored
Normal file
23
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/IBlockCipherMode.cs
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
public interface IBlockCipherMode
|
||||
: IBlockCipher
|
||||
{
|
||||
/// <summary>Return the <code cref="IBlockCipher"/> underlying this cipher mode.</summary>
|
||||
IBlockCipher UnderlyingCipher { get; }
|
||||
|
||||
/// <summary>Indicates whether this cipher mode can handle partial blocks.</summary>
|
||||
bool IsPartialBlockOkay { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Reset the cipher mode to the same state as it was after the last init (if there was one).
|
||||
/// </summary>
|
||||
void Reset();
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1ac4125e3c2b46449b20e6f96891d36
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
668
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/KCcmBlockCipher.cs
vendored
Normal file
668
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/KCcmBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,668 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.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;
|
||||
|
||||
private void setNb(int Nb)
|
||||
{
|
||||
if (Nb == 4 || Nb == 6 || Nb == 8)
|
||||
{
|
||||
Nb_ = Nb;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Nb = 4 is recommended by DSTU7624 but can be changed to only 6 or 8 in this implementation");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base constructor. Nb value is set to 4.
|
||||
/// </summary>
|
||||
/// <param name="engine">base cipher to use under CCM.</param>
|
||||
public KCcmBlockCipher(IBlockCipher engine): this(engine, 4)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor allowing Nb configuration.
|
||||
///
|
||||
/// Nb is a parameter specified in CCM mode of DSTU7624 standard.
|
||||
/// This parameter specifies maximum possible length of input.It should
|
||||
/// be calculated as follows: Nb = 1 / 8 * (-3 + log[2]Nmax) + 1,
|
||||
/// where Nmax - length of input message in bits.For practical reasons
|
||||
/// Nmax usually less than 4Gb, e.g. for Nmax = 2^32 - 1, Nb = 4.
|
||||
/// </summary>
|
||||
/// <param name="engine">base cipher to use under CCM.</param>
|
||||
/// <param name="Nb">Nb value to use.</param>
|
||||
public KCcmBlockCipher(IBlockCipher engine, int Nb)
|
||||
{
|
||||
this.engine = engine;
|
||||
this.macSize = engine.GetBlockSize();
|
||||
this.nonce = new byte[engine.GetBlockSize()];
|
||||
this.initialAssociatedText = new byte[engine.GetBlockSize()];
|
||||
this.mac = new byte[engine.GetBlockSize()];
|
||||
this.macBlock = new byte[engine.GetBlockSize()];
|
||||
this.G1 = new byte[engine.GetBlockSize()];
|
||||
this.buffer = new byte[engine.GetBlockSize()];
|
||||
this.s = new byte[engine.GetBlockSize()];
|
||||
this.counter = new byte[engine.GetBlockSize()];
|
||||
setNb(Nb);
|
||||
}
|
||||
|
||||
public virtual void Init(bool forEncryption, ICipherParameters parameters)
|
||||
{
|
||||
|
||||
ICipherParameters cipherParameters;
|
||||
if (parameters is AeadParameters)
|
||||
{
|
||||
|
||||
AeadParameters param = (AeadParameters)parameters;
|
||||
|
||||
if (param.MacSize > MAX_MAC_BIT_LENGTH || param.MacSize < MIN_MAC_BIT_LENGTH || param.MacSize % 8 != 0)
|
||||
{
|
||||
throw new ArgumentException("Invalid mac size specified");
|
||||
}
|
||||
|
||||
nonce = param.GetNonce();
|
||||
macSize = param.MacSize / BITS_IN_BYTE;
|
||||
initialAssociatedText = param.GetAssociatedText();
|
||||
cipherParameters = param.Key;
|
||||
}
|
||||
else if (parameters is ParametersWithIV)
|
||||
{
|
||||
nonce = ((ParametersWithIV)parameters).GetIV();
|
||||
macSize = engine.GetBlockSize(); // use default blockSize for MAC if it is not specified
|
||||
initialAssociatedText = null;
|
||||
cipherParameters = ((ParametersWithIV)parameters).Parameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Invalid parameters specified");
|
||||
}
|
||||
|
||||
this.mac = new byte[macSize];
|
||||
this.forEncryption = forEncryption;
|
||||
engine.Init(true, cipherParameters);
|
||||
|
||||
counter[0] = 0x01; // defined in standard
|
||||
|
||||
if (initialAssociatedText != null)
|
||||
{
|
||||
ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string AlgorithmName => engine.AlgorithmName + "/KCCM";
|
||||
|
||||
public virtual int GetBlockSize()
|
||||
{
|
||||
return engine.GetBlockSize();
|
||||
}
|
||||
|
||||
public virtual IBlockCipher UnderlyingCipher => 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);
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
|
||||
{
|
||||
associatedText.Write(input);
|
||||
}
|
||||
#endif
|
||||
|
||||
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); // for G1
|
||||
|
||||
Array.Copy(buffer, 0, G1, nonce.Length - Nb_ - 1, BYTES_IN_INT);
|
||||
|
||||
G1[G1.Length - 1] = getFlag(true, macSize);
|
||||
|
||||
engine.ProcessBlock(G1, 0, macBlock, 0);
|
||||
|
||||
intToBytes(assocLen, buffer, 0); // for G2
|
||||
|
||||
if (assocLen <= engine.GetBlockSize() - Nb_)
|
||||
{
|
||||
for (int byteIndex = 0; byteIndex < assocLen; byteIndex++)
|
||||
{
|
||||
buffer[byteIndex + Nb_] ^= assocText[assocOff + byteIndex];
|
||||
}
|
||||
|
||||
for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
|
||||
{
|
||||
macBlock[byteIndex] ^= buffer[byteIndex];
|
||||
}
|
||||
|
||||
engine.ProcessBlock(macBlock, 0, macBlock, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
|
||||
{
|
||||
macBlock[byteIndex] ^= buffer[byteIndex];
|
||||
}
|
||||
|
||||
engine.ProcessBlock(macBlock, 0, macBlock, 0);
|
||||
|
||||
int authLen = assocLen;
|
||||
while (authLen != 0)
|
||||
{
|
||||
for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
|
||||
{
|
||||
macBlock[byteIndex] ^= assocText[byteIndex + assocOff];
|
||||
}
|
||||
|
||||
engine.ProcessBlock(macBlock, 0, macBlock, 0);
|
||||
|
||||
assocOff += engine.GetBlockSize();
|
||||
authLen -= engine.GetBlockSize();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual int ProcessByte(byte input, byte[] output, int outOff)
|
||||
{
|
||||
data.WriteByte(input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int ProcessByte(byte input, Span<byte> output)
|
||||
{
|
||||
data.WriteByte(input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
data.Write(input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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 NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return ProcessPacket(input.AsSpan(inOff, len), output.AsSpan(outOff));
|
||||
#else
|
||||
if (associatedText.Length > 0)
|
||||
{
|
||||
byte[] aad = associatedText.GetBuffer();
|
||||
int aadLen = Convert.ToInt32(associatedText.Length);
|
||||
|
||||
int dataLen = Convert.ToInt32(data.Length) - (forEncryption ? 0 : macSize);
|
||||
|
||||
ProcessAAD(aad, 0, aadLen, dataLen);
|
||||
}
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
Check.DataLength(len % engine.GetBlockSize() != 0, "partial blocks not supported");
|
||||
|
||||
CalculateMac(input, inOff, len);
|
||||
engine.ProcessBlock(nonce, 0, s, 0);
|
||||
|
||||
int totalLength = len;
|
||||
while (totalLength > 0)
|
||||
{
|
||||
ProcessBlock(input, inOff, output, outOff);
|
||||
totalLength -= engine.GetBlockSize();
|
||||
inOff += engine.GetBlockSize();
|
||||
outOff += engine.GetBlockSize();
|
||||
}
|
||||
|
||||
for (int byteIndex = 0; byteIndex<counter.Length; byteIndex++)
|
||||
{
|
||||
s[byteIndex] += counter[byteIndex];
|
||||
}
|
||||
|
||||
engine.ProcessBlock(s, 0, buffer, 0);
|
||||
|
||||
for (int byteIndex = 0; byteIndex<macSize; byteIndex++)
|
||||
{
|
||||
output[outOff + byteIndex] = (byte)(buffer[byteIndex] ^ macBlock[byteIndex]);
|
||||
}
|
||||
|
||||
Array.Copy(macBlock, 0, mac, 0, macSize);
|
||||
|
||||
Reset();
|
||||
|
||||
return len + macSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check.DataLength((len - macSize) % engine.GetBlockSize() != 0, "partial blocks not supported");
|
||||
|
||||
engine.ProcessBlock(nonce, 0, s, 0);
|
||||
|
||||
int blocks = len / engine.GetBlockSize();
|
||||
|
||||
for (int blockNum = 0; blockNum<blocks; blockNum++)
|
||||
{
|
||||
ProcessBlock(input, inOff, output, outOff);
|
||||
|
||||
inOff += engine.GetBlockSize();
|
||||
outOff += engine.GetBlockSize();
|
||||
}
|
||||
|
||||
if (len > inOff)
|
||||
{
|
||||
for (int byteIndex = 0; byteIndex<counter.Length; byteIndex++)
|
||||
{
|
||||
s[byteIndex] += counter[byteIndex];
|
||||
}
|
||||
|
||||
engine.ProcessBlock(s, 0, buffer, 0);
|
||||
|
||||
for (int byteIndex = 0; byteIndex<macSize; byteIndex++)
|
||||
{
|
||||
output[outOff + byteIndex] = (byte)(buffer[byteIndex] ^ input[inOff + byteIndex]);
|
||||
}
|
||||
outOff += macSize;
|
||||
}
|
||||
|
||||
for (int byteIndex = 0; byteIndex<counter.Length; byteIndex++)
|
||||
{
|
||||
s[byteIndex] += counter[byteIndex];
|
||||
}
|
||||
|
||||
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[] calculatedMac = new byte[macSize];
|
||||
|
||||
Array.Copy(buffer, 0, calculatedMac, 0, macSize);
|
||||
|
||||
if (!Arrays.ConstantTimeAreEqual(mac, calculatedMac))
|
||||
{
|
||||
throw new InvalidCipherTextException("mac check failed");
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
return len - macSize;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public int ProcessPacket(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
int len = input.Length;
|
||||
Check.OutputLength(output, len, "output buffer too short");
|
||||
|
||||
if (associatedText.Length > 0)
|
||||
{
|
||||
byte[] aad = associatedText.GetBuffer();
|
||||
int aadLen = Convert.ToInt32(associatedText.Length);
|
||||
|
||||
int dataLen = Convert.ToInt32(data.Length) - (forEncryption ? 0 : macSize);
|
||||
|
||||
ProcessAAD(aad, 0, aadLen, dataLen);
|
||||
}
|
||||
|
||||
int blockSize = engine.GetBlockSize(), index = 0;
|
||||
if (forEncryption)
|
||||
{
|
||||
Check.DataLength(len % blockSize != 0, "partial blocks not supported");
|
||||
|
||||
CalculateMac(input);
|
||||
engine.ProcessBlock(nonce, s);
|
||||
|
||||
int totalLength = len;
|
||||
while (totalLength > 0)
|
||||
{
|
||||
ProcessBlock(input[index..], output[index..]);
|
||||
totalLength -= blockSize;
|
||||
index += blockSize;
|
||||
}
|
||||
|
||||
for (int byteIndex = 0; byteIndex < counter.Length; byteIndex++)
|
||||
{
|
||||
s[byteIndex] += counter[byteIndex];
|
||||
}
|
||||
|
||||
engine.ProcessBlock(s, buffer);
|
||||
|
||||
for (int byteIndex = 0; byteIndex < macSize; byteIndex++)
|
||||
{
|
||||
output[index + byteIndex] = (byte)(buffer[byteIndex] ^ macBlock[byteIndex]);
|
||||
}
|
||||
|
||||
Array.Copy(macBlock, 0, mac, 0, macSize);
|
||||
|
||||
Reset();
|
||||
|
||||
return len + macSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check.DataLength((len - macSize) % blockSize != 0, "partial blocks not supported");
|
||||
|
||||
engine.ProcessBlock(nonce, 0, s, 0);
|
||||
|
||||
int blocks = len / engine.GetBlockSize();
|
||||
|
||||
for (int blockNum = 0; blockNum < blocks; blockNum++)
|
||||
{
|
||||
ProcessBlock(input[index..], output[index..]);
|
||||
index += blockSize;
|
||||
}
|
||||
|
||||
if (len > index)
|
||||
{
|
||||
for (int byteIndex = 0; byteIndex < counter.Length; byteIndex++)
|
||||
{
|
||||
s[byteIndex] += counter[byteIndex];
|
||||
}
|
||||
|
||||
engine.ProcessBlock(s, buffer);
|
||||
|
||||
for (int byteIndex = 0; byteIndex < macSize; byteIndex++)
|
||||
{
|
||||
output[index + byteIndex] = (byte)(buffer[byteIndex] ^ input[index + byteIndex]);
|
||||
}
|
||||
index += macSize;
|
||||
}
|
||||
|
||||
for (int byteIndex = 0; byteIndex < counter.Length; byteIndex++)
|
||||
{
|
||||
s[byteIndex] += counter[byteIndex];
|
||||
}
|
||||
|
||||
engine.ProcessBlock(s, buffer);
|
||||
|
||||
output[(index - macSize)..index].CopyTo(buffer);
|
||||
|
||||
CalculateMac(output[..(index - macSize)]);
|
||||
|
||||
Array.Copy(macBlock, 0, mac, 0, macSize);
|
||||
|
||||
Span<byte> calculatedMac = macSize <= 64
|
||||
? stackalloc byte[macSize]
|
||||
: new byte[macSize];
|
||||
|
||||
calculatedMac.CopyFrom(buffer);
|
||||
|
||||
if (!Arrays.ConstantTimeAreEqual(mac.AsSpan(0, macSize), calculatedMac))
|
||||
throw new InvalidCipherTextException("mac check failed");
|
||||
|
||||
Reset();
|
||||
|
||||
return len - macSize;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
private void CalculateMac(ReadOnlySpan<byte> authText)
|
||||
{
|
||||
int blockSize = engine.GetBlockSize();
|
||||
|
||||
while (!authText.IsEmpty)
|
||||
{
|
||||
for (int byteIndex = 0; byteIndex < blockSize; byteIndex++)
|
||||
{
|
||||
macBlock[byteIndex] ^= authText[byteIndex];
|
||||
}
|
||||
|
||||
engine.ProcessBlock(macBlock, macBlock);
|
||||
|
||||
authText = authText[blockSize..];
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
for (int byteIndex = 0; byteIndex < counter.Length; byteIndex++)
|
||||
{
|
||||
s[byteIndex] += counter[byteIndex];
|
||||
}
|
||||
|
||||
engine.ProcessBlock(s, buffer);
|
||||
|
||||
int blockSize = engine.GetBlockSize();
|
||||
for (int byteIndex = 0; byteIndex < blockSize; byteIndex++)
|
||||
{
|
||||
output[byteIndex] = (byte)(buffer[byteIndex] ^ input[byteIndex]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
private void CalculateMac(byte[] authText, int authOff, int len)
|
||||
{
|
||||
int blockSize = engine.GetBlockSize();
|
||||
int totalLen = len;
|
||||
while (totalLen > 0)
|
||||
{
|
||||
for (int byteIndex = 0; byteIndex < blockSize; byteIndex++)
|
||||
{
|
||||
macBlock[byteIndex] ^= authText[authOff + byteIndex];
|
||||
}
|
||||
|
||||
engine.ProcessBlock(macBlock, 0, macBlock, 0);
|
||||
|
||||
totalLen -= blockSize;
|
||||
authOff += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
|
||||
{
|
||||
|
||||
for (int byteIndex = 0; byteIndex < counter.Length; byteIndex++)
|
||||
{
|
||||
s[byteIndex] += counter[byteIndex];
|
||||
}
|
||||
|
||||
engine.ProcessBlock(s, 0, buffer, 0);
|
||||
|
||||
for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
|
||||
{
|
||||
output[outOff + byteIndex] = (byte)(buffer[byteIndex] ^ input[inOff + byteIndex]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual int DoFinal(byte[] output, int outOff)
|
||||
{
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return DoFinal(output.AsSpan(outOff));
|
||||
#else
|
||||
byte[] buf = data.GetBuffer();
|
||||
int bufLen = Convert.ToInt32(data.Length);
|
||||
|
||||
int len = ProcessPacket(buf, 0, bufLen, output, outOff);
|
||||
|
||||
Reset();
|
||||
|
||||
return len;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int DoFinal(Span<byte> output)
|
||||
{
|
||||
byte[] buf = data.GetBuffer();
|
||||
int bufLen = Convert.ToInt32(data.Length);
|
||||
|
||||
int len = ProcessPacket(buf.AsSpan(0, bufLen), output);
|
||||
|
||||
Reset();
|
||||
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
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, (byte)0);
|
||||
Arrays.Fill(buffer, (byte)0);
|
||||
Arrays.Fill(counter, (byte)0);
|
||||
Arrays.Fill(macBlock, (byte)0);
|
||||
|
||||
counter[0] = 0x01;
|
||||
data.SetLength(0);
|
||||
associatedText.SetLength(0);
|
||||
|
||||
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 flagByte = new StringBuilder();
|
||||
|
||||
if (authTextPresents)
|
||||
{
|
||||
flagByte.Append("1");
|
||||
}
|
||||
else
|
||||
{
|
||||
flagByte.Append("0");
|
||||
}
|
||||
|
||||
|
||||
switch (macSize)
|
||||
{
|
||||
case 8:
|
||||
flagByte.Append("010"); // binary 2
|
||||
break;
|
||||
case 16:
|
||||
flagByte.Append("011"); // binary 3
|
||||
break;
|
||||
case 32:
|
||||
flagByte.Append("100"); // binary 4
|
||||
break;
|
||||
case 48:
|
||||
flagByte.Append("101"); // binary 5
|
||||
break;
|
||||
case 64:
|
||||
flagByte.Append("110"); // binary 6
|
||||
break;
|
||||
}
|
||||
|
||||
string binaryNb = Convert.ToString(Nb_ - 1, 2);
|
||||
while (binaryNb.Length < 4)
|
||||
{
|
||||
binaryNb = new StringBuilder(binaryNb).Insert(0, "0").ToString();
|
||||
}
|
||||
|
||||
flagByte.Append(binaryNb);
|
||||
|
||||
return (byte)Convert.ToInt32(flagByte.ToString(), 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10ee1b085eab17c499ed6a8b5e685402
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
250
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/KCtrBlockCipher.cs
vendored
Normal file
250
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/KCtrBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* Implements a Gamming or Counter (CTR) mode on top of a DSTU 7624 block cipher.
|
||||
*/
|
||||
public class KCtrBlockCipher
|
||||
: IStreamCipher, IBlockCipherMode
|
||||
{
|
||||
private byte[] IV;
|
||||
private byte[] ofbV;
|
||||
private byte[] ofbOutV;
|
||||
private bool initialised;
|
||||
|
||||
private int byteCount;
|
||||
|
||||
private readonly int blockSize;
|
||||
private readonly IBlockCipher cipher;
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used as the basis of the
|
||||
* feedback mode.
|
||||
*/
|
||||
public KCtrBlockCipher(IBlockCipher cipher)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.IV = new byte[cipher.GetBlockSize()];
|
||||
this.blockSize = cipher.GetBlockSize();
|
||||
|
||||
this.ofbV = new byte[cipher.GetBlockSize()];
|
||||
this.ofbOutV = new byte[cipher.GetBlockSize()];
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public IBlockCipher UnderlyingCipher => cipher;
|
||||
|
||||
/**
|
||||
* Initialise the cipher and, possibly, the initialisation vector (IV).
|
||||
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
|
||||
* An IV which is too short is handled in FIPS compliant fashion.
|
||||
*
|
||||
* @param forEncryption if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param param the key and other data required by the cipher.
|
||||
* @exception ArgumentException if the parameters argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void Init(
|
||||
bool forEncryption,
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
this.initialised = true;
|
||||
if (parameters is ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV ivParam = (ParametersWithIV)parameters;
|
||||
byte[] iv = ivParam.GetIV();
|
||||
int diff = IV.Length - iv.Length;
|
||||
|
||||
Array.Clear(IV, 0, IV.Length);
|
||||
Array.Copy(iv, 0, IV, diff, iv.Length);
|
||||
|
||||
parameters = ivParam.Parameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Invalid parameter passed");
|
||||
}
|
||||
|
||||
// if it's null, key is to be reused.
|
||||
if (parameters != null)
|
||||
{
|
||||
cipher.Init(true, parameters);
|
||||
}
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the algorithm name and mode.
|
||||
*
|
||||
* @return the name of the underlying algorithm followed by "/KCTR"
|
||||
* and the block size in bits.
|
||||
*/
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/KCTR"; }
|
||||
}
|
||||
|
||||
public bool IsPartialBlockOkay
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block size we are operating at.
|
||||
*
|
||||
* @return the block size we are operating at (in bytes).
|
||||
*/
|
||||
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)
|
||||
{
|
||||
Check.DataLength(input, inOff, len, "input buffer too small");
|
||||
Check.OutputLength(output, outOff, len, "output buffer too short");
|
||||
|
||||
int inStart = inOff;
|
||||
int inEnd = inOff + len;
|
||||
int outStart = outOff;
|
||||
|
||||
while (inStart < inEnd)
|
||||
{
|
||||
output[outStart++] = CalculateByte(input[inStart++]);
|
||||
}
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public void ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
Check.OutputLength(output, input.Length, "output buffer too short");
|
||||
|
||||
for (int i = 0; i < input.Length; ++i)
|
||||
{
|
||||
output[i] = CalculateByte(input[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
protected byte CalculateByte(byte b)
|
||||
{
|
||||
if (byteCount == 0)
|
||||
{
|
||||
incrementCounterAt(0);
|
||||
|
||||
checkCounter();
|
||||
|
||||
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
|
||||
|
||||
return (byte)(ofbOutV[byteCount++] ^ b);
|
||||
}
|
||||
|
||||
byte rv = (byte)(ofbOutV[byteCount++] ^ b);
|
||||
|
||||
if (byteCount == ofbV.Length)
|
||||
{
|
||||
byteCount = 0;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process one block of input from the array in and write it to
|
||||
* the out array.
|
||||
*
|
||||
* @param input the array containing the input data.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param output the array the output data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
|
||||
{
|
||||
int blockSize = GetBlockSize();
|
||||
Check.DataLength(input, inOff, blockSize, "input buffer too short");
|
||||
Check.OutputLength(output, outOff, blockSize, "output buffer too short");
|
||||
|
||||
ProcessBytes(input, inOff, blockSize, output, outOff);
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
int blockSize = GetBlockSize();
|
||||
Check.DataLength(input, blockSize, "input buffer too short");
|
||||
Check.OutputLength(output, blockSize, "output buffer too short");
|
||||
|
||||
ProcessBytes(input[..blockSize], output);
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* reset the chaining vector back to the IV and reset the underlying
|
||||
* cipher.
|
||||
*/
|
||||
public void Reset()
|
||||
{
|
||||
if (initialised)
|
||||
{
|
||||
cipher.ProcessBlock(IV, 0, ofbV, 0);
|
||||
}
|
||||
byteCount = 0;
|
||||
}
|
||||
|
||||
private void incrementCounterAt(int pos)
|
||||
{
|
||||
int i = pos;
|
||||
while (i < ofbV.Length)
|
||||
{
|
||||
if (++ofbV[i++] != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCounter()
|
||||
{
|
||||
// TODO:
|
||||
// if the IV is the same as the blocksize we assume the user knows what they are doing
|
||||
// if (IV.length < ofbV.length)
|
||||
// {
|
||||
// for (int i = 0; i != IV.length; i++)
|
||||
// {
|
||||
// if (ofbV[i] != IV[i])
|
||||
// {
|
||||
// throw new IllegalStateException("Counter in KCTR mode out of range.");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b0202ca81530df4b96670290d02e774
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
734
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/OCBBlockCipher.cs
vendored
Normal file
734
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/OCBBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,734 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/// <summary>An implementation of <a href="https://tools.ietf.org/html/rfc7253">RFC 7253 on The OCB
|
||||
/// Authenticated-Encryption Algorithm</a>.</summary>
|
||||
/// <remarks>
|
||||
/// For those still concerned about the original patents around this, please see:
|
||||
/// <para>https://mailarchive.ietf.org/arch/msg/cfrg/qLTveWOdTJcLn4HP3ev-vrj05Vg/</para>
|
||||
/// Text reproduced below:
|
||||
/// <para>
|
||||
/// Phillip Rogaway<rogaway@cs.ucdavis.edu> Sat, 27 February 2021 02:46 UTC
|
||||
///
|
||||
/// I can confirm that I have abandoned all OCB patents and placed into the public domain all OCB-related IP of
|
||||
/// mine. While I have been telling people this for quite some time, I don't think I ever made a proper announcement
|
||||
/// to the CFRG or on the OCB webpage. Consider that done.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class OcbBlockCipher
|
||||
: IAeadBlockCipher
|
||||
{
|
||||
private const int BLOCK_SIZE = 16;
|
||||
|
||||
private readonly IBlockCipher hashCipher;
|
||||
private readonly IBlockCipher mainCipher;
|
||||
|
||||
/*
|
||||
* CONFIGURATION
|
||||
*/
|
||||
private bool forEncryption;
|
||||
private int macSize;
|
||||
private byte[] initialAssociatedText;
|
||||
|
||||
/*
|
||||
* KEY-DEPENDENT
|
||||
*/
|
||||
// NOTE: elements are lazily calculated
|
||||
private IList<byte[]> L;
|
||||
private byte[] L_Asterisk, L_Dollar;
|
||||
|
||||
/*
|
||||
* NONCE-DEPENDENT
|
||||
*/
|
||||
private byte[] KtopInput = null;
|
||||
private byte[] Stretch = new byte[24];
|
||||
private byte[] OffsetMAIN_0 = new byte[16];
|
||||
|
||||
/*
|
||||
* PER-ENCRYPTION/DECRYPTION
|
||||
*/
|
||||
private byte[] hashBlock, mainBlock;
|
||||
private int hashBlockPos, mainBlockPos;
|
||||
private long hashBlockCount, mainBlockCount;
|
||||
private byte[] OffsetHASH;
|
||||
private byte[] Sum;
|
||||
private byte[] OffsetMAIN = new byte[16];
|
||||
private byte[] Checksum;
|
||||
|
||||
// NOTE: The MAC value is preserved after doFinal
|
||||
private byte[] macBlock;
|
||||
|
||||
public OcbBlockCipher(IBlockCipher hashCipher, IBlockCipher mainCipher)
|
||||
{
|
||||
if (hashCipher == null)
|
||||
throw new ArgumentNullException("hashCipher");
|
||||
if (hashCipher.GetBlockSize() != BLOCK_SIZE)
|
||||
throw new ArgumentException("must have a block size of " + BLOCK_SIZE, "hashCipher");
|
||||
if (mainCipher == null)
|
||||
throw new ArgumentNullException("mainCipher");
|
||||
if (mainCipher.GetBlockSize() != BLOCK_SIZE)
|
||||
throw new ArgumentException("must have a block size of " + BLOCK_SIZE, "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 string AlgorithmName => mainCipher.AlgorithmName + "/OCB";
|
||||
|
||||
public virtual IBlockCipher UnderlyingCipher => mainCipher;
|
||||
|
||||
public virtual void Init(bool forEncryption, ICipherParameters parameters)
|
||||
{
|
||||
bool oldForEncryption = this.forEncryption;
|
||||
this.forEncryption = forEncryption;
|
||||
this.macBlock = null;
|
||||
|
||||
KeyParameter keyParameter;
|
||||
|
||||
byte[] N;
|
||||
if (parameters is AeadParameters aeadParameters)
|
||||
{
|
||||
N = aeadParameters.GetNonce();
|
||||
initialAssociatedText = aeadParameters.GetAssociatedText();
|
||||
|
||||
int macSizeBits = aeadParameters.MacSize;
|
||||
if (macSizeBits < 64 || macSizeBits > 128 || macSizeBits % 8 != 0)
|
||||
throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
|
||||
|
||||
macSize = macSizeBits / 8;
|
||||
keyParameter = aeadParameters.Key;
|
||||
}
|
||||
else if (parameters is ParametersWithIV parametersWithIV)
|
||||
{
|
||||
N = parametersWithIV.GetIV();
|
||||
initialAssociatedText = null;
|
||||
macSize = 16;
|
||||
keyParameter = (KeyParameter) parametersWithIV.Parameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("invalid parameters passed to OCB");
|
||||
}
|
||||
|
||||
this.hashBlock = new byte[16];
|
||||
this.mainBlock = new byte[forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize)];
|
||||
|
||||
if (N == null)
|
||||
{
|
||||
N = new byte[0];
|
||||
}
|
||||
|
||||
if (N.Length > 15)
|
||||
{
|
||||
throw new ArgumentException("IV must be no more than 15 bytes");
|
||||
}
|
||||
|
||||
/*
|
||||
* KEY-DEPENDENT INITIALISATION
|
||||
*/
|
||||
|
||||
if (keyParameter != null)
|
||||
{
|
||||
// hashCipher always used in forward mode
|
||||
hashCipher.Init(true, keyParameter);
|
||||
mainCipher.Init(forEncryption, keyParameter);
|
||||
KtopInput = null;
|
||||
}
|
||||
else if (oldForEncryption != forEncryption)
|
||||
{
|
||||
throw new ArgumentException("cannot change encrypting state without providing key.");
|
||||
}
|
||||
|
||||
this.L_Asterisk = new byte[16];
|
||||
hashCipher.ProcessBlock(L_Asterisk, 0, L_Asterisk, 0);
|
||||
|
||||
this.L_Dollar = OCB_double(L_Asterisk);
|
||||
|
||||
this.L = new List<byte[]>();
|
||||
this.L.Add(OCB_double(L_Dollar));
|
||||
|
||||
/*
|
||||
* NONCE-DEPENDENT AND PER-ENCRYPTION/DECRYPTION INITIALISATION
|
||||
*/
|
||||
|
||||
int bottom = ProcessNonce(N);
|
||||
|
||||
int bits = bottom % 8, bytes = bottom / 8;
|
||||
if (bits == 0)
|
||||
{
|
||||
Array.Copy(Stretch, bytes, OffsetMAIN_0, 0, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
uint b1 = Stretch[bytes];
|
||||
uint b2 = Stretch[++bytes];
|
||||
this.OffsetMAIN_0[i] = (byte) ((b1 << bits) | (b2 >> (8 - bits)));
|
||||
}
|
||||
}
|
||||
|
||||
this.hashBlockPos = 0;
|
||||
this.mainBlockPos = 0;
|
||||
|
||||
this.hashBlockCount = 0;
|
||||
this.mainBlockCount = 0;
|
||||
|
||||
this.OffsetHASH = new byte[16];
|
||||
this.Sum = new byte[16];
|
||||
Array.Copy(OffsetMAIN_0, 0, OffsetMAIN, 0, 16);
|
||||
this.Checksum = new byte[16];
|
||||
|
||||
if (initialAssociatedText != null)
|
||||
{
|
||||
ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual int ProcessNonce(byte[] N)
|
||||
{
|
||||
byte[] nonce = new byte[16];
|
||||
Array.Copy(N, 0, nonce, nonce.Length - N.Length, N.Length);
|
||||
nonce[0] = (byte)(macSize << 4);
|
||||
nonce[15 - N.Length] |= 1;
|
||||
|
||||
int bottom = nonce[15] & 0x3F;
|
||||
nonce[15] &= 0xC0;
|
||||
|
||||
/*
|
||||
* When used with incrementing nonces, the cipher is only applied once every 64 inits.
|
||||
*/
|
||||
if (KtopInput == null || !Arrays.AreEqual(nonce, KtopInput))
|
||||
{
|
||||
byte[] Ktop = new byte[16];
|
||||
KtopInput = nonce;
|
||||
hashCipher.ProcessBlock(KtopInput, 0, Ktop, 0);
|
||||
Array.Copy(Ktop, 0, Stretch, 0, 16);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
Stretch[16 + i] = (byte)(Ktop[i] ^ Ktop[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
return bottom;
|
||||
}
|
||||
|
||||
public virtual int GetBlockSize()
|
||||
{
|
||||
return BLOCK_SIZE;
|
||||
}
|
||||
|
||||
public virtual byte[] GetMac()
|
||||
{
|
||||
return macBlock == null
|
||||
? new byte[macSize]
|
||||
: Arrays.Clone(macBlock);
|
||||
}
|
||||
|
||||
public virtual int GetOutputSize(int len)
|
||||
{
|
||||
int totalData = len + mainBlockPos;
|
||||
if (forEncryption)
|
||||
{
|
||||
return totalData + macSize;
|
||||
}
|
||||
return totalData < macSize ? 0 : totalData - macSize;
|
||||
}
|
||||
|
||||
public virtual int GetUpdateOutputSize(int len)
|
||||
{
|
||||
int totalData = len + mainBlockPos;
|
||||
if (!forEncryption)
|
||||
{
|
||||
if (totalData < macSize)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
totalData -= macSize;
|
||||
}
|
||||
return totalData - totalData % BLOCK_SIZE;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
|
||||
{
|
||||
for (int i = 0; i < input.Length; ++i)
|
||||
{
|
||||
hashBlock[hashBlockPos] = input[i];
|
||||
if (++hashBlockPos == hashBlock.Length)
|
||||
{
|
||||
ProcessHashBlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual int ProcessByte(byte input, byte[] output, int outOff)
|
||||
{
|
||||
mainBlock[mainBlockPos] = input;
|
||||
if (++mainBlockPos == mainBlock.Length)
|
||||
{
|
||||
ProcessMainBlock(output, outOff);
|
||||
return BLOCK_SIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int ProcessByte(byte input, Span<byte> output)
|
||||
{
|
||||
mainBlock[mainBlockPos] = input;
|
||||
if (++mainBlockPos == mainBlock.Length)
|
||||
{
|
||||
ProcessMainBlock(output);
|
||||
return BLOCK_SIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
|
||||
{
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return ProcessBytes(input.AsSpan(inOff, len), Spans.FromNullable(output, outOff));
|
||||
#else
|
||||
int resultLen = 0;
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
mainBlock[mainBlockPos] = input[inOff + i];
|
||||
if (++mainBlockPos == mainBlock.Length)
|
||||
{
|
||||
ProcessMainBlock(output, outOff + resultLen);
|
||||
resultLen += BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
return resultLen;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
int len = input.Length;
|
||||
int resultLen = 0;
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
mainBlock[mainBlockPos] = input[i];
|
||||
if (++mainBlockPos == mainBlock.Length)
|
||||
{
|
||||
ProcessMainBlock(output[resultLen..]);
|
||||
resultLen += BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual int DoFinal(byte[] output, int outOff)
|
||||
{
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return DoFinal(output.AsSpan(outOff));
|
||||
#else
|
||||
/*
|
||||
* For decryption, get the tag from the end of the message
|
||||
*/
|
||||
byte[] tag = null;
|
||||
if (!forEncryption) {
|
||||
if (mainBlockPos < macSize)
|
||||
throw new InvalidCipherTextException("data too short");
|
||||
|
||||
mainBlockPos -= macSize;
|
||||
tag = new byte[macSize];
|
||||
Array.Copy(mainBlock, mainBlockPos, tag, 0, macSize);
|
||||
}
|
||||
|
||||
/*
|
||||
* HASH: Process any final partial block; compute final hash value
|
||||
*/
|
||||
if (hashBlockPos > 0)
|
||||
{
|
||||
OCB_extend(hashBlock, hashBlockPos);
|
||||
UpdateHASH(L_Asterisk);
|
||||
}
|
||||
|
||||
/*
|
||||
* OCB-ENCRYPT/OCB-DECRYPT: Process any final partial block
|
||||
*/
|
||||
if (mainBlockPos > 0)
|
||||
{
|
||||
if (forEncryption)
|
||||
{
|
||||
OCB_extend(mainBlock, mainBlockPos);
|
||||
Xor(Checksum, mainBlock);
|
||||
}
|
||||
|
||||
Xor(OffsetMAIN, L_Asterisk);
|
||||
|
||||
byte[] Pad = new byte[16];
|
||||
hashCipher.ProcessBlock(OffsetMAIN, 0, Pad, 0);
|
||||
|
||||
Xor(mainBlock, Pad);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OCB-ENCRYPT/OCB-DECRYPT: Compute raw tag
|
||||
*/
|
||||
Xor(Checksum, OffsetMAIN);
|
||||
Xor(Checksum, L_Dollar);
|
||||
hashCipher.ProcessBlock(Checksum, 0, Checksum, 0);
|
||||
Xor(Checksum, Sum);
|
||||
|
||||
this.macBlock = new byte[macSize];
|
||||
Array.Copy(Checksum, 0, macBlock, 0, macSize);
|
||||
|
||||
/*
|
||||
* Validate or append tag and reset this cipher for the next run
|
||||
*/
|
||||
int resultLen = mainBlockPos;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
Check.OutputLength(output, outOff, resultLen + macSize, "output buffer too short");
|
||||
|
||||
// Append tag to the message
|
||||
Array.Copy(macBlock, 0, output, outOff + resultLen, macSize);
|
||||
resultLen += macSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compare the tag from the message with the calculated one
|
||||
if (!Arrays.ConstantTimeAreEqual(macBlock, tag))
|
||||
throw new InvalidCipherTextException("mac check in OCB failed");
|
||||
}
|
||||
|
||||
Reset(false);
|
||||
|
||||
return resultLen;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int DoFinal(Span<byte> output)
|
||||
{
|
||||
/*
|
||||
* For decryption, get the tag from the end of the message
|
||||
*/
|
||||
byte[] tag = null;
|
||||
if (!forEncryption)
|
||||
{
|
||||
if (mainBlockPos < macSize)
|
||||
throw new InvalidCipherTextException("data too short");
|
||||
|
||||
mainBlockPos -= macSize;
|
||||
tag = new byte[macSize];
|
||||
Array.Copy(mainBlock, mainBlockPos, tag, 0, macSize);
|
||||
}
|
||||
|
||||
/*
|
||||
* HASH: Process any final partial block; compute final hash value
|
||||
*/
|
||||
if (hashBlockPos > 0)
|
||||
{
|
||||
OCB_extend(hashBlock, hashBlockPos);
|
||||
UpdateHASH(L_Asterisk);
|
||||
}
|
||||
|
||||
/*
|
||||
* OCB-ENCRYPT/OCB-DECRYPT: Process any final partial block
|
||||
*/
|
||||
if (mainBlockPos > 0)
|
||||
{
|
||||
if (forEncryption)
|
||||
{
|
||||
OCB_extend(mainBlock, mainBlockPos);
|
||||
Xor(Checksum, mainBlock);
|
||||
}
|
||||
|
||||
Xor(OffsetMAIN, L_Asterisk);
|
||||
|
||||
byte[] Pad = new byte[16];
|
||||
hashCipher.ProcessBlock(OffsetMAIN, 0, Pad, 0);
|
||||
|
||||
Xor(mainBlock, Pad);
|
||||
|
||||
Check.OutputLength(output, mainBlockPos, "output buffer too short");
|
||||
mainBlock.AsSpan(0, mainBlockPos).CopyTo(output);
|
||||
|
||||
if (!forEncryption)
|
||||
{
|
||||
OCB_extend(mainBlock, mainBlockPos);
|
||||
Xor(Checksum, mainBlock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OCB-ENCRYPT/OCB-DECRYPT: Compute raw tag
|
||||
*/
|
||||
Xor(Checksum, OffsetMAIN);
|
||||
Xor(Checksum, L_Dollar);
|
||||
hashCipher.ProcessBlock(Checksum, 0, Checksum, 0);
|
||||
Xor(Checksum, Sum);
|
||||
|
||||
this.macBlock = new byte[macSize];
|
||||
Array.Copy(Checksum, 0, macBlock, 0, macSize);
|
||||
|
||||
/*
|
||||
* Validate or append tag and reset this cipher for the next run
|
||||
*/
|
||||
int resultLen = mainBlockPos;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
// Append tag to the message
|
||||
Check.OutputLength(output, resultLen + macSize, "output buffer too short");
|
||||
macBlock.AsSpan(0, macSize).CopyTo(output[resultLen..]);
|
||||
resultLen += macSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compare the tag from the message with the calculated one
|
||||
if (!Arrays.ConstantTimeAreEqual(macBlock, tag))
|
||||
throw new InvalidCipherTextException("mac check in OCB failed");
|
||||
}
|
||||
|
||||
Reset(false);
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
Reset(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(L[L.Count - 1]));
|
||||
}
|
||||
return L[n];
|
||||
}
|
||||
|
||||
protected virtual void ProcessHashBlock()
|
||||
{
|
||||
/*
|
||||
* HASH: Process any whole blocks
|
||||
*/
|
||||
UpdateHASH(GetLSub(OCB_ntz(++hashBlockCount)));
|
||||
hashBlockPos = 0;
|
||||
}
|
||||
|
||||
protected virtual void ProcessMainBlock(byte[] output, int outOff)
|
||||
{
|
||||
Check.DataLength(output, outOff, BLOCK_SIZE, "Output buffer too short");
|
||||
|
||||
/*
|
||||
* OCB-ENCRYPT/OCB-DECRYPT: Process any whole blocks
|
||||
*/
|
||||
|
||||
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, BLOCK_SIZE, mainBlock, 0, macSize);
|
||||
mainBlockPos = macSize;
|
||||
}
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
protected virtual void ProcessMainBlock(Span<byte> output)
|
||||
{
|
||||
Check.DataLength(output, BLOCK_SIZE, "output buffer too short");
|
||||
|
||||
/*
|
||||
* OCB-ENCRYPT/OCB-DECRYPT: Process any whole blocks
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
mainBlock.AsSpan(0, BLOCK_SIZE).CopyTo(output);
|
||||
|
||||
if (!forEncryption)
|
||||
{
|
||||
Xor(Checksum, mainBlock);
|
||||
Array.Copy(mainBlock, BLOCK_SIZE, mainBlock, 0, macSize);
|
||||
mainBlockPos = macSize;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
protected virtual void Reset(bool clearMac)
|
||||
{
|
||||
Clear(hashBlock);
|
||||
Clear(mainBlock);
|
||||
|
||||
hashBlockPos = 0;
|
||||
mainBlockPos = 0;
|
||||
|
||||
hashBlockCount = 0;
|
||||
mainBlockCount = 0;
|
||||
|
||||
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[] result = new byte[16];
|
||||
int carry = ShiftLeft(block, result);
|
||||
|
||||
/*
|
||||
* NOTE: This construction is an attempt at a constant-time implementation.
|
||||
*/
|
||||
result[15] ^= (byte)(0x87 >> ((1 - carry) << 3));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected static void OCB_extend(byte[] block, int pos)
|
||||
{
|
||||
block[pos] = (byte) 0x80;
|
||||
while (++pos < 16)
|
||||
{
|
||||
block[pos] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected static int OCB_ntz(long x)
|
||||
{
|
||||
if (x == 0)
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
ulong ux = (ulong)x;
|
||||
while ((ux & 1UL) == 0UL)
|
||||
{
|
||||
++n;
|
||||
ux >>= 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
protected static int ShiftLeft(byte[] block, byte[] output)
|
||||
{
|
||||
int i = 16;
|
||||
uint bit = 0;
|
||||
while (--i >= 0)
|
||||
{
|
||||
uint b = block[i];
|
||||
output[i] = (byte) ((b << 1) | bit);
|
||||
bit = (b >> 7) & 1;
|
||||
}
|
||||
return (int)bit;
|
||||
}
|
||||
|
||||
protected static void Xor(byte[] block, byte[] val)
|
||||
{
|
||||
for (int i = 15; i >= 0; --i)
|
||||
{
|
||||
block[i] ^= val[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/OCBBlockCipher.cs.meta
vendored
Normal file
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/OCBBlockCipher.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2230f3f7676b64c429e0e63970bc1554
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
182
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/OfbBlockCipher.cs
vendored
Normal file
182
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/OfbBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* implements a Output-FeedBack (OFB) mode on top of a simple cipher.
|
||||
*/
|
||||
public class OfbBlockCipher
|
||||
: IBlockCipherMode
|
||||
{
|
||||
private byte[] IV;
|
||||
private byte[] ofbV;
|
||||
private byte[] ofbOutV;
|
||||
|
||||
private readonly int blockSize;
|
||||
private readonly IBlockCipher cipher;
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used as the basis of the
|
||||
* feedback mode.
|
||||
* @param blockSize the block size in bits (note: a multiple of 8)
|
||||
*/
|
||||
public OfbBlockCipher(
|
||||
IBlockCipher cipher,
|
||||
int blockSize)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.blockSize = blockSize / 8;
|
||||
|
||||
this.IV = new byte[cipher.GetBlockSize()];
|
||||
this.ofbV = new byte[cipher.GetBlockSize()];
|
||||
this.ofbOutV = new byte[cipher.GetBlockSize()];
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public IBlockCipher UnderlyingCipher => cipher;
|
||||
|
||||
/**
|
||||
* Initialise the cipher and, possibly, the initialisation vector (IV).
|
||||
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
|
||||
* An IV which is too short is handled in FIPS compliant fashion.
|
||||
*
|
||||
* @param forEncryption if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param param the key and other data required by the cipher.
|
||||
* @exception ArgumentException if the parameters argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void Init(
|
||||
bool forEncryption, //ignored by this OFB mode
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
if (parameters is ParametersWithIV ivParam)
|
||||
{
|
||||
byte[] iv = ivParam.GetIV();
|
||||
|
||||
if (iv.Length < IV.Length)
|
||||
{
|
||||
// prepend the supplied IV with zeros (per FIPS PUB 81)
|
||||
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 = ivParam.Parameters;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
// if it's null, key is to be reused.
|
||||
if (parameters != null)
|
||||
{
|
||||
cipher.Init(true, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the algorithm name and mode.
|
||||
*
|
||||
* @return the name of the underlying algorithm followed by "/OFB"
|
||||
* and the block size in bits
|
||||
*/
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/OFB" + (blockSize * 8); }
|
||||
}
|
||||
|
||||
public bool IsPartialBlockOkay
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block size we are operating at (in bytes).
|
||||
*
|
||||
* @return the block size we are operating at (in bytes).
|
||||
*/
|
||||
public int GetBlockSize()
|
||||
{
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
|
||||
{
|
||||
Check.DataLength(input, inOff, blockSize, "input buffer too short");
|
||||
Check.OutputLength(output, outOff, blockSize, "output buffer too short");
|
||||
|
||||
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
|
||||
|
||||
//
|
||||
// XOR the ofbV with the plaintext producing the cipher text (and
|
||||
// the next input block).
|
||||
//
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]);
|
||||
}
|
||||
|
||||
//
|
||||
// change over the input block.
|
||||
//
|
||||
Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
|
||||
Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
Check.DataLength(input, blockSize, "input buffer too short");
|
||||
Check.OutputLength(output, blockSize, "output buffer too short");
|
||||
|
||||
cipher.ProcessBlock(ofbV, ofbOutV);
|
||||
|
||||
//
|
||||
// XOR the ofbV with the plaintext producing the cipher text (and
|
||||
// the next input block).
|
||||
//
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
output[i] = (byte)(ofbOutV[i] ^ input[i]);
|
||||
}
|
||||
|
||||
//
|
||||
// change over the input block.
|
||||
//
|
||||
Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
|
||||
Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* reset the feedback vector back to the IV and reset the underlying
|
||||
* cipher.
|
||||
*/
|
||||
public void Reset()
|
||||
{
|
||||
Array.Copy(IV, 0, ofbV, 0, IV.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/OfbBlockCipher.cs.meta
vendored
Normal file
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/OfbBlockCipher.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 155ab1dea42532a47bb238a7232b5908
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
409
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/OpenPgpCfbBlockCipher.cs
vendored
Normal file
409
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/OpenPgpCfbBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,409 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* Implements OpenPGP's rather strange version of Cipher-FeedBack (CFB) mode
|
||||
* on top of a simple cipher. This class assumes the IV has been prepended
|
||||
* to the data stream already, and just accomodates the reset after
|
||||
* (blockSize + 2) bytes have been read.
|
||||
* <p>
|
||||
* For further info see <a href="http://www.ietf.org/rfc/rfc2440.html">RFC 2440</a>.
|
||||
* </p>
|
||||
*/
|
||||
public class OpenPgpCfbBlockCipher
|
||||
: IBlockCipherMode
|
||||
{
|
||||
private byte[] IV;
|
||||
private byte[] FR;
|
||||
private byte[] FRE;
|
||||
|
||||
private readonly IBlockCipher cipher;
|
||||
private readonly int blockSize;
|
||||
|
||||
private int count;
|
||||
private bool forEncryption;
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used as the basis of the
|
||||
* feedback mode.
|
||||
*/
|
||||
public OpenPgpCfbBlockCipher(
|
||||
IBlockCipher cipher)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
|
||||
this.blockSize = cipher.GetBlockSize();
|
||||
this.IV = new byte[blockSize];
|
||||
this.FR = new byte[blockSize];
|
||||
this.FRE = new byte[blockSize];
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public IBlockCipher UnderlyingCipher => cipher;
|
||||
|
||||
/**
|
||||
* return the algorithm name and mode.
|
||||
*
|
||||
* @return the name of the underlying algorithm followed by "/PGPCFB"
|
||||
* and the block size in bits.
|
||||
*/
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/OpenPGPCFB"; }
|
||||
}
|
||||
|
||||
public bool IsPartialBlockOkay
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block size we are operating at.
|
||||
*
|
||||
* @return the block size we are operating at (in bytes).
|
||||
*/
|
||||
public int GetBlockSize()
|
||||
{
|
||||
return cipher.GetBlockSize();
|
||||
}
|
||||
|
||||
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
|
||||
{
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return forEncryption
|
||||
? EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff))
|
||||
: DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
|
||||
#else
|
||||
return forEncryption
|
||||
? EncryptBlock(input, inOff, output, outOff)
|
||||
: DecryptBlock(input, inOff, output, outOff);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
return forEncryption
|
||||
? EncryptBlock(input, output)
|
||||
: DecryptBlock(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* reset the chaining vector back to the IV and reset the underlying
|
||||
* cipher.
|
||||
*/
|
||||
public void Reset()
|
||||
{
|
||||
count = 0;
|
||||
|
||||
Array.Copy(IV, 0, FR, 0, FR.Length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the cipher and, possibly, the initialisation vector (IV).
|
||||
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
|
||||
* An IV which is too short is handled in FIPS compliant fashion.
|
||||
*
|
||||
* @param forEncryption if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param parameters the key and other data required by the cipher.
|
||||
* @exception ArgumentException if the parameters argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void Init(bool forEncryption, ICipherParameters parameters)
|
||||
{
|
||||
this.forEncryption = forEncryption;
|
||||
|
||||
if (parameters is ParametersWithIV ivParam)
|
||||
{
|
||||
byte[] iv = ivParam.GetIV();
|
||||
|
||||
if (iv.Length < IV.Length)
|
||||
{
|
||||
// prepend the supplied IV with zeros (per FIPS PUB 81)
|
||||
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 = ivParam.Parameters;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
cipher.Init(true, parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt one byte of data according to CFB mode.
|
||||
* @param data the byte to encrypt
|
||||
* @param blockOff offset in the current block
|
||||
* @returns the encrypted byte
|
||||
*/
|
||||
private byte EncryptByte(byte data, int blockOff)
|
||||
{
|
||||
return (byte)(FRE[blockOff] ^ data);
|
||||
}
|
||||
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
Check.DataLength(input, blockSize, "input buffer too short");
|
||||
Check.OutputLength(output, blockSize, "output buffer too short");
|
||||
|
||||
if (count > blockSize)
|
||||
{
|
||||
FR[blockSize - 2] = output[0] = EncryptByte(input[0], blockSize - 2);
|
||||
FR[blockSize - 1] = output[1] = EncryptByte(input[1], blockSize - 1);
|
||||
|
||||
cipher.ProcessBlock(FR, FRE);
|
||||
|
||||
for (int n = 2; n < blockSize; n++)
|
||||
{
|
||||
FR[n - 2] = output[n] = EncryptByte(input[n], n - 2);
|
||||
}
|
||||
}
|
||||
else if (count == 0)
|
||||
{
|
||||
cipher.ProcessBlock(FR, FRE);
|
||||
|
||||
for (int n = 0; n < blockSize; n++)
|
||||
{
|
||||
FR[n] = output[n] = EncryptByte(input[n], n);
|
||||
}
|
||||
|
||||
count += blockSize;
|
||||
}
|
||||
else if (count == blockSize)
|
||||
{
|
||||
cipher.ProcessBlock(FR, FRE);
|
||||
|
||||
output[0] = EncryptByte(input[0], 0);
|
||||
output[1] = EncryptByte(input[1], 1);
|
||||
|
||||
//
|
||||
// do reset
|
||||
//
|
||||
Array.Copy(FR, 2, FR, 0, blockSize - 2);
|
||||
output[..2].CopyTo(FR.AsSpan(blockSize - 2));
|
||||
|
||||
cipher.ProcessBlock(FR, FRE);
|
||||
|
||||
for (int n = 2; n < blockSize; n++)
|
||||
{
|
||||
FR[n - 2] = output[n] = EncryptByte(input[n], n - 2);
|
||||
}
|
||||
|
||||
count += blockSize;
|
||||
}
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
Check.DataLength(input, blockSize, "input buffer too short");
|
||||
Check.OutputLength(output, blockSize, "output buffer too short");
|
||||
|
||||
if (count > blockSize)
|
||||
{
|
||||
byte inVal = input[0];
|
||||
FR[blockSize - 2] = inVal;
|
||||
output[0] = EncryptByte(inVal, blockSize - 2);
|
||||
|
||||
inVal = input[1];
|
||||
FR[blockSize - 1] = inVal;
|
||||
output[1] = EncryptByte(inVal, blockSize - 1);
|
||||
|
||||
cipher.ProcessBlock(FR, FRE);
|
||||
|
||||
for (int n = 2; n < blockSize; n++)
|
||||
{
|
||||
inVal = input[n];
|
||||
FR[n - 2] = inVal;
|
||||
output[n] = EncryptByte(inVal, n - 2);
|
||||
}
|
||||
}
|
||||
else if (count == 0)
|
||||
{
|
||||
cipher.ProcessBlock(FR, FRE);
|
||||
|
||||
for (int n = 0; n < blockSize; n++)
|
||||
{
|
||||
FR[n] = input[n];
|
||||
output[n] = EncryptByte(input[n], n);
|
||||
}
|
||||
|
||||
count += blockSize;
|
||||
}
|
||||
else if (count == blockSize)
|
||||
{
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
byte inVal1 = input[0];
|
||||
byte inVal2 = input[1];
|
||||
output[0] = EncryptByte(inVal1, 0);
|
||||
output[1] = EncryptByte(inVal2, 1);
|
||||
|
||||
Array.Copy(FR, 2, FR, 0, blockSize - 2);
|
||||
|
||||
FR[blockSize - 2] = inVal1;
|
||||
FR[blockSize - 1] = inVal2;
|
||||
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
for (int n = 2; n < blockSize; n++)
|
||||
{
|
||||
byte inVal = input[n];
|
||||
FR[n - 2] = inVal;
|
||||
output[n] = EncryptByte(inVal, n - 2);
|
||||
}
|
||||
|
||||
count += blockSize;
|
||||
}
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
#else
|
||||
private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
|
||||
{
|
||||
Check.DataLength(input, inOff, blockSize, "input buffer too short");
|
||||
Check.OutputLength(outBytes, outOff, blockSize, "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 n = 2; n < blockSize; n++)
|
||||
{
|
||||
FR[n - 2] = outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2);
|
||||
}
|
||||
}
|
||||
else if (count == 0)
|
||||
{
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
for (int n = 0; n < blockSize; n++)
|
||||
{
|
||||
FR[n] = outBytes[outOff + n] = EncryptByte(input[inOff + n], n);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
//
|
||||
// do reset
|
||||
//
|
||||
Array.Copy(FR, 2, FR, 0, blockSize - 2);
|
||||
Array.Copy(outBytes, outOff, FR, blockSize - 2, 2);
|
||||
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
for (int n = 2; n < blockSize; n++)
|
||||
{
|
||||
FR[n - 2] = outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2);
|
||||
}
|
||||
|
||||
count += blockSize;
|
||||
}
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
|
||||
{
|
||||
Check.DataLength(input, inOff, blockSize, "input buffer too short");
|
||||
Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
|
||||
|
||||
if (count > blockSize)
|
||||
{
|
||||
byte inVal = input[inOff];
|
||||
FR[blockSize - 2] = inVal;
|
||||
outBytes[outOff] = EncryptByte(inVal, blockSize - 2);
|
||||
|
||||
inVal = input[inOff + 1];
|
||||
FR[blockSize - 1] = inVal;
|
||||
outBytes[outOff + 1] = EncryptByte(inVal, blockSize - 1);
|
||||
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
for (int n = 2; n < blockSize; n++)
|
||||
{
|
||||
inVal = input[inOff + n];
|
||||
FR[n - 2] = inVal;
|
||||
outBytes[outOff + n] = EncryptByte(inVal, n - 2);
|
||||
}
|
||||
}
|
||||
else if (count == 0)
|
||||
{
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
for (int n = 0; n < blockSize; n++)
|
||||
{
|
||||
FR[n] = input[inOff + n];
|
||||
outBytes[outOff + n] = EncryptByte(input[inOff + n], n);
|
||||
}
|
||||
|
||||
count += blockSize;
|
||||
}
|
||||
else if (count == blockSize)
|
||||
{
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
byte inVal1 = input[inOff];
|
||||
byte inVal2 = input[inOff + 1];
|
||||
outBytes[outOff ] = EncryptByte(inVal1, 0);
|
||||
outBytes[outOff + 1] = EncryptByte(inVal2, 1);
|
||||
|
||||
Array.Copy(FR, 2, FR, 0, blockSize - 2);
|
||||
|
||||
FR[blockSize - 2] = inVal1;
|
||||
FR[blockSize - 1] = inVal2;
|
||||
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
for (int n = 2; n < blockSize; n++)
|
||||
{
|
||||
byte inVal = input[inOff + n];
|
||||
FR[n - 2] = inVal;
|
||||
outBytes[outOff + n] = EncryptByte(inVal, n - 2);
|
||||
}
|
||||
|
||||
count += blockSize;
|
||||
}
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5cda7b7eef6b9442b7823faaccbbd70
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
139
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/SicBlockCipher.cs
vendored
Normal file
139
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/SicBlockCipher.cs
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* Implements the Segmented Integer Counter (SIC) mode on top of a simple
|
||||
* block cipher.
|
||||
*/
|
||||
public class SicBlockCipher
|
||||
: IBlockCipherMode
|
||||
{
|
||||
private readonly IBlockCipher cipher;
|
||||
private readonly int blockSize;
|
||||
private readonly byte[] counter;
|
||||
private readonly byte[] counterOut;
|
||||
private byte[] IV;
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param c the block cipher to be used.
|
||||
*/
|
||||
public SicBlockCipher(IBlockCipher cipher)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.blockSize = cipher.GetBlockSize();
|
||||
this.counter = new byte[blockSize];
|
||||
this.counterOut = new byte[blockSize];
|
||||
this.IV = new byte[blockSize];
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public IBlockCipher UnderlyingCipher => cipher;
|
||||
|
||||
public virtual void Init(
|
||||
bool forEncryption, //ignored by this CTR mode
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
ParametersWithIV ivParam = parameters as ParametersWithIV;
|
||||
if (ivParam == null)
|
||||
throw new ArgumentException("CTR/SIC mode requires ParametersWithIV", "parameters");
|
||||
|
||||
this.IV = Arrays.Clone(ivParam.GetIV());
|
||||
|
||||
if (blockSize < IV.Length)
|
||||
throw new ArgumentException("CTR/SIC mode requires IV no greater than: " + blockSize + " bytes.");
|
||||
|
||||
int maxCounterSize = System.Math.Min(8, blockSize / 2);
|
||||
if (blockSize - IV.Length > maxCounterSize)
|
||||
throw new ArgumentException("CTR/SIC mode requires IV of at least: " + (blockSize - maxCounterSize) + " bytes.");
|
||||
|
||||
// if null it's an IV changed only.
|
||||
if (ivParam.Parameters != null)
|
||||
{
|
||||
cipher.Init(true, ivParam.Parameters);
|
||||
}
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public virtual string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/SIC"; }
|
||||
}
|
||||
|
||||
public virtual bool IsPartialBlockOkay
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
//
|
||||
// XOR the counterOut with the plaintext producing the cipher text
|
||||
//
|
||||
for (int i = 0; i < counterOut.Length; i++)
|
||||
{
|
||||
output[outOff + i] = (byte)(counterOut[i] ^ input[inOff + i]);
|
||||
}
|
||||
|
||||
// Increment the counter
|
||||
int j = counter.Length;
|
||||
while (--j >= 0 && ++counter[j] == 0)
|
||||
{
|
||||
}
|
||||
|
||||
return counter.Length;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
cipher.ProcessBlock(counter, 0, counterOut, 0);
|
||||
|
||||
//
|
||||
// XOR the counterOut with the plaintext producing the cipher text
|
||||
//
|
||||
for (int i = 0; i < counterOut.Length; i++)
|
||||
{
|
||||
output[i] = (byte)(counterOut[i] ^ input[i]);
|
||||
}
|
||||
|
||||
// Increment the counter
|
||||
int j = counter.Length;
|
||||
while (--j >= 0 && ++counter[j] == 0)
|
||||
{
|
||||
}
|
||||
|
||||
return counter.Length;
|
||||
}
|
||||
#endif
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
Arrays.Fill(counter, (byte)0);
|
||||
Array.Copy(IV, 0, counter, 0, IV.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/SicBlockCipher.cs.meta
vendored
Normal file
11
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/SicBlockCipher.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e5d0376c6b84f343ae4ebb978626670
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/gcm.meta
vendored
Normal file
8
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/gcm.meta
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ff0bc1a8cbd285449fb86b525082d47
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,42 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes.Gcm
|
||||
{
|
||||
public class BasicGcmExponentiator
|
||||
: IGcmExponentiator
|
||||
{
|
||||
private GcmUtilities.FieldElement x;
|
||||
|
||||
public void Init(byte[] x)
|
||||
{
|
||||
GcmUtilities.AsFieldElement(x, out this.x);
|
||||
}
|
||||
|
||||
public void ExponentiateX(long pow, byte[] output)
|
||||
{
|
||||
GcmUtilities.FieldElement y;
|
||||
GcmUtilities.One(out y);
|
||||
|
||||
if (pow > 0)
|
||||
{
|
||||
GcmUtilities.FieldElement powX = x;
|
||||
do
|
||||
{
|
||||
if ((pow & 1L) != 0)
|
||||
{
|
||||
GcmUtilities.Multiply(ref y, ref powX);
|
||||
}
|
||||
GcmUtilities.Square(ref powX);
|
||||
pow >>= 1;
|
||||
}
|
||||
while (pow > 0);
|
||||
}
|
||||
|
||||
GcmUtilities.AsBytes(ref y, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32321bd134c65cc4cac0fb4bde7e360d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,26 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes.Gcm
|
||||
{
|
||||
public class BasicGcmMultiplier
|
||||
: IGcmMultiplier
|
||||
{
|
||||
private GcmUtilities.FieldElement H;
|
||||
|
||||
public void Init(byte[] H)
|
||||
{
|
||||
GcmUtilities.AsFieldElement(H, out this.H);
|
||||
}
|
||||
|
||||
public void MultiplyH(byte[] x)
|
||||
{
|
||||
GcmUtilities.AsFieldElement(x, out var T);
|
||||
GcmUtilities.Multiply(ref T, ref H);
|
||||
GcmUtilities.AsBytes(ref T, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f85532d10251c946bc54a31bd727126
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
302
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/gcm/GcmUtilities.cs
vendored
Normal file
302
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/gcm/GcmUtilities.cs
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
using System.Runtime.CompilerServices;
|
||||
#endif
|
||||
#if NETCOREAPP3_0_OR_GREATER
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
#endif
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math.Raw;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes.Gcm
|
||||
{
|
||||
internal abstract class GcmUtilities
|
||||
{
|
||||
internal struct FieldElement
|
||||
{
|
||||
internal ulong n0, n1;
|
||||
}
|
||||
|
||||
private const uint E1 = 0xe1000000;
|
||||
private const ulong E1UL = (ulong)E1 << 32;
|
||||
|
||||
internal static void One(out FieldElement x)
|
||||
{
|
||||
x.n0 = 1UL << 63;
|
||||
x.n1 = 0UL;
|
||||
}
|
||||
|
||||
#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
internal static void AsBytes(ulong x0, ulong x1, byte[] z)
|
||||
{
|
||||
Pack.UInt64_To_BE(x0, z, 0);
|
||||
Pack.UInt64_To_BE(x1, z, 8);
|
||||
}
|
||||
|
||||
#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
internal static void AsBytes(ref FieldElement x, byte[] z)
|
||||
{
|
||||
AsBytes(x.n0, x.n1, z);
|
||||
}
|
||||
|
||||
#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
internal static void AsFieldElement(byte[] x, out FieldElement z)
|
||||
{
|
||||
z.n0 = Pack.BE_To_UInt64(x, 0);
|
||||
z.n1 = Pack.BE_To_UInt64(x, 8);
|
||||
}
|
||||
|
||||
internal static void DivideP(ref FieldElement x, out FieldElement z)
|
||||
{
|
||||
ulong x0 = x.n0, x1 = x.n1;
|
||||
ulong m = (ulong)((long)x0 >> 63);
|
||||
x0 ^= (m & E1UL);
|
||||
z.n0 = (x0 << 1) | (x1 >> 63);
|
||||
z.n1 = (x1 << 1) | (ulong)(-(long)m);
|
||||
}
|
||||
|
||||
internal static void Multiply(byte[] x, byte[] y)
|
||||
{
|
||||
AsFieldElement(x, out FieldElement X);
|
||||
AsFieldElement(y, out FieldElement Y);
|
||||
Multiply(ref X, ref Y);
|
||||
AsBytes(ref X, x);
|
||||
}
|
||||
|
||||
internal static void Multiply(ref FieldElement x, ref FieldElement y)
|
||||
{
|
||||
ulong z0, z1, z2, z3;
|
||||
|
||||
#if NETCOREAPP3_0_OR_GREATER
|
||||
if (Pclmulqdq.IsSupported)
|
||||
{
|
||||
var X = Vector128.Create(x.n1, x.n0);
|
||||
var Y = Vector128.Create(y.n1, y.n0);
|
||||
|
||||
var Z0 = Pclmulqdq.CarrylessMultiply(X, Y, 0x00);
|
||||
var Z1 = Sse2.Xor(
|
||||
Pclmulqdq.CarrylessMultiply(X, Y, 0x01),
|
||||
Pclmulqdq.CarrylessMultiply(X, Y, 0x10));
|
||||
var Z2 = Pclmulqdq.CarrylessMultiply(X, Y, 0x11);
|
||||
|
||||
ulong t3 = Z0.GetElement(0);
|
||||
ulong t2 = Z0.GetElement(1) ^ Z1.GetElement(0);
|
||||
ulong t1 = Z2.GetElement(0) ^ Z1.GetElement(1);
|
||||
ulong t0 = Z2.GetElement(1);
|
||||
|
||||
z0 = (t0 << 1) | (t1 >> 63);
|
||||
z1 = (t1 << 1) | (t2 >> 63);
|
||||
z2 = (t2 << 1) | (t3 >> 63);
|
||||
z3 = (t3 << 1);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* "Three-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
|
||||
*
|
||||
* Without access to the high part of a 64x64 product x * y, we use a bit reversal to calculate it:
|
||||
* rev(x) * rev(y) == rev((x * y) << 1)
|
||||
*/
|
||||
|
||||
ulong x0 = x.n0, x1 = x.n1;
|
||||
ulong y0 = y.n0, y1 = y.n1;
|
||||
ulong x0r = Longs.Reverse(x0), x1r = Longs.Reverse(x1);
|
||||
ulong y0r = Longs.Reverse(y0), y1r = Longs.Reverse(y1);
|
||||
|
||||
ulong h0 = Longs.Reverse(ImplMul64(x0r, y0r));
|
||||
ulong h1 = ImplMul64(x0, y0) << 1;
|
||||
ulong h2 = Longs.Reverse(ImplMul64(x1r, y1r));
|
||||
ulong h3 = ImplMul64(x1, y1) << 1;
|
||||
ulong h4 = Longs.Reverse(ImplMul64(x0r ^ x1r, y0r ^ y1r));
|
||||
ulong h5 = ImplMul64(x0 ^ x1, y0 ^ y1) << 1;
|
||||
|
||||
z0 = h0;
|
||||
z1 = h1 ^ h0 ^ h2 ^ h4;
|
||||
z2 = h2 ^ h1 ^ h3 ^ h5;
|
||||
z3 = h3;
|
||||
}
|
||||
|
||||
Debug.Assert(z3 << 63 == 0);
|
||||
|
||||
z1 ^= z3 ^ (z3 >> 1) ^ (z3 >> 2) ^ (z3 >> 7);
|
||||
// z2 ^= (z3 << 63) ^ (z3 << 62) ^ (z3 << 57);
|
||||
z2 ^= (z3 << 62) ^ (z3 << 57);
|
||||
|
||||
z0 ^= z2 ^ (z2 >> 1) ^ (z2 >> 2) ^ (z2 >> 7);
|
||||
z1 ^= (z2 << 63) ^ (z2 << 62) ^ (z2 << 57);
|
||||
|
||||
x.n0 = z0;
|
||||
x.n1 = z1;
|
||||
}
|
||||
|
||||
internal static void MultiplyP7(ref FieldElement x)
|
||||
{
|
||||
ulong x0 = x.n0, x1 = x.n1;
|
||||
ulong c = x1 << 57;
|
||||
x.n0 = (x0 >> 7) ^ c ^ (c >> 1) ^ (c >> 2) ^ (c >> 7);
|
||||
x.n1 = (x1 >> 7) | (x0 << 57);
|
||||
}
|
||||
|
||||
internal static void MultiplyP8(ref FieldElement x)
|
||||
{
|
||||
ulong x0 = x.n0, x1 = x.n1;
|
||||
ulong c = x1 << 56;
|
||||
x.n0 = (x0 >> 8) ^ c ^ (c >> 1) ^ (c >> 2) ^ (c >> 7);
|
||||
x.n1 = (x1 >> 8) | (x0 << 56);
|
||||
}
|
||||
|
||||
internal static void MultiplyP8(ref FieldElement x, out FieldElement y)
|
||||
{
|
||||
ulong x0 = x.n0, x1 = x.n1;
|
||||
ulong c = x1 << 56;
|
||||
y.n0 = (x0 >> 8) ^ c ^ (c >> 1) ^ (c >> 2) ^ (c >> 7);
|
||||
y.n1 = (x1 >> 8) | (x0 << 56);
|
||||
}
|
||||
|
||||
internal static void MultiplyP16(ref FieldElement x)
|
||||
{
|
||||
ulong x0 = x.n0, x1 = x.n1;
|
||||
ulong c = x1 << 48;
|
||||
x.n0 = (x0 >> 16) ^ c ^ (c >> 1) ^ (c >> 2) ^ (c >> 7);
|
||||
x.n1 = (x1 >> 16) | (x0 << 48);
|
||||
}
|
||||
|
||||
internal static void Square(ref FieldElement x)
|
||||
{
|
||||
ulong z1 = Interleave.Expand64To128Rev(x.n0, out ulong z0);
|
||||
ulong z3 = Interleave.Expand64To128Rev(x.n1, out ulong z2);
|
||||
|
||||
Debug.Assert(z3 << 63 == 0);
|
||||
|
||||
z1 ^= z3 ^ (z3 >> 1) ^ (z3 >> 2) ^ (z3 >> 7);
|
||||
// z2 ^= (z3 << 63) ^ (z3 << 62) ^ (z3 << 57);
|
||||
z2 ^= (z3 << 62) ^ (z3 << 57);
|
||||
|
||||
Debug.Assert(z2 << 63 == 0);
|
||||
|
||||
z0 ^= z2 ^ (z2 >> 1) ^ (z2 >> 2) ^ (z2 >> 7);
|
||||
// z1 ^= (z2 << 63) ^ (z2 << 62) ^ (z2 << 57);
|
||||
z1 ^= (z2 << 62) ^ (z2 << 57);
|
||||
|
||||
x.n0 = z0;
|
||||
x.n1 = z1;
|
||||
}
|
||||
|
||||
internal static void Xor(byte[] x, byte[] y)
|
||||
{
|
||||
int i = 0;
|
||||
do
|
||||
{
|
||||
x[i] ^= y[i]; ++i;
|
||||
x[i] ^= y[i]; ++i;
|
||||
x[i] ^= y[i]; ++i;
|
||||
x[i] ^= y[i]; ++i;
|
||||
}
|
||||
while (i < 16);
|
||||
}
|
||||
|
||||
internal static void Xor(byte[] x, byte[] y, int yOff)
|
||||
{
|
||||
int i = 0;
|
||||
do
|
||||
{
|
||||
x[i] ^= y[yOff + i]; ++i;
|
||||
x[i] ^= y[yOff + i]; ++i;
|
||||
x[i] ^= y[yOff + i]; ++i;
|
||||
x[i] ^= y[yOff + i]; ++i;
|
||||
}
|
||||
while (i < 16);
|
||||
}
|
||||
|
||||
internal static void Xor(byte[] x, byte[] y, int yOff, int yLen)
|
||||
{
|
||||
while (--yLen >= 0)
|
||||
{
|
||||
x[yLen] ^= y[yOff + yLen];
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Xor(byte[] x, int xOff, byte[] y, int yOff, int len)
|
||||
{
|
||||
while (--len >= 0)
|
||||
{
|
||||
x[xOff + len] ^= y[yOff + len];
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Xor(ref FieldElement x, ref FieldElement y)
|
||||
{
|
||||
x.n0 ^= y.n0;
|
||||
x.n1 ^= y.n1;
|
||||
}
|
||||
|
||||
internal static void Xor(ref FieldElement x, ref FieldElement y, out FieldElement z)
|
||||
{
|
||||
z.n0 = x.n0 ^ y.n0;
|
||||
z.n1 = x.n1 ^ y.n1;
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
internal static void Xor(Span<byte> x, ReadOnlySpan<byte> y)
|
||||
{
|
||||
int i = 0;
|
||||
do
|
||||
{
|
||||
x[i] ^= y[i]; ++i;
|
||||
x[i] ^= y[i]; ++i;
|
||||
x[i] ^= y[i]; ++i;
|
||||
x[i] ^= y[i]; ++i;
|
||||
}
|
||||
while (i < 16);
|
||||
}
|
||||
|
||||
internal static void Xor(Span<byte> x, ReadOnlySpan<byte> y, int len)
|
||||
{
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
x[i] ^= y[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private static ulong ImplMul64(ulong x, ulong y)
|
||||
{
|
||||
ulong x0 = x & 0x1111111111111111UL;
|
||||
ulong x1 = x & 0x2222222222222222UL;
|
||||
ulong x2 = x & 0x4444444444444444UL;
|
||||
ulong x3 = x & 0x8888888888888888UL;
|
||||
|
||||
ulong y0 = y & 0x1111111111111111UL;
|
||||
ulong y1 = y & 0x2222222222222222UL;
|
||||
ulong y2 = y & 0x4444444444444444UL;
|
||||
ulong y3 = y & 0x8888888888888888UL;
|
||||
|
||||
ulong z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1);
|
||||
ulong z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2);
|
||||
ulong z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3);
|
||||
ulong z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0);
|
||||
|
||||
z0 &= 0x1111111111111111UL;
|
||||
z1 &= 0x2222222222222222UL;
|
||||
z2 &= 0x4444444444444444UL;
|
||||
z3 &= 0x8888888888888888UL;
|
||||
|
||||
return z0 | z1 | z2 | z3;
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b541d643c97f0db4c8ac41882cf50f7a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes.Gcm
|
||||
{
|
||||
public interface IGcmExponentiator
|
||||
{
|
||||
void Init(byte[] x);
|
||||
void ExponentiateX(long pow, byte[] output);
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a73c4e1c5866f746971e04ec6972cf8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
14
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/gcm/IGcmMultiplier.cs
vendored
Normal file
14
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/modes/gcm/IGcmMultiplier.cs
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes.Gcm
|
||||
{
|
||||
public interface IGcmMultiplier
|
||||
{
|
||||
void Init(byte[] H);
|
||||
void MultiplyH(byte[] x);
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d084b7e75aa6eda4bbd8804fad7c3c98
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,63 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes.Gcm
|
||||
{
|
||||
public class Tables1kGcmExponentiator
|
||||
: IGcmExponentiator
|
||||
{
|
||||
// A lookup table of the power-of-two powers of 'x'
|
||||
// - lookupPowX2[i] = x^(2^i)
|
||||
private IList<GcmUtilities.FieldElement> lookupPowX2;
|
||||
|
||||
public void Init(byte[] x)
|
||||
{
|
||||
GcmUtilities.FieldElement y;
|
||||
GcmUtilities.AsFieldElement(x, out y);
|
||||
if (lookupPowX2 != null && y.Equals(lookupPowX2[0]))
|
||||
return;
|
||||
|
||||
lookupPowX2 = new List<GcmUtilities.FieldElement>(8);
|
||||
lookupPowX2.Add(y);
|
||||
}
|
||||
|
||||
public void ExponentiateX(long pow, byte[] output)
|
||||
{
|
||||
GcmUtilities.FieldElement y;
|
||||
GcmUtilities.One(out y);
|
||||
int bit = 0;
|
||||
while (pow > 0)
|
||||
{
|
||||
if ((pow & 1L) != 0)
|
||||
{
|
||||
EnsureAvailable(bit);
|
||||
GcmUtilities.FieldElement powX2 = (GcmUtilities.FieldElement)lookupPowX2[bit];
|
||||
GcmUtilities.Multiply(ref y, ref powX2);
|
||||
}
|
||||
++bit;
|
||||
pow >>= 1;
|
||||
}
|
||||
|
||||
GcmUtilities.AsBytes(ref y, output);
|
||||
}
|
||||
|
||||
private void EnsureAvailable(int bit)
|
||||
{
|
||||
int count = lookupPowX2.Count;
|
||||
if (count <= bit)
|
||||
{
|
||||
GcmUtilities.FieldElement powX2 = (GcmUtilities.FieldElement)lookupPowX2[count - 1];
|
||||
do
|
||||
{
|
||||
GcmUtilities.Square(ref powX2);
|
||||
lookupPowX2.Add(powX2);
|
||||
}
|
||||
while (++count <= bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 292216b0bad4fea4d9a088d66834fbb9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,72 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes.Gcm
|
||||
{
|
||||
public class Tables4kGcmMultiplier
|
||||
: IGcmMultiplier
|
||||
{
|
||||
private byte[] H;
|
||||
private GcmUtilities.FieldElement[] T;
|
||||
|
||||
public void Init(byte[] H)
|
||||
{
|
||||
if (T == null)
|
||||
{
|
||||
T = new GcmUtilities.FieldElement[256];
|
||||
}
|
||||
else if (Arrays.AreEqual(this.H, H))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.H = Arrays.Clone(H);
|
||||
|
||||
// T[0] = 0
|
||||
|
||||
// T[1] = H.p^7
|
||||
GcmUtilities.AsFieldElement(this.H, out T[1]);
|
||||
GcmUtilities.MultiplyP7(ref T[1]);
|
||||
|
||||
for (int n = 1; n < 128; ++n)
|
||||
{
|
||||
// T[2.n] = T[n].p^-1
|
||||
GcmUtilities.DivideP(ref T[n], out T[n << 1]);
|
||||
|
||||
// T[2.n + 1] = T[2.n] + T[1]
|
||||
GcmUtilities.Xor(ref T[n << 1], ref T[1], out T[(n << 1) + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
public void MultiplyH(byte[] x)
|
||||
{
|
||||
//GcmUtilities.FieldElement z = T[x[15]];
|
||||
//for (int i = 14; i >= 0; --i)
|
||||
//{
|
||||
// GcmUtilities.MultiplyP8(ref z);
|
||||
// GcmUtilities.Xor(ref z, ref T[x[i]]);
|
||||
//}
|
||||
//GcmUtilities.AsBytes(ref z, x);
|
||||
|
||||
int pos = x[15];
|
||||
ulong z0 = T[pos].n0, z1 = T[pos].n1;
|
||||
|
||||
for (int i = 14; i >= 0; --i)
|
||||
{
|
||||
pos = x[i];
|
||||
|
||||
ulong c = z1 << 56;
|
||||
z1 = T[pos].n1 ^ ((z1 >> 8) | (z0 << 56));
|
||||
z0 = T[pos].n0 ^ (z0 >> 8) ^ c ^ (c >> 1) ^ (c >> 2) ^ (c >> 7);
|
||||
}
|
||||
|
||||
GcmUtilities.AsBytes(z0, z1, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5498d1413e74d74e8430fe02dbf6d89
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,84 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes.Gcm
|
||||
{
|
||||
public class Tables64kGcmMultiplier
|
||||
: IGcmMultiplier
|
||||
{
|
||||
private byte[] H;
|
||||
private GcmUtilities.FieldElement[][] T;
|
||||
|
||||
public void Init(byte[] H)
|
||||
{
|
||||
if (T == null)
|
||||
{
|
||||
T = new GcmUtilities.FieldElement[16][];
|
||||
}
|
||||
else if (Arrays.AreEqual(this.H, H))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.H = Arrays.Clone(H);
|
||||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
GcmUtilities.FieldElement[] t = T[i] = new GcmUtilities.FieldElement[256];
|
||||
|
||||
// t[0] = 0
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
// t[1] = H.p^7
|
||||
GcmUtilities.AsFieldElement(this.H, out t[1]);
|
||||
GcmUtilities.MultiplyP7(ref t[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// t[1] = T[i-1][1].p^8
|
||||
GcmUtilities.MultiplyP8(ref T[i - 1][1], out t[1]);
|
||||
}
|
||||
|
||||
for (int n = 1; n < 128; ++n)
|
||||
{
|
||||
// t[2.n] = t[n].p^-1
|
||||
GcmUtilities.DivideP(ref t[n], out t[n << 1]);
|
||||
|
||||
// t[2.n + 1] = t[2.n] + t[1]
|
||||
GcmUtilities.Xor(ref t[n << 1], ref t[1], out t[(n << 1) + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void MultiplyH(byte[] x)
|
||||
{
|
||||
//GcmUtilities.FieldElement z = T[15][x[15]];
|
||||
//for (int i = 14; i >= 0; --i)
|
||||
//{
|
||||
// GcmUtilities.Xor(ref z, ref T[i][x[i]]);
|
||||
//}
|
||||
//GcmUtilities.AsBytes(ref z, x);
|
||||
|
||||
GcmUtilities.FieldElement[] t = T[15];
|
||||
int tPos = x[15];
|
||||
ulong z0 = t[tPos].n0, z1 = t[tPos].n1;
|
||||
|
||||
for (int i = 14; i >= 0; --i)
|
||||
{
|
||||
t = T[i];
|
||||
tPos = x[i];
|
||||
z0 ^= t[tPos].n0;
|
||||
z1 ^= t[tPos].n1;
|
||||
}
|
||||
|
||||
GcmUtilities.AsBytes(z0, z1, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2bc5f428ffb5c774eacfa6b8f8fc91f1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,93 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes.Gcm
|
||||
{
|
||||
public sealed class Tables8kGcmMultiplier
|
||||
: IGcmMultiplier
|
||||
{
|
||||
private byte[] H;
|
||||
private GcmUtilities.FieldElement[][] T;
|
||||
|
||||
public void Init(byte[] H)
|
||||
{
|
||||
if (T == null)
|
||||
{
|
||||
T = new GcmUtilities.FieldElement[2][];
|
||||
}
|
||||
else if (Arrays.AreEqual(this.H, H))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.H = Arrays.Clone(H);
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
GcmUtilities.FieldElement[] t = T[i] = new GcmUtilities.FieldElement[256];
|
||||
|
||||
// t[0] = 0
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
// t[1] = H.p^7
|
||||
GcmUtilities.AsFieldElement(this.H, out t[1]);
|
||||
GcmUtilities.MultiplyP7(ref t[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// t[1] = T[i-1][1].p^8
|
||||
GcmUtilities.MultiplyP8(ref T[i - 1][1], out t[1]);
|
||||
}
|
||||
|
||||
for (int n = 1; n < 128; ++n)
|
||||
{
|
||||
// t[2.n] = t[n].p^-1
|
||||
GcmUtilities.DivideP(ref t[n], out t[n << 1]);
|
||||
|
||||
// t[2.n + 1] = t[2.n] + t[1]
|
||||
GcmUtilities.Xor(ref t[n << 1], ref t[1], out t[(n << 1) + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
uint[] z = new uint[4];
|
||||
|
||||
public void MultiplyH(byte[] x)
|
||||
{
|
||||
GcmUtilities.FieldElement[] T0 = T[0], T1 = T[1];
|
||||
|
||||
//GcmUtilities.FieldElement z;
|
||||
//GcmUtilities.Xor(ref T0[x[14]], ref T1[x[15]], out z);
|
||||
//for (int i = 12; i >= 0; i -= 2)
|
||||
//{
|
||||
// GcmUtilities.MultiplyP16(ref z);
|
||||
// GcmUtilities.Xor(ref z, ref T0[x[i]]);
|
||||
// GcmUtilities.Xor(ref z, ref T1[x[i + 1]]);
|
||||
//}
|
||||
//GcmUtilities.AsBytes(ref z, x);
|
||||
|
||||
int vPos = x[15];
|
||||
int uPos = x[14];
|
||||
ulong z1 = T0[uPos].n1 ^ T1[vPos].n1;
|
||||
ulong z0 = T0[uPos].n0 ^ T1[vPos].n0;
|
||||
|
||||
for (int i = 12; i >= 0; i -= 2)
|
||||
{
|
||||
vPos = x[i + 1];
|
||||
uPos = x[i];
|
||||
|
||||
ulong c = z1 << 48;
|
||||
z1 = T0[uPos].n1 ^ T1[vPos].n1 ^ ((z1 >> 16) | (z0 << 48));
|
||||
z0 = T0[uPos].n0 ^ T1[vPos].n0 ^ (z0 >> 16) ^ c ^ (c >> 1) ^ (c >> 2) ^ (c >> 7);
|
||||
}
|
||||
|
||||
GcmUtilities.AsBytes(z0, z1, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af0e47802908a1e4686d49b38f408d0d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user