Example #1
0
        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();
        }
Example #2
0
        /**
         * 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);
        }