This commit is contained in:
2020-07-09 08:50:24 +08:00
parent 13d25f4707
commit c523462b82
1818 changed files with 174940 additions and 582 deletions

View File

@@ -0,0 +1,245 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Modes
{
/**
* implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
*/
public class CbcBlockCipher
: IBlockCipher
{
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 GetUnderlyingCipher()
{
return 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)
{
ParametersWithIV ivParam = (ParametersWithIV)parameters;
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();
}
/**
* Process one block of input from the array in and write it to
* the out array.
*
* @param in the array containing the input data.
* @param inOff offset into the in array the data starts at.
* @param out 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)
{
return (encrypting)
? EncryptBlock(input, inOff, output, outOff)
: DecryptBlock(input, inOff, output, outOff);
}
/**
* 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);
cipher.Reset();
}
/**
* Do the appropriate chaining step for CBC mode encryption.
*
* @param in the array containing the data to be encrypted.
* @param inOff offset into the in array the data starts at.
* @param out the array the encrypted 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.
*/
private int EncryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
if ((inOff + blockSize) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
/*
* XOR the cbcV and the input,
* then encrypt the cbcV
*/
for (int i = 0; i < blockSize; i++)
{
cbcV[i] ^= input[inOff + i];
}
int length = cipher.ProcessBlock(cbcV, 0, outBytes, outOff);
/*
* copy ciphertext to cbcV
*/
Array.Copy(outBytes, outOff, cbcV, 0, cbcV.Length);
return length;
}
/**
* Do the appropriate chaining step for CBC mode decryption.
*
* @param in the array containing the data to be decrypted.
* @param inOff offset into the in array the data starts at.
* @param out the array the decrypted 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.
*/
private int DecryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
if ((inOff + blockSize) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
Array.Copy(input, inOff, cbcNextV, 0, blockSize);
int length = cipher.ProcessBlock(input, inOff, outBytes, outOff);
/*
* XOR the cbcV and the output
*/
for (int i = 0; i < blockSize; i++)
{
outBytes[outOff + i] ^= cbcV[i];
}
/*
* swap the back up buffer into next position
*/
byte[] tmp;
tmp = cbcV;
cbcV = cbcNextV;
cbcNextV = tmp;
return length;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e0d6530dbcc5b447e8a5976d6a80cfa1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,453 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using System.IO;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
namespace 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 GetUnderlyingCipher()
{
return cipher;
}
public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
this.forEncryption = forEncryption;
ICipherParameters cipherParameters;
if (parameters is AeadParameters)
{
AeadParameters param = (AeadParameters) parameters;
nonce = param.GetNonce();
initialAssociatedText = param.GetAssociatedText();
macSize = param.MacSize / 8;
cipherParameters = param.Key;
}
else if (parameters is ParametersWithIV)
{
ParametersWithIV param = (ParametersWithIV) parameters;
nonce = param.GetIV();
initialAssociatedText = null;
macSize = macBlock.Length / 2;
cipherParameters = param.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
{
get { return 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);
}
public virtual int ProcessByte(
byte input,
byte[] outBytes,
int outOff)
{
data.WriteByte(input);
return 0;
}
public virtual int ProcessBytes(
byte[] inBytes,
int inOff,
int inLen,
byte[] outBytes,
int outOff)
{
Check.DataLength(inBytes, inOff, inLen, "Input buffer too short");
data.Write(inBytes, inOff, inLen);
return 0;
}
public virtual int DoFinal(
byte[] outBytes,
int outOff)
{
#if PORTABLE || NETFX_CORE
byte[] input = data.ToArray();
int inLen = input.Length;
#else
byte[] input = data.GetBuffer();
int inLen = (int)data.Position;
#endif
int len = ProcessPacket(input, 0, inLen, outBytes, outOff);
Reset();
return len;
}
public virtual void Reset()
{
cipher.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 = (int)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;
}
private int CalculateMac(byte[] data, int dataOff, int dataLen, 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 = 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.Position > 0)
{
#if PORTABLE || NETFX_CORE
byte[] input = associatedText.ToArray();
int len = input.Length;
#else
byte[] input = associatedText.GetBuffer();
int len = (int)associatedText.Position;
#endif
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);
}
private int GetAssociatedTextLength()
{
return (int)associatedText.Length + ((initialAssociatedText == null) ? 0 : initialAssociatedText.Length);
}
private bool HasAssociatedText()
{
return GetAssociatedTextLength() > 0;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 18bad243fabea4f049a5c2441f9ed3f0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,228 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Modes
{
/**
* implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
*/
public class CfbBlockCipher
: IBlockCipher
{
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)
{
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 GetUnderlyingCipher()
{
return 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;
}
/**
* Process one block of input from the array in and write it to
* the out array.
*
* @param in the array containing the input data.
* @param inOff offset into the in array the data starts at.
* @param out 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)
{
return (encrypting)
? EncryptBlock(input, inOff, output, outOff)
: DecryptBlock(input, inOff, output, outOff);
}
/**
* Do the appropriate processing for CFB mode encryption.
*
* @param in the array containing the data to be encrypted.
* @param inOff offset into the in array the data starts at.
* @param out the array the encrypted 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 EncryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
if ((inOff + blockSize) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + blockSize) > outBytes.Length)
{
throw new DataLengthException("output buffer too short");
}
cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
//
// 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;
}
/**
* Do the appropriate processing for CFB mode decryption.
*
* @param in the array containing the data to be decrypted.
* @param inOff offset into the in array the data starts at.
* @param out the array the encrypted 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 DecryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
if ((inOff + blockSize) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + blockSize) > outBytes.Length)
{
throw new DataLengthException("output buffer too short");
}
cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
//
// 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;
}
/**
* reset the chaining vector back to the IV and reset the underlying
* cipher.
*/
public void Reset()
{
Array.Copy(IV, 0, cfbV, 0, IV.Length);
cipher.Reset();
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 170d26d41fe79464981e6696e7f818ca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,257 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using System.Diagnostics;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
namespace 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;
/**
* Create a buffered block cipher that uses Cipher Text Stealing
*
* @param cipher the underlying block cipher this buffering object wraps.
*/
public CtsBlockCipher(
IBlockCipher cipher)
{
// TODO Should this test for acceptable ones instead?
if (cipher is OfbBlockCipher || cipher is CfbBlockCipher)
throw new ArgumentException("CtsBlockCipher can only accept ECB, or CBC ciphers");
this.cipher = cipher;
blockSize = cipher.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 = cipher.ProcessBlock(buf, 0, output, outOff);
Debug.Assert(resultLen == blockSize);
Array.Copy(buf, blockSize, buf, 0, blockSize);
bufOff = blockSize;
}
buf[bufOff++] = input;
return resultLen;
}
/**
* 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 outLength!");
}
int blockSize = GetBlockSize();
int outLength = GetUpdateOutputSize(length);
if (outLength > 0)
{
if ((outOff + outLength) > output.Length)
{
throw new DataLengthException("output buffer too short");
}
}
int resultLen = 0;
int gapLen = buf.Length - bufOff;
if (length > gapLen)
{
Array.Copy(input, inOff, buf, bufOff, gapLen);
resultLen += cipher.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 += cipher.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;
}
/**
* 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 = cipher.GetBlockSize();
int length = bufOff - blockSize;
byte[] block = new byte[blockSize];
if (forEncryption)
{
cipher.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];
}
IBlockCipher c = (cipher is CbcBlockCipher)
? ((CbcBlockCipher)cipher).GetUnderlyingCipher()
: cipher;
c.ProcessBlock(buf, blockSize, output, outOff);
Array.Copy(block, 0, output, outOff + blockSize, length);
}
else
{
byte[] lastBlock = new byte[blockSize];
IBlockCipher c = (cipher is CbcBlockCipher)
? ((CbcBlockCipher)cipher).GetUnderlyingCipher()
: cipher;
c.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);
cipher.ProcessBlock(block, 0, output, outOff);
Array.Copy(lastBlock, 0, output, outOff + blockSize, length);
}
int offset = bufOff;
Reset();
return offset;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: eaa7642f859b644abaccfaad1c7cdc3a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,383 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
namespace 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
{
get { return cipher.GetUnderlyingCipher().AlgorithmName + "/EAX"; }
}
public virtual IBlockCipher GetUnderlyingCipher()
{
return cipher;
}
public virtual int GetBlockSize()
{
return cipher.GetBlockSize();
}
public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
this.forEncryption = forEncryption;
byte[] nonce;
ICipherParameters keyParam;
if (parameters is AeadParameters)
{
AeadParameters param = (AeadParameters) parameters;
nonce = param.GetNonce();
initialAssociatedText = param.GetAssociatedText();
macSize = param.MacSize / 8;
keyParam = param.Key;
}
else if (parameters is ParametersWithIV)
{
ParametersWithIV param = (ParametersWithIV) parameters;
nonce = param.GetIV();
initialAssociatedText = null;
macSize = mac.GetMacSize() / 2;
keyParam = param.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);
}
public virtual int ProcessByte(
byte input,
byte[] outBytes,
int outOff)
{
InitCipher();
return Process(input, outBytes, outOff);
}
public virtual int ProcessBytes(
byte[] inBytes,
int inOff,
int len,
byte[] outBytes,
int outOff)
{
InitCipher();
int resultLen = 0;
for (int i = 0; i != len; i++)
{
resultLen += Process(inBytes[inOff + i], outBytes, outOff + resultLen);
}
return resultLen;
}
public virtual int DoFinal(
byte[] outBytes,
int outOff)
{
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;
}
}
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;
}
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;
}
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;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 22aa0030c62014175b7ef80bf2c393a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,540 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Modes.Gcm;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes
{
/// <summary>
/// Implements the Galois/Counter mode (GCM) detailed in
/// NIST Special Publication 800-38D.
/// </summary>
public class GcmBlockCipher
: IAeadBlockCipher
{
private const int BlockSize = 16;
private readonly IBlockCipher cipher;
private readonly IGcmMultiplier multiplier;
private IGcmExponentiator exp;
// These fields are set by Init and not modified by processing
private bool forEncryption;
private int macSize;
private byte[] nonce;
private byte[] initialAssociatedText;
private byte[] H;
private byte[] J0;
// These fields are modified during processing
private byte[] bufBlock;
private byte[] macBlock;
private byte[] S, S_at, S_atPre;
private byte[] counter;
private uint blocksRemaining;
private int bufOff;
private ulong totalLength;
private byte[] atBlock;
private int atBlockPos;
private ulong atLength;
private ulong atLengthPre;
public GcmBlockCipher(
IBlockCipher c)
: this(c, null)
{
}
public GcmBlockCipher(
IBlockCipher c,
IGcmMultiplier m)
{
if (c.GetBlockSize() != BlockSize)
throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
if (m == null)
{
// TODO Consider a static property specifying default multiplier
m = new Tables8kGcmMultiplier();
}
this.cipher = c;
this.multiplier = m;
}
public virtual string AlgorithmName
{
get { return cipher.AlgorithmName + "/GCM"; }
}
public IBlockCipher GetUnderlyingCipher()
{
return cipher;
}
public virtual int GetBlockSize()
{
return BlockSize;
}
/// <remarks>
/// MAC sizes from 32 bits to 128 bits (must be a multiple of 8) are supported. The default is 128 bits.
/// Sizes less than 96 are not recommended, but are supported for specialized applications.
/// </remarks>
public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
this.forEncryption = forEncryption;
this.macBlock = null;
KeyParameter keyParam;
if (parameters is AeadParameters)
{
AeadParameters param = (AeadParameters)parameters;
nonce = param.GetNonce();
initialAssociatedText = param.GetAssociatedText();
int macSizeBits = param.MacSize;
if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0)
{
throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
}
macSize = macSizeBits / 8;
keyParam = param.Key;
}
else if (parameters is ParametersWithIV)
{
ParametersWithIV param = (ParametersWithIV)parameters;
nonce = param.GetIV();
initialAssociatedText = null;
macSize = 16;
keyParam = (KeyParameter)param.Parameters;
}
else
{
throw new ArgumentException("invalid parameters passed to GCM");
}
int bufLength = forEncryption ? BlockSize : (BlockSize + macSize);
this.bufBlock = new byte[bufLength];
if (nonce == null || nonce.Length < 1)
{
throw new ArgumentException("IV must be at least 1 byte");
}
// TODO Restrict macSize to 16 if nonce length not 12?
// Cipher always used in forward mode
// if keyParam is null we're reusing the last key.
if (keyParam != null)
{
cipher.Init(true, keyParam);
this.H = new byte[BlockSize];
cipher.ProcessBlock(H, 0, H, 0);
// if keyParam is null we're reusing the last key and the multiplier doesn't need re-init
multiplier.Init(H);
exp = null;
}
else if (this.H == null)
{
throw new ArgumentException("Key must be specified in initial init");
}
this.J0 = new byte[BlockSize];
if (nonce.Length == 12)
{
Array.Copy(nonce, 0, J0, 0, nonce.Length);
this.J0[BlockSize - 1] = 0x01;
}
else
{
gHASH(J0, nonce, nonce.Length);
byte[] X = new byte[BlockSize];
Pack.UInt64_To_BE((ulong)nonce.Length * 8UL, X, 8);
gHASHBlock(J0, X);
}
this.S = new byte[BlockSize];
this.S_at = new byte[BlockSize];
this.S_atPre = new byte[BlockSize];
this.atBlock = new byte[BlockSize];
this.atBlockPos = 0;
this.atLength = 0;
this.atLengthPre = 0;
this.counter = Arrays.Clone(J0);
this.blocksRemaining = uint.MaxValue - 1; // page 8, len(P) <= 2^39 - 256, 1 block used by tag
this.bufOff = 0;
this.totalLength = 0;
if (initialAssociatedText != null)
{
ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
}
}
public virtual byte[] GetMac()
{
return Arrays.Clone(macBlock);
}
public virtual int GetOutputSize(
int len)
{
int totalData = len + bufOff;
if (forEncryption)
{
return totalData + macSize;
}
return totalData < macSize ? 0 : totalData - macSize;
}
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 void ProcessAadByte(byte input)
{
atBlock[atBlockPos] = input;
if (++atBlockPos == BlockSize)
{
// Hash each block as it fills
gHASHBlock(S_at, atBlock);
atBlockPos = 0;
atLength += BlockSize;
}
}
public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
{
for (int i = 0; i < len; ++i)
{
atBlock[atBlockPos] = inBytes[inOff + i];
if (++atBlockPos == BlockSize)
{
// Hash each block as it fills
gHASHBlock(S_at, atBlock);
atBlockPos = 0;
atLength += BlockSize;
}
}
}
private void InitCipher()
{
if (atLength > 0)
{
Array.Copy(S_at, 0, S_atPre, 0, BlockSize);
atLengthPre = atLength;
}
// Finish hash for partial AAD block
if (atBlockPos > 0)
{
gHASHPartial(S_atPre, atBlock, 0, atBlockPos);
atLengthPre += (uint)atBlockPos;
}
if (atLengthPre > 0)
{
Array.Copy(S_atPre, 0, S, 0, BlockSize);
}
}
public virtual int ProcessByte(
byte input,
byte[] output,
int outOff)
{
bufBlock[bufOff] = input;
if (++bufOff == bufBlock.Length)
{
OutputBlock(output, outOff);
return BlockSize;
}
return 0;
}
public virtual int ProcessBytes(
byte[] input,
int inOff,
int len,
byte[] output,
int outOff)
{
if (input.Length < (inOff + len))
throw new DataLengthException("Input buffer too short");
int resultLen = 0;
for (int i = 0; i < len; ++i)
{
bufBlock[bufOff] = input[inOff + i];
if (++bufOff == bufBlock.Length)
{
OutputBlock(output, outOff + resultLen);
resultLen += BlockSize;
}
}
return resultLen;
}
private void OutputBlock(byte[] output, int offset)
{
Check.OutputLength(output, offset, BlockSize, "Output buffer too short");
if (totalLength == 0)
{
InitCipher();
}
gCTRBlock(bufBlock, output, offset);
if (forEncryption)
{
bufOff = 0;
}
else
{
Array.Copy(bufBlock, BlockSize, bufBlock, 0, macSize);
bufOff = macSize;
}
}
public int DoFinal(byte[] output, int outOff)
{
if (totalLength == 0)
{
InitCipher();
}
int extra = bufOff;
if (forEncryption)
{
Check.OutputLength(output, outOff, extra + macSize, "Output buffer too short");
}
else
{
if (extra < macSize)
throw new InvalidCipherTextException("data too short");
extra -= macSize;
Check.OutputLength(output, outOff, extra, "Output buffer too short");
}
if (extra > 0)
{
gCTRPartial(bufBlock, 0, extra, output, outOff);
}
atLength += (uint)atBlockPos;
if (atLength > atLengthPre)
{
/*
* Some AAD was sent after the cipher started. We determine the difference b/w the hash value
* we actually used when the cipher started (S_atPre) and the final hash value calculated (S_at).
* Then we carry this difference forward by multiplying by H^c, where c is the number of (full or
* partial) cipher-text blocks produced, and adjust the current hash.
*/
// Finish hash for partial AAD block
if (atBlockPos > 0)
{
gHASHPartial(S_at, atBlock, 0, atBlockPos);
}
// Find the difference between the AAD hashes
if (atLengthPre > 0)
{
GcmUtilities.Xor(S_at, S_atPre);
}
// Number of cipher-text blocks produced
long c = (long)(((totalLength * 8) + 127) >> 7);
// Calculate the adjustment factor
byte[] H_c = new byte[16];
if (exp == null)
{
exp = new Tables1kGcmExponentiator();
exp.Init(H);
}
exp.ExponentiateX(c, H_c);
// Carry the difference forward
GcmUtilities.Multiply(S_at, H_c);
// Adjust the current hash
GcmUtilities.Xor(S, S_at);
}
// Final gHASH
byte[] X = new byte[BlockSize];
Pack.UInt64_To_BE(atLength * 8UL, X, 0);
Pack.UInt64_To_BE(totalLength * 8UL, X, 8);
gHASHBlock(S, X);
// T = MSBt(GCTRk(J0,S))
byte[] tag = new byte[BlockSize];
cipher.ProcessBlock(J0, 0, tag, 0);
GcmUtilities.Xor(tag, S);
int resultLen = extra;
// We place into macBlock our calculated value for T
this.macBlock = new byte[macSize];
Array.Copy(tag, 0, macBlock, 0, macSize);
if (forEncryption)
{
// Append T to the message
Array.Copy(macBlock, 0, output, outOff + bufOff, macSize);
resultLen += macSize;
}
else
{
// Retrieve the T value from the message and compare to calculated one
byte[] msgMac = new byte[macSize];
Array.Copy(bufBlock, extra, msgMac, 0, macSize);
if (!Arrays.ConstantTimeAreEqual(this.macBlock, msgMac))
throw new InvalidCipherTextException("mac check in GCM failed");
}
Reset(false);
return resultLen;
}
public virtual void Reset()
{
Reset(true);
}
private void Reset(
bool clearMac)
{
cipher.Reset();
S = new byte[BlockSize];
S_at = new byte[BlockSize];
S_atPre = new byte[BlockSize];
atBlock = new byte[BlockSize];
atBlockPos = 0;
atLength = 0;
atLengthPre = 0;
counter = Arrays.Clone(J0);
blocksRemaining = uint.MaxValue - 1;
bufOff = 0;
totalLength = 0;
if (bufBlock != null)
{
Arrays.Fill(bufBlock, 0);
}
if (clearMac)
{
macBlock = null;
}
if (initialAssociatedText != null)
{
ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
}
}
private void gCTRBlock(byte[] block, byte[] output, int outOff)
{
byte[] tmp = GetNextCounterBlock();
GcmUtilities.Xor(tmp, block);
Array.Copy(tmp, 0, output, outOff, BlockSize);
gHASHBlock(S, forEncryption ? tmp : block);
totalLength += BlockSize;
}
private void gCTRPartial(byte[] buf, int off, int len, byte[] output, int outOff)
{
byte[] tmp = GetNextCounterBlock();
GcmUtilities.Xor(tmp, buf, off, len);
Array.Copy(tmp, 0, output, outOff, len);
gHASHPartial(S, forEncryption ? tmp : buf, 0, len);
totalLength += (uint)len;
}
private void gHASH(byte[] Y, byte[] b, int len)
{
for (int pos = 0; pos < len; pos += BlockSize)
{
int num = System.Math.Min(len - pos, BlockSize);
gHASHPartial(Y, b, pos, num);
}
}
private void gHASHBlock(byte[] Y, byte[] b)
{
GcmUtilities.Xor(Y, b);
multiplier.MultiplyH(Y);
}
private void gHASHPartial(byte[] Y, byte[] b, int off, int len)
{
GcmUtilities.Xor(Y, b, off, len);
multiplier.MultiplyH(Y);
}
private byte[] GetNextCounterBlock()
{
if (blocksRemaining == 0)
throw new InvalidOperationException("Attempt to process too many blocks");
blocksRemaining--;
uint c = 1;
c += counter[15]; counter[15] = (byte)c; c >>= 8;
c += counter[14]; counter[14] = (byte)c; c >>= 8;
c += counter[13]; counter[13] = (byte)c; c >>= 8;
c += counter[12]; counter[12] = (byte)c;
byte[] tmp = new byte[BlockSize];
// TODO Sure would be nice if ciphers could operate on int[]
cipher.ProcessBlock(counter, 0, tmp, 0);
return tmp;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f1106778ff743498b89fc01203768166
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,231 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Modes
{
/**
* implements the GOST 28147 OFB counter mode (GCTR).
*/
public class GOfbBlockCipher
: IBlockCipher
{
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 GetUnderlyingCipher()
{
return 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;
}
/**
* Process one block of input from the array in and write it to
* the out array.
*
* @param in the array containing the input data.
* @param inOff offset into the in array the data starts at.
* @param out 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)
{
if ((inOff + blockSize) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + blockSize) > output.Length)
{
throw new DataLengthException("output buffer too short");
}
if (firstStep)
{
firstStep = false;
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
N3 = bytesToint(ofbOutV, 0);
N4 = bytesToint(ofbOutV, 4);
}
N3 += C2;
N4 += C1;
intTobytes(N3, ofbV, 0);
intTobytes(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;
}
/**
* reset the feedback vector back to the IV and reset the underlying
* cipher.
*/
public void Reset()
{
Array.Copy(IV, 0, ofbV, 0, IV.Length);
cipher.Reset();
}
//array of bytes to type int
private int bytesToint(
byte[] inBytes,
int inOff)
{
return (int)((inBytes[inOff + 3] << 24) & 0xff000000) + ((inBytes[inOff + 2] << 16) & 0xff0000) +
((inBytes[inOff + 1] << 8) & 0xff00) + (inBytes[inOff] & 0xff);
}
//int to array of bytes
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;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3008300e761cc48a99bba74960fff771
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,109 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Modes
{
/// <summary>
/// A block cipher mode that includes authenticated encryption with a streaming mode
/// and optional associated data.</summary>
/// <see cref="AeadParameters"/>
public interface IAeadBlockCipher
{
/// <summary>The name of the algorithm this cipher implements.</summary>
string AlgorithmName { get; }
/// <summary>The block cipher underlying this algorithm.</summary>
IBlockCipher GetUnderlyingCipher();
/// <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);
/// <returns>The block size for this cipher, in bytes.</returns>
int GetBlockSize();
/// <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);
/**
* 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);
/**
* 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);
/**
* 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);
/**
* 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();
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3e804d368f67c4a409dad23d93d06e7e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,567 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using System.Collections;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes
{
/**
* An implementation of <a href="http://tools.ietf.org/html/rfc7253">RFC 7253 on The OCB
* Authenticated-Encryption Algorithm</a>, licensed per:
*
* <blockquote><p><a href="http://www.cs.ucdavis.edu/~rogaway/ocb/license1.pdf">License for
* Open-Source Software Implementations of OCB</a> (Jan 9, 2013) - 'License 1'<br/>
* Under this license, you are authorized to make, use, and distribute open-source software
* implementations of OCB. This license terminates for you if you sue someone over their open-source
* software implementation of OCB claiming that you have a patent covering their implementation.
* </p><p>
* This is a non-binding summary of a legal document (the link above). The parameters of the license
* are specified in the license document and that document is controlling.</p></blockquote>
*/
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 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 IBlockCipher GetUnderlyingCipher()
{
return mainCipher;
}
public virtual string AlgorithmName
{
get { return mainCipher.AlgorithmName + "/OCB"; }
}
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 aeadParameters = (AeadParameters) parameters;
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 parametersWithIV = (ParametersWithIV) parameters;
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 = Platform.CreateArrayList();
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 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();
}
}
}
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;
}
public virtual int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
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;
}
public virtual int DoFinal(byte[] output, int outOff)
{
/*
* 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;
}
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((byte[]) L[L.Count - 1]));
}
return (byte[])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;
}
}
protected virtual void Reset(bool clearMac)
{
hashCipher.Reset();
mainCipher.Reset();
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];
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e87d917585fd3419ab0b1860525ed55b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,186 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace Org.BouncyCastle.Crypto.Modes
{
/**
* implements a Output-FeedBack (OFB) mode on top of a simple cipher.
*/
public class OfbBlockCipher
: IBlockCipher
{
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 GetUnderlyingCipher()
{
return 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)
{
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 "/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;
}
/**
* Process one block of input from the array in and write it to
* the out array.
*
* @param in the array containing the input data.
* @param inOff offset into the in array the data starts at.
* @param out 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)
{
if ((inOff + blockSize) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + blockSize) > output.Length)
{
throw new DataLengthException("output buffer too short");
}
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
//
// 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;
}
/**
* reset the feedback vector back to the IV and reset the underlying
* cipher.
*/
public void Reset()
{
Array.Copy(IV, 0, ofbV, 0, IV.Length);
cipher.Reset();
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d259215b8984042c991745c07d5fcb59
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,341 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using Org.BouncyCastle.Crypto.Parameters;
namespace 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
: IBlockCipher
{
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 GetUnderlyingCipher()
{
return 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();
}
/**
* Process one block of input from the array in and write it to
* the out array.
*
* @param in the array containing the input data.
* @param inOff offset into the in array the data starts at.
* @param out 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)
{
return (forEncryption) ? EncryptBlock(input, inOff, output, outOff) : DecryptBlock(input, inOff, output, outOff);
}
/**
* 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);
cipher.Reset();
}
/**
* 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)
{
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();
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);
}
/**
* Do the appropriate processing for CFB IV mode encryption.
*
* @param in the array containing the data to be encrypted.
* @param inOff offset into the in array the data starts at.
* @param out the array the encrypted 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.
*/
private int EncryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
if ((inOff + blockSize) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + blockSize) > outBytes.Length)
{
throw new DataLengthException("output buffer too short");
}
if (count > blockSize)
{
FR[blockSize - 2] = outBytes[outOff] = EncryptByte(input[inOff], blockSize - 2);
FR[blockSize - 1] = outBytes[outOff + 1] = EncryptByte(input[inOff + 1], blockSize - 1);
cipher.ProcessBlock(FR, 0, FRE, 0);
for (int 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;
}
/**
* Do the appropriate processing for CFB IV mode decryption.
*
* @param in the array containing the data to be decrypted.
* @param inOff offset into the in array the data starts at.
* @param out the array the encrypted 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.
*/
private int DecryptBlock(
byte[] input,
int inOff,
byte[] outBytes,
int outOff)
{
if ((inOff + blockSize) > input.Length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + blockSize) > outBytes.Length)
{
throw new DataLengthException("output buffer too short");
}
if (count > blockSize)
{
byte 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[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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c3be24a5876346d280a3c39f8a24379
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,124 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes
{
/**
* Implements the Segmented Integer Counter (SIC) mode on top of a simple
* block cipher.
*/
public class SicBlockCipher
: IBlockCipher
{
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 virtual IBlockCipher GetUnderlyingCipher()
{
return 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;
}
public virtual void Reset()
{
Arrays.Fill(counter, (byte)0);
Array.Copy(IV, 0, counter, 0, IV.Length);
cipher.Reset();
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2ffd856d6c9dd48aea0fbb1fb66e9019
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 11524718565b740b6a99c4cdcb06ce9f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,323 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes.Gcm
{
internal abstract class GcmUtilities
{
private const uint E1 = 0xe1000000;
private const ulong E1L = (ulong)E1 << 32;
private static uint[] GenerateLookup()
{
uint[] lookup = new uint[256];
for (int c = 0; c < 256; ++c)
{
uint v = 0;
for (int i = 7; i >= 0; --i)
{
if ((c & (1 << i)) != 0)
{
v ^= (E1 >> (7 - i));
}
}
lookup[c] = v;
}
return lookup;
}
private static readonly uint[] LOOKUP = GenerateLookup();
internal static byte[] OneAsBytes()
{
byte[] tmp = new byte[16];
tmp[0] = 0x80;
return tmp;
}
internal static uint[] OneAsUints()
{
uint[] tmp = new uint[4];
tmp[0] = 0x80000000;
return tmp;
}
internal static ulong[] OneAsUlongs()
{
ulong[] tmp = new ulong[2];
tmp[0] = 1UL << 63;
return tmp;
}
internal static byte[] AsBytes(uint[] x)
{
return Pack.UInt32_To_BE(x);
}
internal static void AsBytes(uint[] x, byte[] z)
{
Pack.UInt32_To_BE(x, z, 0);
}
internal static byte[] AsBytes(ulong[] x)
{
byte[] z = new byte[16];
Pack.UInt64_To_BE(x, z, 0);
return z;
}
internal static void AsBytes(ulong[] x, byte[] z)
{
Pack.UInt64_To_BE(x, z, 0);
}
internal static uint[] AsUints(byte[] bs)
{
uint[] output = new uint[4];
Pack.BE_To_UInt32(bs, 0, output);
return output;
}
internal static void AsUints(byte[] bs, uint[] output)
{
Pack.BE_To_UInt32(bs, 0, output);
}
internal static ulong[] AsUlongs(byte[] x)
{
ulong[] z = new ulong[2];
Pack.BE_To_UInt64(x, 0, z);
return z;
}
public static void AsUlongs(byte[] x, ulong[] z)
{
Pack.BE_To_UInt64(x, 0, z);
}
internal static void Multiply(byte[] x, byte[] y)
{
uint[] t1 = GcmUtilities.AsUints(x);
uint[] t2 = GcmUtilities.AsUints(y);
GcmUtilities.Multiply(t1, t2);
GcmUtilities.AsBytes(t1, x);
}
internal static void Multiply(uint[] x, uint[] y)
{
uint r00 = x[0], r01 = x[1], r02 = x[2], r03 = x[3];
uint r10 = 0, r11 = 0, r12 = 0, r13 = 0;
for (int i = 0; i < 4; ++i)
{
int bits = (int)y[i];
for (int j = 0; j < 32; ++j)
{
uint m1 = (uint)(bits >> 31); bits <<= 1;
r10 ^= (r00 & m1);
r11 ^= (r01 & m1);
r12 ^= (r02 & m1);
r13 ^= (r03 & m1);
uint m2 = (uint)((int)(r03 << 31) >> 8);
r03 = (r03 >> 1) | (r02 << 31);
r02 = (r02 >> 1) | (r01 << 31);
r01 = (r01 >> 1) | (r00 << 31);
r00 = (r00 >> 1) ^ (m2 & E1);
}
}
x[0] = r10;
x[1] = r11;
x[2] = r12;
x[3] = r13;
}
internal static void Multiply(ulong[] x, ulong[] y)
{
ulong r00 = x[0], r01 = x[1], r10 = 0, r11 = 0;
for (int i = 0; i < 2; ++i)
{
long bits = (long)y[i];
for (int j = 0; j < 64; ++j)
{
ulong m1 = (ulong)(bits >> 63); bits <<= 1;
r10 ^= (r00 & m1);
r11 ^= (r01 & m1);
ulong m2 = (ulong)((long)(r01 << 63) >> 8);
r01 = (r01 >> 1) | (r00 << 63);
r00 = (r00 >> 1) ^ (m2 & E1L);
}
}
x[0] = r10;
x[1] = r11;
}
// P is the value with only bit i=1 set
internal static void MultiplyP(uint[] x)
{
uint m = (uint)((int)ShiftRight(x) >> 8);
x[0] ^= (m & E1);
}
internal static void MultiplyP(uint[] x, uint[] z)
{
uint m = (uint)((int)ShiftRight(x, z) >> 8);
z[0] ^= (m & E1);
}
internal static void MultiplyP8(uint[] x)
{
// for (int i = 8; i != 0; --i)
// {
// MultiplyP(x);
// }
uint c = ShiftRightN(x, 8);
x[0] ^= LOOKUP[c >> 24];
}
internal static void MultiplyP8(uint[] x, uint[] y)
{
uint c = ShiftRightN(x, 8, y);
y[0] ^= LOOKUP[c >> 24];
}
internal static uint ShiftRight(uint[] x)
{
uint b = x[0];
x[0] = b >> 1;
uint c = b << 31;
b = x[1];
x[1] = (b >> 1) | c;
c = b << 31;
b = x[2];
x[2] = (b >> 1) | c;
c = b << 31;
b = x[3];
x[3] = (b >> 1) | c;
return b << 31;
}
internal static uint ShiftRight(uint[] x, uint[] z)
{
uint b = x[0];
z[0] = b >> 1;
uint c = b << 31;
b = x[1];
z[1] = (b >> 1) | c;
c = b << 31;
b = x[2];
z[2] = (b >> 1) | c;
c = b << 31;
b = x[3];
z[3] = (b >> 1) | c;
return b << 31;
}
internal static uint ShiftRightN(uint[] x, int n)
{
uint b = x[0]; int nInv = 32 - n;
x[0] = b >> n;
uint c = b << nInv;
b = x[1];
x[1] = (b >> n) | c;
c = b << nInv;
b = x[2];
x[2] = (b >> n) | c;
c = b << nInv;
b = x[3];
x[3] = (b >> n) | c;
return b << nInv;
}
internal static uint ShiftRightN(uint[] x, int n, uint[] z)
{
uint b = x[0]; int nInv = 32 - n;
z[0] = b >> n;
uint c = b << nInv;
b = x[1];
z[1] = (b >> n) | c;
c = b << nInv;
b = x[2];
z[2] = (b >> n) | c;
c = b << nInv;
b = x[3];
z[3] = (b >> n) | c;
return b << nInv;
}
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 yLen)
{
while (--yLen >= 0)
{
x[yLen] ^= y[yOff + yLen];
}
}
internal static void Xor(byte[] x, byte[] y, byte[] z)
{
int i = 0;
do
{
z[i] = (byte)(x[i] ^ y[i]); ++i;
z[i] = (byte)(x[i] ^ y[i]); ++i;
z[i] = (byte)(x[i] ^ y[i]); ++i;
z[i] = (byte)(x[i] ^ y[i]); ++i;
}
while (i < 16);
}
internal static void Xor(uint[] x, uint[] y)
{
x[0] ^= y[0];
x[1] ^= y[1];
x[2] ^= y[2];
x[3] ^= y[3];
}
internal static void Xor(uint[] x, uint[] y, uint[] z)
{
z[0] = x[0] ^ y[0];
z[1] = x[1] ^ y[1];
z[2] = x[2] ^ y[2];
z[3] = x[3] ^ y[3];
}
internal static void Xor(ulong[] x, ulong[] y)
{
x[0] ^= y[0];
x[1] ^= y[1];
}
internal static void Xor(ulong[] x, ulong[] y, ulong[] z)
{
z[0] = x[0] ^ y[0];
z[1] = x[1] ^ y[1];
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9161f2ba060f64038a7d15dc37938e02
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
namespace Org.BouncyCastle.Crypto.Modes.Gcm
{
public interface IGcmExponentiator
{
void Init(byte[] x);
void ExponentiateX(long pow, byte[] output);
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d2de0b4d04da7432b876404ab38fd59b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
namespace Org.BouncyCastle.Crypto.Modes.Gcm
{
public interface IGcmMultiplier
{
void Init(byte[] H);
void MultiplyH(byte[] x);
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3e6b652ec310a4ff39aa6e37f36e9454
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,63 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using System.Collections;
using Org.BouncyCastle.Utilities;
namespace 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 lookupPowX2;
public void Init(byte[] x)
{
uint[] y = GcmUtilities.AsUints(x);
if (lookupPowX2 != null && Arrays.AreEqual(y, (uint[])lookupPowX2[0]))
return;
lookupPowX2 = Platform.CreateArrayList(8);
lookupPowX2.Add(y);
}
public void ExponentiateX(long pow, byte[] output)
{
uint[] y = GcmUtilities.OneAsUints();
int bit = 0;
while (pow > 0)
{
if ((pow & 1L) != 0)
{
EnsureAvailable(bit);
GcmUtilities.Multiply(y, (uint[])lookupPowX2[bit]);
}
++bit;
pow >>= 1;
}
GcmUtilities.AsBytes(y, output);
}
private void EnsureAvailable(int bit)
{
int count = lookupPowX2.Count;
if (count <= bit)
{
uint[] tmp = (uint[])lookupPowX2[count - 1];
do
{
tmp = Arrays.Clone(tmp);
GcmUtilities.Multiply(tmp, tmp);
lookupPowX2.Add(tmp);
}
while (++count <= bit);
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9baec52f99b21430ea2a70d383656640
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,107 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes.Gcm
{
public class Tables8kGcmMultiplier
: IGcmMultiplier
{
private byte[] H;
private uint[][][] M;
public void Init(byte[] H)
{
if (M == null)
{
M = new uint[32][][];
}
else if (Arrays.AreEqual(this.H, H))
{
return;
}
this.H = Arrays.Clone(H);
M[0] = new uint[16][];
M[1] = new uint[16][];
M[0][0] = new uint[4];
M[1][0] = new uint[4];
M[1][8] = GcmUtilities.AsUints(H);
for (int j = 4; j >= 1; j >>= 1)
{
uint[] tmp = (uint[])M[1][j + j].Clone();
GcmUtilities.MultiplyP(tmp);
M[1][j] = tmp;
}
{
uint[] tmp = (uint[])M[1][1].Clone();
GcmUtilities.MultiplyP(tmp);
M[0][8] = tmp;
}
for (int j = 4; j >= 1; j >>= 1)
{
uint[] tmp = (uint[])M[0][j + j].Clone();
GcmUtilities.MultiplyP(tmp);
M[0][j] = tmp;
}
for (int i = 0; ; )
{
for (int j = 2; j < 16; j += j)
{
for (int k = 1; k < j; ++k)
{
uint[] tmp = (uint[])M[i][j].Clone();
GcmUtilities.Xor(tmp, M[i][k]);
M[i][j + k] = tmp;
}
}
if (++i == 32) return;
if (i > 1)
{
M[i] = new uint[16][];
M[i][0] = new uint[4];
for (int j = 8; j > 0; j >>= 1)
{
uint[] tmp = (uint[])M[i - 2][j].Clone();
GcmUtilities.MultiplyP8(tmp);
M[i][j] = tmp;
}
}
}
}
public void MultiplyH(byte[] x)
{
uint[] z = new uint[4];
for (int i = 15; i >= 0; --i)
{
//GcmUtilities.Xor(z, M[i + i][x[i] & 0x0f]);
uint[] m = M[i + i][x[i] & 0x0f];
z[0] ^= m[0];
z[1] ^= m[1];
z[2] ^= m[2];
z[3] ^= m[3];
//GcmUtilities.Xor(z, M[i + i + 1][(x[i] & 0xf0) >> 4]);
m = M[i + i + 1][(x[i] & 0xf0) >> 4];
z[0] ^= m[0];
z[1] ^= m[1];
z[2] ^= m[2];
z[3] ^= m[3];
}
Pack.UInt32_To_BE(z, x, 0);
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f51ca98d86f5a499b849d03b824036ac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: