123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- #pragma warning disable
- using System;
- using System.IO;
- using System.Text;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
- namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
- {
- public class KCcmBlockCipher: IAeadBlockCipher
- {
- private static readonly int BYTES_IN_INT = 4;
- private static readonly int BITS_IN_BYTE = 8;
- private static readonly int MAX_MAC_BIT_LENGTH = 512;
- private static readonly int MIN_MAC_BIT_LENGTH = 64;
- private IBlockCipher engine;
- private int macSize;
- private bool forEncryption;
- private byte[] initialAssociatedText;
- private byte[] mac;
- private byte[] macBlock;
- private byte[] nonce;
- private byte[] G1;
- private byte[] buffer;
- private byte[] s;
- private byte[] counter;
- private readonly MemoryStream associatedText = new MemoryStream();
- private readonly MemoryStream data = new MemoryStream();
- /*
- *
- *
- */
- private int Nb_ = 4;
- private void setNb(int Nb)
- {
- if (Nb == 4 || Nb == 6 || Nb == 8)
- {
- Nb_ = Nb;
- }
- else
- {
- throw new ArgumentException("Nb = 4 is recommended by DSTU7624 but can be changed to only 6 or 8 in this implementation");
- }
- }
- /// <summary>
- /// Base constructor. Nb value is set to 4.
- /// </summary>
- /// <param name="engine">base cipher to use under CCM.</param>
- public KCcmBlockCipher(IBlockCipher engine): this(engine, 4)
- {
- }
- /// <summary>
- /// Constructor allowing Nb configuration.
- ///
- /// Nb is a parameter specified in CCM mode of DSTU7624 standard.
- /// This parameter specifies maximum possible length of input.It should
- /// be calculated as follows: Nb = 1 / 8 * (-3 + log[2]Nmax) + 1,
- /// where Nmax - length of input message in bits.For practical reasons
- /// Nmax usually less than 4Gb, e.g. for Nmax = 2^32 - 1, Nb = 4.
- /// </summary>
- /// <param name="engine">base cipher to use under CCM.</param>
- /// <param name="Nb">Nb value to use.</param>
- public KCcmBlockCipher(IBlockCipher engine, int Nb)
- {
- this.engine = engine;
- this.macSize = engine.GetBlockSize();
- this.nonce = new byte[engine.GetBlockSize()];
- this.initialAssociatedText = new byte[engine.GetBlockSize()];
- this.mac = new byte[engine.GetBlockSize()];
- this.macBlock = new byte[engine.GetBlockSize()];
- this.G1 = new byte[engine.GetBlockSize()];
- this.buffer = new byte[engine.GetBlockSize()];
- this.s = new byte[engine.GetBlockSize()];
- this.counter = new byte[engine.GetBlockSize()];
- setNb(Nb);
- }
- public virtual void Init(bool forEncryption, ICipherParameters parameters)
- {
- ICipherParameters cipherParameters;
- if (parameters is AeadParameters)
- {
- AeadParameters param = (AeadParameters)parameters;
- if (param.MacSize > MAX_MAC_BIT_LENGTH || param.MacSize < MIN_MAC_BIT_LENGTH || param.MacSize % 8 != 0)
- {
- throw new ArgumentException("Invalid mac size specified");
- }
- nonce = param.GetNonce();
- macSize = param.MacSize / BITS_IN_BYTE;
- initialAssociatedText = param.GetAssociatedText();
- cipherParameters = param.Key;
- }
- else if (parameters is ParametersWithIV)
- {
- nonce = ((ParametersWithIV)parameters).GetIV();
- macSize = engine.GetBlockSize(); // use default blockSize for MAC if it is not specified
- initialAssociatedText = null;
- cipherParameters = ((ParametersWithIV)parameters).Parameters;
- }
- else
- {
- throw new ArgumentException("Invalid parameters specified");
- }
- this.mac = new byte[macSize];
- this.forEncryption = forEncryption;
- engine.Init(true, cipherParameters);
- counter[0] = 0x01; // defined in standard
- if (initialAssociatedText != null)
- {
- ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
- }
- }
- public virtual String AlgorithmName
- {
- get
- {
- return engine.AlgorithmName + "/KCCM";
- }
- }
- public virtual int GetBlockSize()
- {
- return engine.GetBlockSize();
- }
- public virtual IBlockCipher GetUnderlyingCipher()
- {
- return engine;
- }
- public virtual void ProcessAadByte(byte input)
- {
- associatedText.WriteByte(input);
- }
- public virtual void ProcessAadBytes(byte[] input, int inOff, int len)
- {
- associatedText.Write(input, inOff, len);
- }
- private void ProcessAAD(byte[] assocText, int assocOff, int assocLen, int dataLen)
- {
- if (assocLen - assocOff < engine.GetBlockSize())
- {
- throw new ArgumentException("authText buffer too short");
- }
- if (assocLen % engine.GetBlockSize() != 0)
- {
- throw new ArgumentException("padding not supported");
- }
- Array.Copy(nonce, 0, G1, 0, nonce.Length - Nb_ - 1);
- intToBytes(dataLen, buffer, 0); // for G1
- Array.Copy(buffer, 0, G1, nonce.Length - Nb_ - 1, BYTES_IN_INT);
- G1[G1.Length - 1] = getFlag(true, macSize);
- engine.ProcessBlock(G1, 0, macBlock, 0);
- intToBytes(assocLen, buffer, 0); // for G2
- if (assocLen <= engine.GetBlockSize() - Nb_)
- {
- for (int byteIndex = 0; byteIndex < assocLen; byteIndex++)
- {
- buffer[byteIndex + Nb_] ^= assocText[assocOff + byteIndex];
- }
- for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
- {
- macBlock[byteIndex] ^= buffer[byteIndex];
- }
- engine.ProcessBlock(macBlock, 0, macBlock, 0);
- return;
- }
- for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
- {
- macBlock[byteIndex] ^= buffer[byteIndex];
- }
- engine.ProcessBlock(macBlock, 0, macBlock, 0);
- int authLen = assocLen;
- while (authLen != 0)
- {
- for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
- {
- macBlock[byteIndex] ^= assocText[byteIndex + assocOff];
- }
- engine.ProcessBlock(macBlock, 0, macBlock, 0);
- assocOff += engine.GetBlockSize();
- authLen -= engine.GetBlockSize();
- }
- }
- public virtual int ProcessByte(byte input, byte[] output, int outOff)
- {
- data.WriteByte(input);
- return 0;
- }
- public virtual int ProcessBytes(byte[] input, int inOff, int inLen, byte[] output, int outOff)
- {
- Check.DataLength(input, inOff, inLen, "input buffer too short");
- data.Write(input, inOff, inLen);
- return 0;
- }
- public int ProcessPacket(byte[] input, int inOff, int len, byte[] output, int outOff)
- {
- Check.DataLength(input, inOff, len, "input buffer too short");
- Check.OutputLength(output, outOff, len, "output buffer too short");
- if (associatedText.Length > 0)
- {
- #if PORTABLE || NETFX_CORE
- byte[] aad = associatedText.ToArray();
- int aadLen = aad.Length;
- #else
- byte[] aad = associatedText.GetBuffer();
- int aadLen = (int)associatedText.Length;
- #endif
- int dataLen = forEncryption ? (int)data.Length : ((int)data.Length - macSize);
- ProcessAAD(aad, 0, aadLen, dataLen);
- }
- if (forEncryption)
- {
- Check.DataLength(len % engine.GetBlockSize() != 0, "partial blocks not supported");
- CalculateMac(input, inOff, len);
- engine.ProcessBlock(nonce, 0, s, 0);
- int totalLength = len;
- while (totalLength > 0)
- {
- ProcessBlock(input, inOff, len, output, outOff);
- totalLength -= engine.GetBlockSize();
- inOff += engine.GetBlockSize();
- outOff += engine.GetBlockSize();
- }
- for (int byteIndex = 0; byteIndex<counter.Length; byteIndex++)
- {
- s[byteIndex] += counter[byteIndex];
- }
- engine.ProcessBlock(s, 0, buffer, 0);
- for (int byteIndex = 0; byteIndex<macSize; byteIndex++)
- {
- output[outOff + byteIndex] = (byte)(buffer[byteIndex] ^ macBlock[byteIndex]);
- }
- Array.Copy(macBlock, 0, mac, 0, macSize);
- Reset();
- return len + macSize;
- }
- else
- {
- Check.DataLength((len - macSize) % engine.GetBlockSize() != 0, "partial blocks not supported");
- engine.ProcessBlock(nonce, 0, s, 0);
- int blocks = len / engine.GetBlockSize();
- for (int blockNum = 0; blockNum<blocks; blockNum++)
- {
- ProcessBlock(input, inOff, len, output, outOff);
- inOff += engine.GetBlockSize();
- outOff += engine.GetBlockSize();
- }
- if (len > inOff)
- {
- for (int byteIndex = 0; byteIndex<counter.Length; byteIndex++)
- {
- s[byteIndex] += counter[byteIndex];
- }
- engine.ProcessBlock(s, 0, buffer, 0);
- for (int byteIndex = 0; byteIndex<macSize; byteIndex++)
- {
- output[outOff + byteIndex] = (byte)(buffer[byteIndex] ^ input[inOff + byteIndex]);
- }
- outOff += macSize;
- }
- for (int byteIndex = 0; byteIndex<counter.Length; byteIndex++)
- {
- s[byteIndex] += counter[byteIndex];
- }
- engine.ProcessBlock(s, 0, buffer, 0);
- Array.Copy(output, outOff - macSize, buffer, 0, macSize);
- CalculateMac(output, 0, outOff - macSize);
- Array.Copy(macBlock, 0, mac, 0, macSize);
- byte[] calculatedMac = new byte[macSize];
- Array.Copy(buffer, 0, calculatedMac, 0, macSize);
- if (!Arrays.ConstantTimeAreEqual(mac, calculatedMac))
- {
- throw new InvalidCipherTextException("mac check failed");
- }
- Reset();
- return len - macSize;
- }
- }
- private void ProcessBlock(byte[] input, int inOff, int len, byte[] output, int outOff)
- {
- for (int byteIndex = 0; byteIndex < counter.Length; byteIndex++)
- {
- s[byteIndex] += counter[byteIndex];
- }
- engine.ProcessBlock(s, 0, buffer, 0);
- for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
- {
- output[outOff + byteIndex] = (byte)(buffer[byteIndex] ^ input[inOff + byteIndex]);
- }
- }
- private void CalculateMac(byte[] authText, int authOff, int len)
- {
- int totalLen = len;
- while (totalLen > 0)
- {
- for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
- {
- macBlock[byteIndex] ^= authText[authOff + byteIndex];
- }
- engine.ProcessBlock(macBlock, 0, macBlock, 0);
- totalLen -= engine.GetBlockSize();
- authOff += engine.GetBlockSize();
- }
- }
- public virtual int DoFinal(byte[] output, int outOff)
- {
- #if PORTABLE || NETFX_CORE
- byte[] buf = data.ToArray();
- int bufLen = buf.Length;
- #else
- byte[] buf = data.GetBuffer();
- int bufLen = (int)data.Length;
- #endif
- int len = ProcessPacket(buf, 0, bufLen, output, outOff);
- Reset();
- return len;
- }
- public virtual byte[] GetMac()
- {
- return Arrays.Clone(mac);
- }
- public virtual int GetUpdateOutputSize(int len)
- {
- return len;
- }
- public virtual int GetOutputSize(int len)
- {
- return len + macSize;
- }
- public virtual void Reset()
- {
- Arrays.Fill(G1, (byte)0);
- Arrays.Fill(buffer, (byte)0);
- Arrays.Fill(counter, (byte)0);
- Arrays.Fill(macBlock, (byte)0);
- counter[0] = 0x01;
- data.SetLength(0);
- associatedText.SetLength(0);
- if (initialAssociatedText != null)
- {
- ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
- }
- }
- private void intToBytes(
- int num,
- byte[] outBytes,
- int outOff)
- {
- outBytes[outOff + 3] = (byte)(num >> 24);
- outBytes[outOff + 2] = (byte)(num >> 16);
- outBytes[outOff + 1] = (byte)(num >> 8);
- outBytes[outOff] = (byte)num;
- }
- private byte getFlag(bool authTextPresents, int macSize)
- {
- StringBuilder flagByte = new StringBuilder();
- if (authTextPresents)
- {
- flagByte.Append("1");
- }
- else
- {
- flagByte.Append("0");
- }
- switch (macSize)
- {
- case 8:
- flagByte.Append("010"); // binary 2
- break;
- case 16:
- flagByte.Append("011"); // binary 3
- break;
- case 32:
- flagByte.Append("100"); // binary 4
- break;
- case 48:
- flagByte.Append("101"); // binary 5
- break;
- case 64:
- flagByte.Append("110"); // binary 6
- break;
- }
- String binaryNb = Convert.ToString(Nb_ - 1, 2);
- while (binaryNb.Length < 4)
- {
- binaryNb = new StringBuilder(binaryNb).Insert(0, "0").ToString();
- }
- flagByte.Append(binaryNb);
- return (byte)Convert.ToInt32(flagByte.ToString(), 2);
- }
- }
- }
- #pragma warning restore
- #endif
|