diff options
Diffstat (limited to 'core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java')
-rw-r--r-- | core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java | 457 |
1 files changed, 0 insertions, 457 deletions
diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java deleted file mode 100644 index 7f870ca2..00000000 --- a/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java +++ /dev/null @@ -1,457 +0,0 @@ -package org.bouncycastle.crypto.modes; - -import java.io.ByteArrayOutputStream; - -import org.bouncycastle.crypto.BlockCipher; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.Mac; -import org.bouncycastle.crypto.OutputLengthException; -import org.bouncycastle.crypto.macs.CBCBlockCipherMac; -import org.bouncycastle.crypto.params.AEADParameters; -import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.util.Arrays; - -/** - * 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. - */ -public class CCMBlockCipher - implements AEADBlockCipher -{ - private BlockCipher cipher; - private int blockSize; - private boolean forEncryption; - private byte[] nonce; - private byte[] initialAssociatedText; - private int macSize; - private CipherParameters keyParam; - private byte[] macBlock; - private ExposedByteArrayOutputStream associatedText = new ExposedByteArrayOutputStream(); - private ExposedByteArrayOutputStream data = new ExposedByteArrayOutputStream(); - - /** - * Basic constructor. - * - * @param c the block cipher to be used. - */ - public CCMBlockCipher(BlockCipher c) - { - this.cipher = c; - this.blockSize = c.getBlockSize(); - this.macBlock = new byte[blockSize]; - - if (blockSize != 16) - { - throw new IllegalArgumentException("cipher required with a block size of 16."); - } - } - - /** - * return the underlying block cipher that we are wrapping. - * - * @return the underlying block cipher that we are wrapping. - */ - public BlockCipher getUnderlyingCipher() - { - return cipher; - } - - - public void init(boolean forEncryption, CipherParameters params) - throws IllegalArgumentException - { - this.forEncryption = forEncryption; - - CipherParameters cipherParameters; - if (params instanceof AEADParameters) - { - AEADParameters param = (AEADParameters)params; - - nonce = param.getNonce(); - initialAssociatedText = param.getAssociatedText(); - macSize = param.getMacSize() / 8; - cipherParameters = param.getKey(); - } - else if (params instanceof ParametersWithIV) - { - ParametersWithIV param = (ParametersWithIV)params; - - nonce = param.getIV(); - initialAssociatedText = null; - macSize = macBlock.length / 2; - cipherParameters = param.getParameters(); - } - else - { - throw new IllegalArgumentException("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 IllegalArgumentException("nonce must have length from 7 to 13 octets"); - } - - reset(); - } - - public String getAlgorithmName() - { - return cipher.getAlgorithmName() + "/CCM"; - } - - public void processAADByte(byte in) - { - associatedText.write(in); - } - - public void processAADBytes(byte[] in, int inOff, int len) - { - // TODO: Process AAD online - associatedText.write(in, inOff, len); - } - - public int processByte(byte in, byte[] out, int outOff) - throws DataLengthException, IllegalStateException - { - data.write(in); - - return 0; - } - - public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff) - throws DataLengthException, IllegalStateException - { - if (in.length < (inOff + inLen)) - { - throw new DataLengthException("Input buffer too short"); - } - data.write(in, inOff, inLen); - - return 0; - } - - public int doFinal(byte[] out, int outOff) - throws IllegalStateException, InvalidCipherTextException - { - int len = processPacket(data.getBuffer(), 0, data.size(), out, outOff); - - reset(); - - return len; - } - - public void reset() - { - cipher.reset(); - associatedText.reset(); - data.reset(); - } - - /** - * Returns a byte array containing the mac calculated as part of the - * last encrypt or decrypt operation. - * - * @return the last mac calculated. - */ - public byte[] getMac() - { - byte[] mac = new byte[macSize]; - - System.arraycopy(macBlock, 0, mac, 0, mac.length); - - return mac; - } - - public int getUpdateOutputSize(int len) - { - return 0; - } - - public int getOutputSize(int len) - { - int totalData = len + data.size(); - - 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 byte[] processPacket(byte[] in, int inOff, int inLen) - throws IllegalStateException, InvalidCipherTextException - { - 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(in, 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 int processPacket(byte[] in, int inOff, int inLen, byte[] output, int outOff) - throws IllegalStateException, InvalidCipherTextException, DataLengthException - { - // 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 IllegalStateException("CCM cipher unitialized."); - } - - int n = nonce.length; - int q = 15 - n; - if (q < 4) - { - int limitLen = 1 << (8 * q); - if (inLen >= limitLen) - { - throw new IllegalStateException("CCM packet too large for choice of q."); - } - } - - byte[] iv = new byte[blockSize]; - iv[0] = (byte)((q - 1) & 0x7); - System.arraycopy(nonce, 0, iv, 1, nonce.length); - - BlockCipher ctrCipher = new SICBlockCipher(cipher); - ctrCipher.init(forEncryption, new ParametersWithIV(keyParam, iv)); - - int outputLen; - int inIndex = inOff; - int outIndex = outOff; - - if (forEncryption) - { - outputLen = inLen + macSize; - if (output.length < (outputLen + outOff)) - { - throw new OutputLengthException("Output buffer too short."); - } - - calculateMac(in, inOff, inLen, macBlock); - - ctrCipher.processBlock(macBlock, 0, macBlock, 0); // S0 - - while (inIndex < (inOff + inLen - blockSize)) // S1... - { - ctrCipher.processBlock(in, inIndex, output, outIndex); - outIndex += blockSize; - inIndex += blockSize; - } - - byte[] block = new byte[blockSize]; - - System.arraycopy(in, inIndex, block, 0, inLen + inOff - inIndex); - - ctrCipher.processBlock(block, 0, block, 0); - - System.arraycopy(block, 0, output, outIndex, inLen + inOff - inIndex); - - System.arraycopy(macBlock, 0, output, outOff + inLen, macSize); - } - else - { - if (inLen < macSize) - { - throw new InvalidCipherTextException("data too short"); - } - outputLen = inLen - macSize; - if (output.length < (outputLen + outOff)) - { - throw new OutputLengthException("Output buffer too short."); - } - - System.arraycopy(in, 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(in, inIndex, output, outIndex); - outIndex += blockSize; - inIndex += blockSize; - } - - byte[] block = new byte[blockSize]; - - System.arraycopy(in, inIndex, block, 0, outputLen - (inIndex - inOff)); - - ctrCipher.processBlock(block, 0, block, 0); - - System.arraycopy(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) - { - Mac cMac = new CBCBlockCipherMac(cipher, macSize * 8); - - cMac.init(keyParam); - - // - // build b0 - // - byte[] b0 = new byte[16]; - - if (hasAssociatedText()) - { - b0[0] |= 0x40; - } - - b0[0] |= (((cMac.getMacSize() - 2) / 2) & 0x7) << 3; - - b0[0] |= ((15 - nonce.length) - 1) & 0x7; - - System.arraycopy(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.update(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.update(initialAssociatedText, 0, initialAssociatedText.length); - } - if (associatedText.size() > 0) - { - cMac.update(associatedText.getBuffer(), 0, associatedText.size()); - } - - extra = (extra + textLength) % 16; - if (extra != 0) - { - for (int i = extra; i != 16; i++) - { - cMac.update((byte)0x00); - } - } - } - - // - // add the text - // - cMac.update(data, dataOff, dataLen); - - return cMac.doFinal(macBlock, 0); - } - - private int getAssociatedTextLength() - { - return associatedText.size() + ((initialAssociatedText == null) ? 0 : initialAssociatedText.length); - } - - private boolean hasAssociatedText() - { - return getAssociatedTextLength() > 0; - } - - private class ExposedByteArrayOutputStream - extends ByteArrayOutputStream - { - public ExposedByteArrayOutputStream() - { - } - - public byte[] getBuffer() - { - return this.buf; - } - } -} |