/** * 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); }
/** * 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); }