diff options
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto/modes')
18 files changed, 990 insertions, 494 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java index 71b75954..fe461196 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java @@ -7,6 +7,16 @@ import org.bouncycastle.crypto.InvalidCipherTextException; /** * A block cipher mode that includes authenticated encryption with a streaming mode and optional associated data. + * <p> + * Implementations of this interface may operate in a packet mode (where all input data is buffered and + * processed dugin the call to {@link #doFinal(byte[], int)}), or in a streaming mode (where output data is + * incrementally produced with each call to {@link #processByte(byte, byte[], int)} or + * {@link #processBytes(byte[], int, int, byte[], int)}. + * </p> + * This is important to consider during decryption: in a streaming mode, unauthenticated plaintext data + * may be output prior to the call to {@link #doFinal(byte[], int)} that results in an authentication + * failure. The higher level protocol utilising this cipher must ensure the plaintext data is handled + * appropriately until the end of data is reached and the entire ciphertext is authenticated. * @see org.bouncycastle.crypto.params.AEADParameters */ public interface AEADBlockCipher @@ -101,6 +111,11 @@ public interface AEADBlockCipher /** * return the size of the output buffer required for a processBytes * an input of len bytes. + * <p> + * The returned size may be dependent on the initialisation of this cipher + * and may not be accurate once subsequent input data is processed - this method + * should be invoked immediately prior to input data being processed. + * </p> * * @param len the length of the input. * @return the space required to accommodate a call to processBytes @@ -111,7 +126,12 @@ public interface AEADBlockCipher /** * return the size of the output buffer required for a processBytes plus a * doFinal with an input of len bytes. - * + * <p> + * The returned size may be dependent on the initialisation of this cipher + * and may not be accurate once subsequent input data is processed - this method + * should be invoked immediately prior to a call to final processing of input data + * and a call to {@link #doFinal(byte[], int)}. + * </p> * @param len the length of the input. * @return the space required to accommodate a call to processBytes and doFinal * with len bytes of input. diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java index fef51fdb..7f870ca2 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java @@ -7,6 +7,7 @@ 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; @@ -42,7 +43,7 @@ public class CCMBlockCipher 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."); @@ -99,7 +100,7 @@ public class CCMBlockCipher { throw new IllegalArgumentException("nonce must have length from 7 to 13 octets"); } - + reset(); } @@ -130,6 +131,10 @@ public class CCMBlockCipher 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; @@ -155,15 +160,15 @@ public class CCMBlockCipher /** * 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; } @@ -267,7 +272,7 @@ public class CCMBlockCipher outputLen = inLen + macSize; if (output.length < (outputLen + outOff)) { - throw new DataLengthException("Output buffer too short."); + throw new OutputLengthException("Output buffer too short."); } calculateMac(in, inOff, inLen, macBlock); @@ -300,7 +305,7 @@ public class CCMBlockCipher outputLen = inLen - macSize; if (output.length < (outputLen + outOff)) { - throw new DataLengthException("Output buffer too short."); + throw new OutputLengthException("Output buffer too short."); } System.arraycopy(in, inOff + outputLen, macBlock, 0, macSize); @@ -350,18 +355,18 @@ public class CCMBlockCipher // 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) @@ -370,22 +375,22 @@ public class CCMBlockCipher 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 @@ -396,7 +401,7 @@ public class CCMBlockCipher cMac.update((byte)(textLength >> 16)); cMac.update((byte)(textLength >> 8)); cMac.update((byte)textLength); - + extra = 6; } @@ -418,7 +423,7 @@ public class CCMBlockCipher } } } - + // // add the text // diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java index a8851690..6167d256 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java @@ -3,6 +3,7 @@ package org.bouncycastle.crypto.modes; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.StreamBlockCipher; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.util.Arrays; @@ -10,15 +11,17 @@ import org.bouncycastle.util.Arrays; * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher. */ public class CFBBlockCipher - implements BlockCipher + extends StreamBlockCipher { private byte[] IV; private byte[] cfbV; private byte[] cfbOutV; + private byte[] inBuf; private int blockSize; private BlockCipher cipher = null; private boolean encrypting; + private int byteCount; /** * Basic constructor. @@ -31,22 +34,15 @@ public class CFBBlockCipher BlockCipher cipher, int bitBlockSize) { + super(cipher); + 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 BlockCipher getUnderlyingCipher() - { - return cipher; + this.inBuf = new byte[blockSize]; } /** @@ -117,6 +113,54 @@ public class CFBBlockCipher return cipher.getAlgorithmName() + "/CFB" + (blockSize * 8); } + protected byte calculateByte(byte in) + throws DataLengthException, IllegalStateException + { + return (encrypting) ? encryptByte(in) : decryptByte(in); + } + + private byte encryptByte(byte in) + { + if (byteCount == 0) + { + cipher.processBlock(cfbV, 0, cfbOutV, 0); + } + + byte rv = (byte)(cfbOutV[byteCount] ^ in); + inBuf[byteCount++] = rv; + + if (byteCount == blockSize) + { + byteCount = 0; + + System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize); + System.arraycopy(inBuf, 0, cfbV, cfbV.length - blockSize, blockSize); + } + + return rv; + } + + private byte decryptByte(byte in) + { + if (byteCount == 0) + { + cipher.processBlock(cfbV, 0, cfbOutV, 0); + } + + inBuf[byteCount] = in; + byte rv = (byte)(cfbOutV[byteCount++] ^ in); + + if (byteCount == blockSize) + { + byteCount = 0; + + System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize); + System.arraycopy(inBuf, 0, cfbV, cfbV.length - blockSize, blockSize); + } + + return rv; + } + /** * return the block size we are operating at. * @@ -147,7 +191,9 @@ public class CFBBlockCipher int outOff) throws DataLengthException, IllegalStateException { - return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff); + processBytes(in, inOff, blockSize, out, outOff); + + return blockSize; } /** @@ -169,31 +215,7 @@ public class CFBBlockCipher int outOff) throws DataLengthException, IllegalStateException { - if ((inOff + blockSize) > in.length) - { - throw new DataLengthException("input buffer too short"); - } - - if ((outOff + blockSize) > out.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++) - { - out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]); - } - - // - // change over the input block. - // - System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize); - System.arraycopy(out, outOff, cfbV, cfbV.length - blockSize, blockSize); + processBytes(in, inOff, blockSize, out, outOff); return blockSize; } @@ -217,31 +239,7 @@ public class CFBBlockCipher int outOff) throws DataLengthException, IllegalStateException { - if ((inOff + blockSize) > in.length) - { - throw new DataLengthException("input buffer too short"); - } - - if ((outOff + blockSize) > out.length) - { - throw new DataLengthException("output buffer too short"); - } - - cipher.processBlock(cfbV, 0, cfbOutV, 0); - - // - // change over the input block. - // - System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize); - System.arraycopy(in, inOff, cfbV, cfbV.length - blockSize, blockSize); - - // - // XOR the cfbV with the ciphertext producing the plaintext - // - for (int i = 0; i < blockSize; i++) - { - out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]); - } + processBytes(in, inOff, blockSize, out, outOff); return blockSize; } @@ -263,6 +261,8 @@ public class CFBBlockCipher public void reset() { System.arraycopy(IV, 0, cfbV, 0, IV.length); + Arrays.fill(inBuf, (byte)0); + byteCount = 0; cipher.reset(); } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java index 5388b407..64b076dd 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java @@ -4,6 +4,7 @@ import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.StreamBlockCipher; /** * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to @@ -22,9 +23,8 @@ public class CTSBlockCipher public CTSBlockCipher( BlockCipher cipher) { - if ((cipher instanceof OFBBlockCipher) || (cipher instanceof CFBBlockCipher) || (cipher instanceof SICBlockCipher)) + if (cipher instanceof StreamBlockCipher) { - // TODO: This is broken - need to introduce marker interface to differentiate block cipher primitive from mode? throw new IllegalArgumentException("CTSBlockCipher can only accept ECB, or CBC ciphers"); } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java index 8f740006..209d5cdb 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java @@ -5,22 +5,23 @@ 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.CMac; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.util.Arrays; /** - * A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and + * 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 + * + * 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 @@ -43,7 +44,7 @@ public class EAXBlockCipher private byte[] nonceMac; private byte[] associatedTextMac; private byte[] macBlock; - + private int macSize; private byte[] bufBlock; private int bufOff; @@ -61,7 +62,6 @@ public class EAXBlockCipher blockSize = cipher.getBlockSize(); mac = new CMac(cipher); macBlock = new byte[blockSize]; - bufBlock = new byte[blockSize * 2]; associatedTextMac = new byte[mac.getMacSize()]; nonceMac = new byte[mac.getMacSize()]; this.cipher = new SICBlockCipher(cipher); @@ -113,6 +113,8 @@ public class EAXBlockCipher throw new IllegalArgumentException("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 @@ -123,9 +125,9 @@ public class EAXBlockCipher mac.update(nonce, 0, nonce.length); mac.doFinal(nonceMac, 0); - // Same BlockCipher underlies this and the mac, so reuse last key on cipher + // Same BlockCipher underlies this and the mac, so reuse last key on cipher cipher.init(true, new ParametersWithIV(null, nonceMac)); - + reset(); } @@ -218,6 +220,11 @@ public class EAXBlockCipher { initCipher(); + if (in.length < (inOff + len)) + { + throw new DataLengthException("Input buffer too short"); + } + int resultLen = 0; for (int i = 0; i != len; i++) @@ -240,12 +247,11 @@ public class EAXBlockCipher if (forEncryption) { - if (out.length < (outOff + extra)) + if (out.length < (outOff + extra + macSize)) { - throw new DataLengthException("Output buffer too short"); + throw new OutputLengthException("Output buffer too short"); } cipher.processBlock(bufBlock, 0, tmp, 0); - cipher.processBlock(bufBlock, blockSize, tmp, blockSize); System.arraycopy(tmp, 0, out, outOff, extra); @@ -261,6 +267,10 @@ public class EAXBlockCipher } else { + if (out.length < (outOff + extra - macSize)) + { + throw new OutputLengthException("Output buffer too short"); + } if (extra < macSize) { throw new InvalidCipherTextException("data too short"); @@ -270,7 +280,6 @@ public class EAXBlockCipher mac.update(bufBlock, 0, extra - macSize); cipher.processBlock(bufBlock, 0, tmp, 0); - cipher.processBlock(bufBlock, blockSize, tmp, blockSize); System.arraycopy(tmp, 0, out, outOff, extra - macSize); } @@ -329,6 +338,10 @@ public class EAXBlockCipher if (bufOff == bufBlock.length) { + if (out.length < (outOff + blockSize)) + { + throw new OutputLengthException("Output buffer is too short"); + } // TODO Could move the processByte(s) calls to here // initCipher(); @@ -347,8 +360,12 @@ public class EAXBlockCipher size = cipher.processBlock(bufBlock, 0, out, outOff); } - bufOff = blockSize; - System.arraycopy(bufBlock, blockSize, bufBlock, 0, blockSize); + bufOff = 0; + if (!forEncryption) + { + System.arraycopy(bufBlock, blockSize, bufBlock, 0, macSize); + bufOff = macSize; + } return size; } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCFBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCFBBlockCipher.java index 887c1697..5791e89c 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCFBBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCFBBlockCipher.java @@ -3,6 +3,7 @@ package org.bouncycastle.crypto.modes; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.StreamBlockCipher; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.crypto.params.ParametersWithRandom; @@ -12,7 +13,7 @@ import org.bouncycastle.crypto.params.ParametersWithSBox; * An implementation of the GOST CFB mode with CryptoPro key meshing as described in RFC 4357. */ public class GCFBBlockCipher - implements BlockCipher + extends StreamBlockCipher { private static final byte[] C = { @@ -30,6 +31,8 @@ public class GCFBBlockCipher public GCFBBlockCipher(BlockCipher engine) { + super(engine); + this.cfbEngine = new CFBBlockCipher(engine, engine.getBlockSize() * 8); } @@ -61,7 +64,8 @@ public class GCFBBlockCipher public String getAlgorithmName() { - return "G" + cfbEngine.getAlgorithmName(); + String name = cfbEngine.getAlgorithmName(); + return name.substring(0, name.indexOf('/') - 1) + "/G" + name.substring(name.indexOf('/') + 1); } public int getBlockSize() @@ -72,6 +76,13 @@ public class GCFBBlockCipher public int processBlock(byte[] in, int inOff, byte[] out, int outOff) throws DataLengthException, IllegalStateException { + this.processBytes(in, inOff, cfbEngine.getBlockSize(), out, outOff); + + return cfbEngine.getBlockSize(); + } + + protected byte calculateByte(byte b) + { if (counter > 0 && counter % 1024 == 0) { BlockCipher base = cfbEngine.getUnderlyingCipher(); @@ -87,18 +98,18 @@ public class GCFBBlockCipher key = new KeyParameter(nextKey); - byte[] iv = new byte[8]; - base.init(true, key); - base.processBlock(cfbEngine.getCurrentIV(), 0, iv, 0); + byte[] iv = cfbEngine.getCurrentIV(); + + base.processBlock(iv, 0, iv, 0); cfbEngine.init(forEncryption, new ParametersWithIV(key, iv)); } - counter += cfbEngine.getBlockSize(); + counter++; - return cfbEngine.processBlock(in, inOff, out, outOff); + return cfbEngine.calculateByte(b); } public void reset() diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java index 9e617ec9..93f0fe92 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java @@ -4,15 +4,17 @@ import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.modes.gcm.GCMExponentiator; import org.bouncycastle.crypto.modes.gcm.GCMMultiplier; +import org.bouncycastle.crypto.modes.gcm.GCMUtil; import org.bouncycastle.crypto.modes.gcm.Tables1kGCMExponentiator; import org.bouncycastle.crypto.modes.gcm.Tables8kGCMMultiplier; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.crypto.util.Pack; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; /** * Implements the Galois/Counter mode (GCM) detailed in @@ -23,7 +25,7 @@ public class GCMBlockCipher { private static final int BLOCK_SIZE = 16; - // not final due to a compiler bug + // not final due to a compiler bug private BlockCipher cipher; private GCMMultiplier multiplier; private GCMExponentiator exp; @@ -81,6 +83,10 @@ public class GCMBlockCipher return cipher.getAlgorithmName() + "/GCM"; } + /** + * NOTE: 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. + */ public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException { @@ -97,12 +103,12 @@ public class GCMBlockCipher initialAssociatedText = param.getAssociatedText(); int macSizeBits = param.getMacSize(); - if (macSizeBits < 96 || macSizeBits > 128 || macSizeBits % 8 != 0) + if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0) { throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits); } - macSize = macSizeBits / 8; + macSize = macSizeBits / 8; keyParam = param.getKey(); } else if (params instanceof ParametersWithIV) @@ -119,7 +125,7 @@ public class GCMBlockCipher throw new IllegalArgumentException("invalid parameters passed to GCM"); } - int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize); + int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize); this.bufBlock = new byte[bufLength]; if (nonce == null || nonce.length < 1) @@ -127,9 +133,7 @@ public class GCMBlockCipher throw new IllegalArgumentException("IV must be at least 1 byte"); } - // TODO This should be configurable by init parameters - // (but must be 16 if nonce length not 12) (BLOCK_SIZE?) -// this.tagLength = 16; + // 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. @@ -144,6 +148,10 @@ public class GCMBlockCipher multiplier.init(H); exp = null; } + else if (this.H == null) + { + throw new IllegalArgumentException("Key must be specified in initial init"); + } this.J0 = new byte[BLOCK_SIZE]; @@ -188,7 +196,7 @@ public class GCMBlockCipher if (forEncryption) { - return totalData + macSize; + return totalData + macSize; } return totalData < macSize ? 0 : totalData - macSize; @@ -271,6 +279,10 @@ public class GCMBlockCipher public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException { + if (in.length < (inOff + len)) + { + throw new DataLengthException("Input buffer too short"); + } int resultLen = 0; for (int i = 0; i < len; ++i) @@ -288,6 +300,10 @@ public class GCMBlockCipher private void outputBlock(byte[] output, int offset) { + if (output.length < (offset + BLOCK_SIZE)) + { + throw new OutputLengthException("Output buffer too short"); + } if (totalLength == 0) { initCipher(); @@ -324,6 +340,10 @@ public class GCMBlockCipher if (extra > 0) { + if (out.length < (outOff + extra)) + { + throw new OutputLengthException("Output buffer too short"); + } gCTRPartial(bufBlock, 0, extra, out, outOff); } @@ -347,7 +367,7 @@ public class GCMBlockCipher // Find the difference between the AAD hashes if (atLengthPre > 0) { - xor(S_at, S_atPre); + GCMUtil.xor(S_at, S_atPre); } // Number of cipher-text blocks produced @@ -363,10 +383,10 @@ public class GCMBlockCipher exp.exponentiateX(c, H_c); // Carry the difference forward - multiply(S_at, H_c); + GCMUtil.multiply(S_at, H_c); // Adjust the current hash - xor(S, S_at); + GCMUtil.xor(S, S_at); } // Final gHASH @@ -376,11 +396,10 @@ public class GCMBlockCipher gHASHBlock(S, X); - // TODO Fix this if tagLength becomes configurable // T = MSBt(GCTRk(J0,S)) byte[] tag = new byte[BLOCK_SIZE]; cipher.processBlock(J0, 0, tag, 0); - xor(tag, S); + GCMUtil.xor(tag, S); int resultLen = extra; @@ -390,6 +409,10 @@ public class GCMBlockCipher if (forEncryption) { + if (out.length < (outOff + extra + macSize)) + { + throw new OutputLengthException("Output buffer too short"); + } // Append T to the message System.arraycopy(macBlock, 0, out, outOff + bufOff, macSize); resultLen += macSize; @@ -451,7 +474,7 @@ public class GCMBlockCipher { byte[] tmp = getNextCounterBlock(); - xor(tmp, block); + GCMUtil.xor(tmp, block); System.arraycopy(tmp, 0, out, outOff, BLOCK_SIZE); gHASHBlock(S, forEncryption ? tmp : block); @@ -463,7 +486,7 @@ public class GCMBlockCipher { byte[] tmp = getNextCounterBlock(); - xor(tmp, buf, off, len); + GCMUtil.xor(tmp, buf, off, len); System.arraycopy(tmp, 0, out, outOff, len); gHASHPartial(S, forEncryption ? tmp : buf, 0, len); @@ -482,13 +505,13 @@ public class GCMBlockCipher private void gHASHBlock(byte[] Y, byte[] b) { - xor(Y, b); + GCMUtil.xor(Y, b); multiplier.multiplyH(Y); } private void gHASHPartial(byte[] Y, byte[] b, int off, int len) { - xor(Y, b, off, len); + GCMUtil.xor(Y, b, off, len); multiplier.multiplyH(Y); } @@ -510,65 +533,4 @@ public class GCMBlockCipher cipher.processBlock(counter, 0, tmp, 0); return tmp; } - - private static void multiply(byte[] block, byte[] val) - { - byte[] tmp = Arrays.clone(block); - byte[] c = new byte[16]; - - for (int i = 0; i < 16; ++i) - { - byte bits = val[i]; - for (int j = 7; j >= 0; --j) - { - if ((bits & (1 << j)) != 0) - { - xor(c, tmp); - } - - boolean lsb = (tmp[15] & 1) != 0; - shiftRight(tmp); - if (lsb) - { - // R = new byte[]{ 0xe1, ... }; -// xor(v, R); - tmp[0] ^= (byte)0xe1; - } - } - } - - System.arraycopy(c, 0, block, 0, 16); - } - - private static void shiftRight(byte[] block) - { - int i = 0; - int bit = 0; - for (;;) - { - int b = block[i] & 0xff; - block[i] = (byte) ((b >>> 1) | bit); - if (++i == 16) - { - break; - } - bit = (b & 1) << 7; - } - } - - private static void xor(byte[] block, byte[] val) - { - for (int i = 15; i >= 0; --i) - { - block[i] ^= val[i]; - } - } - - private static void xor(byte[] block, byte[] val, int off, int len) - { - while (len-- > 0) - { - block[len] ^= val[off + len]; - } - } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GOFBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GOFBBlockCipher.java index 0e66cf3f..b025a1b8 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GOFBBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GOFBBlockCipher.java @@ -3,17 +3,19 @@ package org.bouncycastle.crypto.modes; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.StreamBlockCipher; import org.bouncycastle.crypto.params.ParametersWithIV; /** * implements the GOST 28147 OFB counter mode (GCTR). */ public class GOFBBlockCipher - implements BlockCipher + extends StreamBlockCipher { private byte[] IV; private byte[] ofbV; private byte[] ofbOutV; + private int byteCount; private final int blockSize; private final BlockCipher cipher; @@ -34,6 +36,8 @@ public class GOFBBlockCipher public GOFBBlockCipher( BlockCipher cipher) { + super(cipher); + this.cipher = cipher; this.blockSize = cipher.getBlockSize(); @@ -48,16 +52,6 @@ public class GOFBBlockCipher } /** - * return the underlying block cipher that we are wrapping. - * - * @return the underlying block cipher that we are wrapping. - */ - public BlockCipher 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. @@ -127,7 +121,6 @@ public class GOFBBlockCipher return cipher.getAlgorithmName() + "/GCTR"; } - /** * return the block size we are operating at (in bytes). * @@ -158,44 +151,7 @@ public class GOFBBlockCipher int outOff) throws DataLengthException, IllegalStateException { - if ((inOff + blockSize) > in.length) - { - throw new DataLengthException("input buffer too short"); - } - - if ((outOff + blockSize) > out.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++) - { - out[outOff + i] = (byte)(ofbOutV[i] ^ in[inOff + i]); - } - - // - // change over the input block. - // - System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize); - System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize); + processBytes(in, inOff, blockSize, out, outOff); return blockSize; } @@ -210,7 +166,7 @@ public class GOFBBlockCipher N3 = 0; N4 = 0; System.arraycopy(IV, 0, ofbV, 0, IV.length); - + byteCount = 0; cipher.reset(); } @@ -234,4 +190,39 @@ public class GOFBBlockCipher out[outOff + 1] = (byte)(num >>> 8); out[outOff] = (byte)num; } + + protected byte calculateByte(byte b) + { + if (byteCount == 0) + { + 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); + } + + byte rv = (byte)(ofbOutV[byteCount++] ^ b); + + if (byteCount == blockSize) + { + byteCount = 0; + + // + // change over the input block. + // + System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize); + System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize); + } + + return rv; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/NISTCTSBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/NISTCTSBlockCipher.java new file mode 100644 index 00000000..fe7bf971 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/NISTCTSBlockCipher.java @@ -0,0 +1,337 @@ +/** + * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to + * be used to produce cipher text which is the same length as the plain text. + */ +package org.bouncycastle.crypto.modes; + +import org.bouncycastle.crypto.BlockCipher; +import org.bouncycastle.crypto.BufferedBlockCipher; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.StreamBlockCipher; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; + +/** + * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to + * be used to produce cipher text which is the same length as the plain text. + * <p> + * This class implements the NIST version as documented in "Addendum to NIST SP 800-38A, Recommendation for Block Cipher Modes of Operation: Three Variants of Ciphertext Stealing for CBC Mode" + * </p> + */ +public class NISTCTSBlockCipher + extends BufferedBlockCipher +{ + public static final int CS1 = 1; + public static final int CS2 = 2; + public static final int CS3 = 3; + + private final int type; + private final int blockSize; + + /** + * Create a buffered block cipher that uses NIST Cipher Text Stealing + * + * @param type type of CTS mode (CS1, CS2, or CS3) + * @param cipher the underlying block cipher used to create the CBC block cipher this cipher uses.. + */ + public NISTCTSBlockCipher( + int type, + BlockCipher cipher) + { + this.type = type; + this.cipher = new CBCBlockCipher(cipher); + + blockSize = cipher.getBlockSize(); + + buf = new byte[blockSize * 2]; + bufOff = 0; + } + + /** + * return the size of the output buffer required for an update + * an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to update + * with len bytes of input. + */ + public int getUpdateOutputSize( + int len) + { + int total = len + 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 len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to update and doFinal + * with len bytes of input. + */ + public int getOutputSize( + int len) + { + return len + 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 org.bouncycastle.crypto.DataLengthException if there isn't enough space in out. + * @exception IllegalStateException if the cipher isn't initialised. + */ + public int processByte( + byte in, + byte[] out, + int outOff) + throws DataLengthException, IllegalStateException + { + int resultLen = 0; + + if (bufOff == buf.length) + { + resultLen = cipher.processBlock(buf, 0, out, outOff); + System.arraycopy(buf, blockSize, buf, 0, blockSize); + + bufOff = blockSize; + } + + buf[bufOff++] = in; + + 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 len 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 org.bouncycastle.crypto.DataLengthException if there isn't enough space in out. + * @exception IllegalStateException if the cipher isn't initialised. + */ + public int processBytes( + byte[] in, + int inOff, + int len, + byte[] out, + int outOff) + throws DataLengthException, IllegalStateException + { + if (len < 0) + { + throw new IllegalArgumentException("Can't have a negative input length!"); + } + + int blockSize = getBlockSize(); + int length = getUpdateOutputSize(len); + + if (length > 0) + { + if ((outOff + length) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + } + + int resultLen = 0; + int gapLen = buf.length - bufOff; + + if (len > gapLen) + { + System.arraycopy(in, inOff, buf, bufOff, gapLen); + + resultLen += cipher.processBlock(buf, 0, out, outOff); + System.arraycopy(buf, blockSize, buf, 0, blockSize); + + bufOff = blockSize; + + len -= gapLen; + inOff += gapLen; + + while (len > blockSize) + { + System.arraycopy(in, inOff, buf, bufOff, blockSize); + resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen); + System.arraycopy(buf, blockSize, buf, 0, blockSize); + + len -= blockSize; + inOff += blockSize; + } + } + + System.arraycopy(in, inOff, buf, bufOff, len); + + bufOff += len; + + 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 org.bouncycastle.crypto.DataLengthException if there is insufficient space in out for + * the output. + * @exception IllegalStateException if the underlying cipher is not + * initialised. + * @exception org.bouncycastle.crypto.InvalidCipherTextException if cipher text decrypts wrongly (in + * case the exception will never get thrown). + */ + public int doFinal( + byte[] out, + int outOff) + throws DataLengthException, IllegalStateException, InvalidCipherTextException + { + if (bufOff + outOff > out.length) + { + throw new DataLengthException("output buffer to small in doFinal"); + } + + int blockSize = cipher.getBlockSize(); + int len = bufOff - blockSize; + byte[] block = new byte[blockSize]; + + if (forEncryption) + { + if (bufOff < blockSize) + { + throw new DataLengthException("need at least one block of input for NISTCTS"); + } + + if (bufOff > blockSize) + { + byte[] lastBlock = new byte[blockSize]; + + if (this.type == CS2 || this.type == CS3) + { + cipher.processBlock(buf, 0, block, 0); + + System.arraycopy(buf, blockSize, lastBlock, 0, len); + + cipher.processBlock(lastBlock, 0, lastBlock, 0); + + if (this.type == CS2 && len == blockSize) + { + System.arraycopy(block, 0, out, outOff, blockSize); + + System.arraycopy(lastBlock, 0, out, outOff + blockSize, len); + } + else + { + System.arraycopy(lastBlock, 0, out, outOff, blockSize); + + System.arraycopy(block, 0, out, outOff + blockSize, len); + } + } + else + { + System.arraycopy(buf, 0, block, 0, blockSize); + cipher.processBlock(block, 0, block, 0); + System.arraycopy(block, 0, out, outOff, len); + + System.arraycopy(buf, bufOff - len, lastBlock, 0, len); + cipher.processBlock(lastBlock, 0, lastBlock, 0); + System.arraycopy(lastBlock, 0, out, outOff + len, blockSize); + } + } + else + { + cipher.processBlock(buf, 0, block, 0); + + System.arraycopy(block, 0, out, outOff, blockSize); + } + } + else + { + if (bufOff < blockSize) + { + throw new DataLengthException("need at least one block of input for CTS"); + } + + byte[] lastBlock = new byte[blockSize]; + + if (bufOff > blockSize) + { + if (this.type == CS3 || (this.type == CS2 && ((buf.length - bufOff) % blockSize) != 0)) + { + if (cipher instanceof CBCBlockCipher) + { + BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher(); + + c.processBlock(buf, 0, block, 0); + } + else + { + cipher.processBlock(buf, 0, block, 0); + } + + for (int i = blockSize; i != bufOff; i++) + { + lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]); + } + + System.arraycopy(buf, blockSize, block, 0, len); + + cipher.processBlock(block, 0, out, outOff); + System.arraycopy(lastBlock, 0, out, outOff + blockSize, len); + } + else + { + BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher(); + + c.processBlock(buf, bufOff - blockSize, lastBlock, 0); + + System.arraycopy(buf, 0, block, 0, blockSize); + + if (len != blockSize) + { + System.arraycopy(lastBlock, len, block, len, blockSize - len); + } + + cipher.processBlock(block, 0, block, 0); + + System.arraycopy(block, 0, out, outOff, blockSize); + + for (int i = 0; i != len; i++) + { + lastBlock[i] ^= buf[i]; + } + + System.arraycopy(lastBlock, 0, out, outOff + blockSize, len); + } + } + else + { + cipher.processBlock(buf, 0, block, 0); + + System.arraycopy(block, 0, out, outOff, blockSize); + } + } + + int offset = bufOff; + + reset(); + + return offset; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java index 6dc71481..86263914 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java @@ -6,29 +6,28 @@ import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.util.Arrays; /** - * An implementation of the "work in progress" Internet-Draft <a - * href="http://tools.ietf.org/html/draft-irtf-cfrg-ocb-03">The OCB Authenticated-Encryption - * Algorithm</a>, licensed per: - * <p/> + * An implementation of <a href="http://tools.ietf.org/html/rfc7253">RFC 7253 on The OCB + * Authenticated-Encryption Algorithm</a>, licensed per: + * <p> * <blockquote> <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. </blockquote> */ public class OCBBlockCipher implements AEADBlockCipher { - private static final int BLOCK_SIZE = 16; private BlockCipher hashCipher; @@ -51,7 +50,9 @@ public class OCBBlockCipher /* * NONCE-DEPENDENT */ - private byte[] OffsetMAIN_0; + private byte[] KtopInput = null; + private byte[] Stretch = new byte[24]; + private byte[] OffsetMAIN_0 = new byte[16]; /* * PER-ENCRYPTION/DECRYPTION @@ -61,7 +62,7 @@ public class OCBBlockCipher private long hashBlockCount, mainBlockCount; private byte[] OffsetHASH; private byte[] Sum; - private byte[] OffsetMAIN; + private byte[] OffsetMAIN = new byte[16]; private byte[] Checksum; // NOTE: The MAC value is preserved after doFinal @@ -111,6 +112,7 @@ public class OCBBlockCipher public void init(boolean forEncryption, CipherParameters parameters) throws IllegalArgumentException { + boolean oldForEncryption = this.forEncryption; this.forEncryption = forEncryption; this.macBlock = null; @@ -164,14 +166,17 @@ public class OCBBlockCipher * KEY-DEPENDENT INITIALISATION */ - if (keyParameter == null) + if (keyParameter != null) { - // TODO If 'keyParameter' is null we're re-using the last key. + // hashCipher always used in forward mode + hashCipher.init(true, keyParameter); + mainCipher.init(forEncryption, keyParameter); + KtopInput = null; + } + else if (oldForEncryption != forEncryption) + { + throw new IllegalArgumentException("cannot change encrypting state without providing key."); } - - // hashCipher always used in forward mode - hashCipher.init(true, keyParameter); - mainCipher.init(forEncryption, keyParameter); this.L_Asterisk = new byte[16]; hashCipher.processBlock(L_Asterisk, 0, L_Asterisk, 0); @@ -185,25 +190,8 @@ public class OCBBlockCipher * NONCE-DEPENDENT AND PER-ENCRYPTION/DECRYPTION INITIALISATION */ - byte[] nonce = new byte[16]; - System.arraycopy(N, 0, nonce, nonce.length - N.length, N.length); - nonce[0] = (byte)(macSize << 4); - nonce[15 - N.length] |= 1; + int bottom = processNonce(N); - int bottom = nonce[15] & 0x3F; - - byte[] Ktop = new byte[16]; - nonce[15] &= 0xC0; - hashCipher.processBlock(nonce, 0, Ktop, 0); - - byte[] Stretch = new byte[24]; - System.arraycopy(Ktop, 0, Stretch, 0, 16); - for (int i = 0; i < 8; ++i) - { - Stretch[16 + i] = (byte)(Ktop[i] ^ Ktop[i + 1]); - } - - this.OffsetMAIN_0 = new byte[16]; int bits = bottom % 8, bytes = bottom / 8; if (bits == 0) { @@ -227,7 +215,7 @@ public class OCBBlockCipher this.OffsetHASH = new byte[16]; this.Sum = new byte[16]; - this.OffsetMAIN = Arrays.clone(this.OffsetMAIN_0); + System.arraycopy(this.OffsetMAIN_0, 0, this.OffsetMAIN, 0, 16); this.Checksum = new byte[16]; if (initialAssociatedText != null) @@ -236,6 +224,34 @@ public class OCBBlockCipher } } + protected int processNonce(byte[] N) + { + byte[] nonce = new byte[16]; + System.arraycopy(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); + System.arraycopy(Ktop, 0, Stretch, 0, 16); + for (int i = 0; i < 8; ++i) + { + Stretch[16 + i] = (byte)(Ktop[i] ^ Ktop[i + 1]); + } + } + + return bottom; + } + public byte[] getMac() { return Arrays.clone(macBlock); @@ -301,6 +317,10 @@ public class OCBBlockCipher public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) throws DataLengthException { + if (input.length < (inOff + len)) + { + throw new DataLengthException("Input buffer too short"); + } int resultLen = 0; for (int i = 0; i < len; ++i) @@ -362,6 +382,10 @@ public class OCBBlockCipher xor(mainBlock, Pad); + if (output.length < (outOff + mainBlockPos)) + { + throw new OutputLengthException("Output buffer too short"); + } System.arraycopy(mainBlock, 0, output, outOff, mainBlockPos); if (!forEncryption) @@ -389,6 +413,10 @@ public class OCBBlockCipher if (forEncryption) { + if (output.length < (outOff + resultLen + macSize)) + { + throw new OutputLengthException("Output buffer too short"); + } // Append tag to the message System.arraycopy(macBlock, 0, output, outOff + resultLen, macSize); resultLen += macSize; @@ -440,6 +468,11 @@ public class OCBBlockCipher protected void processMainBlock(byte[] output, int outOff) { + if (output.length < (outOff + BLOCK_SIZE)) + { + throw new OutputLengthException("Output buffer too short"); + } + /* * OCB-ENCRYPT/OCB-DECRYPT: Process any whole blocks */ @@ -537,7 +570,7 @@ public class OCBBlockCipher while ((x & 1L) == 0L) { ++n; - x >>= 1; + x >>>= 1; } return n; } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java index 5297698f..d9ff428f 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java @@ -3,14 +3,16 @@ package org.bouncycastle.crypto.modes; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.StreamBlockCipher; import org.bouncycastle.crypto.params.ParametersWithIV; /** * implements a Output-FeedBack (OFB) mode on top of a simple cipher. */ public class OFBBlockCipher - implements BlockCipher + extends StreamBlockCipher { + private int byteCount; private byte[] IV; private byte[] ofbV; private byte[] ofbOutV; @@ -29,6 +31,8 @@ public class OFBBlockCipher BlockCipher cipher, int blockSize) { + super(cipher); + this.cipher = cipher; this.blockSize = blockSize / 8; @@ -38,16 +42,6 @@ public class OFBBlockCipher } /** - * return the underlying block cipher that we are wrapping. - * - * @return the underlying block cipher that we are wrapping. - */ - public BlockCipher 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. @@ -113,7 +107,7 @@ public class OFBBlockCipher return cipher.getAlgorithmName() + "/OFB" + (blockSize * 8); } - + /** * return the block size we are operating at (in bytes). * @@ -144,32 +138,7 @@ public class OFBBlockCipher int outOff) throws DataLengthException, IllegalStateException { - if ((inOff + blockSize) > in.length) - { - throw new DataLengthException("input buffer too short"); - } - - if ((outOff + blockSize) > out.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++) - { - out[outOff + i] = (byte)(ofbOutV[i] ^ in[inOff + i]); - } - - // - // change over the input block. - // - System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize); - System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize); + processBytes(in, inOff, blockSize, out, outOff); return blockSize; } @@ -181,7 +150,29 @@ public class OFBBlockCipher public void reset() { System.arraycopy(IV, 0, ofbV, 0, IV.length); + byteCount = 0; cipher.reset(); } + + protected byte calculateByte(byte in) + throws DataLengthException, IllegalStateException + { + if (byteCount == 0) + { + cipher.processBlock(ofbV, 0, ofbOutV, 0); + } + + byte rv = (byte)(ofbOutV[byteCount++] ^ in); + + if (byteCount == blockSize) + { + byteCount = 0; + + System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize); + System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize); + } + + return rv; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java index da8c4ae1..fbc8bf45 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java @@ -3,14 +3,18 @@ package org.bouncycastle.crypto.modes; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.SkippingStreamCipher; +import org.bouncycastle.crypto.StreamBlockCipher; import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.Pack; /** * Implements the Segmented Integer Counter (SIC) mode on top of a simple * block cipher. This mode is also known as CTR mode. */ public class SICBlockCipher - implements BlockCipher + extends StreamBlockCipher + implements SkippingStreamCipher { private final BlockCipher cipher; private final int blockSize; @@ -18,7 +22,7 @@ public class SICBlockCipher private byte[] IV; private byte[] counter; private byte[] counterOut; - + private int byteCount; /** * Basic constructor. @@ -27,25 +31,16 @@ public class SICBlockCipher */ public SICBlockCipher(BlockCipher c) { + super(c); + this.cipher = c; this.blockSize = cipher.getBlockSize(); this.IV = new byte[blockSize]; this.counter = new byte[blockSize]; this.counterOut = new byte[blockSize]; + this.byteCount = 0; } - - /** - * 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, //ignored by this CTR mode CipherParameters params) @@ -53,17 +48,17 @@ public class SICBlockCipher { if (params instanceof ParametersWithIV) { - ParametersWithIV ivParam = (ParametersWithIV)params; - byte[] iv = ivParam.getIV(); - System.arraycopy(iv, 0, IV, 0, IV.length); + ParametersWithIV ivParam = (ParametersWithIV)params; + byte[] iv = ivParam.getIV(); + System.arraycopy(iv, 0, IV, 0, IV.length); - reset(); + // if null it's an IV changed only. + if (ivParam.getParameters() != null) + { + cipher.init(true, ivParam.getParameters()); + } - // if null it's an IV changed only. - if (ivParam.getParameters() != null) - { - cipher.init(true, ivParam.getParameters()); - } + reset(); } else { @@ -81,33 +76,240 @@ public class SICBlockCipher return cipher.getBlockSize(); } - public int processBlock(byte[] in, int inOff, byte[] out, int outOff) throws DataLengthException, IllegalStateException { - cipher.processBlock(counter, 0, counterOut, 0); + processBytes(in, inOff, blockSize, out, outOff); - // - // XOR the counterOut with the plaintext producing the cipher text - // - for (int i = 0; i < counterOut.length; i++) + return blockSize; + } + + protected byte calculateByte(byte in) + throws DataLengthException, IllegalStateException + { + if (byteCount == 0) + { + cipher.processBlock(counter, 0, counterOut, 0); + + return (byte)(counterOut[byteCount++] ^ in); + } + + byte rv = (byte)(counterOut[byteCount++] ^ in); + + if (byteCount == counter.length) { - out[outOff + i] = (byte)(counterOut[i] ^ in[inOff + i]); + byteCount = 0; + + incrementCounter(); } + return rv; + } + + private void incrementCounterPow2(int pow2Div8) + { + // increment counter by 1 << 8 * pow2Div8 + for (int i = counter.length - (1 + pow2Div8); i >= 0 && ++counter[i] == 0; i--) + { + ; // do nothing - pre-increment and test for 0 in counter does the job. + } + } + + private void incrementCounter(int offSet) + { + byte old = counter[counter.length - 1]; + + counter[counter.length - 1] += offSet; + + if (old != 0 && counter[counter.length - 1] < old) + { + incrementCounterPow2(1); + } + } + + private void incrementCounter() + { // increment counter by 1. for (int i = counter.length - 1; i >= 0 && ++counter[i] == 0; i--) { ; // do nothing - pre-increment and test for 0 in counter does the job. } + } + + private void decrementCounterPow2(int pow2Div8) + { + if (counter[pow2Div8] == 0) + { + boolean nonZero = false; + + for (int i = counter.length - (1 + pow2Div8); i > 0; i--) + { + if (counter[i] != 0) + { + nonZero = true; + } + } + + if (!nonZero) + { + throw new IllegalStateException("attempt to reduce counter past zero."); + } + } - return counter.length; + // decrement counter by 1. + for (int i = counter.length - (1 + pow2Div8); i >= 0 && --counter[i] == -1; i--) + { + ; + } } + private void decrementCounter() + { + if (counter[0] == 0) + { + boolean nonZero = false; + + for (int i = counter.length - 1; i > 0; i--) + { + if (counter[i] != 0) + { + nonZero = true; + } + } + + if (!nonZero) + { + throw new IllegalStateException("attempt to reduce counter past zero."); + } + } + + // decrement counter by 1. + for (int i = counter.length - 1; i >= 0 && --counter[i] == -1; i--) + { + ; + } + } + + private void adjustCounter(long n) + { + if (n >= 0) + { + long numBlocks = (n + byteCount) / blockSize; + + if (numBlocks > 255) + { + long gap = numBlocks; + + for (int i = 5; i >= 1; i--) + { + long diff = 1L << (8 * i); + + while (gap >= diff) + { + incrementCounterPow2(i); + + gap -= diff; + } + } + + incrementCounter((int)gap); + } + else + { + incrementCounter((int)numBlocks); + } + + byteCount = (int)((n + byteCount) - (blockSize * numBlocks)); + } + else + { + long numBlocks = (-n - byteCount) / blockSize; + + if (numBlocks > 255) + { + long gap = numBlocks; + + for (int i = 5; i >= 1; i--) + { + long diff = 1L << (8 * i); + + while (gap > diff) + { + decrementCounterPow2(i); + + gap -= diff; + } + } + + for (long i = 0; i != gap; i++) + { + decrementCounter(); + } + } + else + { + for (long i = 0; i != numBlocks; i++) + { + decrementCounter(); + } + } + + int gap = (int)(byteCount + n + (blockSize * numBlocks)); + + if (gap >= 0) + { + byteCount = 0; + } + else + { + decrementCounter(); + byteCount = blockSize + gap; + } + } + } public void reset() { System.arraycopy(IV, 0, counter, 0, counter.length); cipher.reset(); + this.byteCount = 0; + } + + public long skip(long numberOfBytes) + { + adjustCounter(numberOfBytes); + + cipher.processBlock(counter, 0, counterOut, 0); + + return numberOfBytes; + } + + public long seekTo(long position) + { + reset(); + + return skip(position); + } + + public long getPosition() + { + byte[] res = new byte[IV.length]; + + System.arraycopy(counter, 0, res, 0, res.length); + + for (int i = res.length - 1; i >= 1; i--) + { + int v = (res[i] & 0xff) - (IV[i] & 0xff); + + if (v < 0) + { + res[i - 1]--; + v += 256; + } + + res[i] = (byte)v; + } + + return Pack.bigEndianToLong(res, res.length - 8) * blockSize + byteCount; } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMMultiplier.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMMultiplier.java index a98d5b2a..2afb18fc 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMMultiplier.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMMultiplier.java @@ -1,18 +1,18 @@ package org.bouncycastle.crypto.modes.gcm; -import org.bouncycastle.util.Arrays; - public class BasicGCMMultiplier implements GCMMultiplier { - private byte[] H; + private int[] H; public void init(byte[] H) { - this.H = Arrays.clone(H); + this.H = GCMUtil.asInts(H); } public void multiplyH(byte[] x) { - GCMUtil.multiply(x, H); + int[] t = GCMUtil.asInts(x); + GCMUtil.multiply(t, H); + GCMUtil.asBytes(t, x); } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java index 3031a444..58f40788 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java @@ -1,13 +1,11 @@ package org.bouncycastle.crypto.modes.gcm; -import org.bouncycastle.crypto.util.Pack; -import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; -abstract class GCMUtil +public abstract class GCMUtil { private static final int E1 = 0xe1000000; - private static final byte E1B = (byte)0xe1; - private static final long E1L = (E1 & 0xFFFFFFFFL) << 24; + private static final long E1L = (E1 & 0xFFFFFFFFL) << 32; private static int[] generateLookup() { @@ -31,170 +29,151 @@ abstract class GCMUtil private static final int[] LOOKUP = generateLookup(); - static byte[] oneAsBytes() + public static byte[] oneAsBytes() { byte[] tmp = new byte[16]; tmp[0] = (byte)0x80; return tmp; } - static int[] oneAsInts() + public static int[] oneAsInts() { int[] tmp = new int[4]; tmp[0] = 1 << 31; return tmp; } - static long[] oneAsLongs() + public static long[] oneAsLongs() { long[] tmp = new long[2]; tmp[0] = 1L << 63; return tmp; } - static byte[] asBytes(int[] x) + public static byte[] asBytes(int[] x) { byte[] z = new byte[16]; Pack.intToBigEndian(x, z, 0); return z; } - static void asBytes(int[] x, byte[] z) + public static void asBytes(int[] x, byte[] z) { Pack.intToBigEndian(x, z, 0); } - static byte[] asBytes(long[] x) + public static byte[] asBytes(long[] x) { byte[] z = new byte[16]; Pack.longToBigEndian(x, z, 0); return z; } - static void asBytes(long[] x, byte[] z) + public static void asBytes(long[] x, byte[] z) { Pack.longToBigEndian(x, z, 0); } - static int[] asInts(byte[] x) + public static int[] asInts(byte[] x) { int[] z = new int[4]; Pack.bigEndianToInt(x, 0, z); return z; } - static void asInts(byte[] x, int[] z) + public static void asInts(byte[] x, int[] z) { Pack.bigEndianToInt(x, 0, z); } - static long[] asLongs(byte[] x) + public static long[] asLongs(byte[] x) { long[] z = new long[2]; Pack.bigEndianToLong(x, 0, z); return z; } - static void asLongs(byte[] x, long[] z) + public static void asLongs(byte[] x, long[] z) { Pack.bigEndianToLong(x, 0, z); } - static void multiply(byte[] x, byte[] y) + public static void multiply(byte[] x, byte[] y) { - byte[] r0 = Arrays.clone(x); - byte[] r1 = new byte[16]; - - for (int i = 0; i < 16; ++i) - { - byte bits = y[i]; - for (int j = 7; j >= 0; --j) - { - if ((bits & (1 << j)) != 0) - { - xor(r1, r0); - } - - if (shiftRight(r0) != 0) - { - r0[0] ^= E1B; - } - } - } - - System.arraycopy(r1, 0, x, 0, 16); + int[] t1 = GCMUtil.asInts(x); + int[] t2 = GCMUtil.asInts(y); + GCMUtil.multiply(t1, t2); + GCMUtil.asBytes(t1, x); } - static void multiply(int[] x, int[] y) + public static void multiply(int[] x, int[] y) { - int[] r0 = Arrays.clone(x); - int[] r1 = new int[4]; - + int r00 = x[0], r01 = x[1], r02 = x[2], r03 = x[3]; + int r10 = 0, r11 = 0, r12 = 0, r13 = 0; + for (int i = 0; i < 4; ++i) { int bits = y[i]; - for (int j = 31; j >= 0; --j) + for (int j = 0; j < 32; ++j) { - if ((bits & (1 << j)) != 0) - { - xor(r1, r0); - } - - if (shiftRight(r0) != 0) - { - r0[0] ^= E1; - } + int m1 = bits >> 31; bits <<= 1; + r10 ^= (r00 & m1); + r11 ^= (r01 & m1); + r12 ^= (r02 & m1); + r13 ^= (r03 & m1); + + int m2 = (r03 << 31) >> 8; + r03 = (r03 >>> 1) | (r02 << 63); + r02 = (r02 >>> 1) | (r01 << 63); + r01 = (r01 >>> 1) | (r00 << 63); + r00 = (r00 >>> 1) ^ (m2 & E1); } } - System.arraycopy(r1, 0, x, 0, 4); + x[0] = r10; + x[1] = r11; + x[2] = r12; + x[3] = r13; } - static void multiply(long[] x, long[] y) + public static void multiply(long[] x, long[] y) { - long[] r0 = new long[]{ x[0], x[1] }; - long[] r1 = new long[2]; + long r00 = x[0], r01 = x[1], r10 = 0, r11 = 0; for (int i = 0; i < 2; ++i) { long bits = y[i]; - for (int j = 63; j >= 0; --j) + for (int j = 0; j < 64; ++j) { - if ((bits & (1L << j)) != 0) - { - xor(r1, r0); - } + long m1 = bits >> 63; bits <<= 1; + r10 ^= (r00 & m1); + r11 ^= (r01 & m1); - if (shiftRight(r0) != 0) - { - r0[0] ^= E1L; - } + long m2 = (r01 << 63) >> 8; + r01 = (r01 >>> 1) | (r00 << 63); + r00 = (r00 >>> 1) ^ (m2 & E1L); } } - x[0] = r1[0]; - x[1] = r1[1]; + x[0] = r10; + x[1] = r11; } // P is the value with only bit i=1 set - static void multiplyP(int[] x) + public static void multiplyP(int[] x) { - if (shiftRight(x) != 0) - { - x[0] ^= E1; - } + int m = shiftRight(x) >> 8; + x[0] ^= (m & E1); } - static void multiplyP(int[] x, int[] y) + public static void multiplyP(int[] x, int[] z) { - if (shiftRight(x, y) != 0) - { - y[0] ^= E1; - } + int m = shiftRight(x, z) >> 8; + z[0] ^= (m & E1); } // P is the value with only bit i=1 set - static void multiplyP8(int[] x) + public static void multiplyP8(int[] x) { // for (int i = 8; i != 0; --i) // { @@ -205,74 +184,12 @@ abstract class GCMUtil x[0] ^= LOOKUP[c >>> 24]; } - static void multiplyP8(int[] x, int[] y) + public static void multiplyP8(int[] x, int[] y) { int c = shiftRightN(x, 8, y); y[0] ^= LOOKUP[c >>> 24]; } - static byte shiftRight(byte[] x) - { -// int c = 0; -// for (int i = 0; i < 16; ++i) -// { -// int b = x[i] & 0xff; -// x[i] = (byte)((b >>> 1) | c); -// c = (b & 1) << 7; -// } -// return (byte)c; - - int i = 0, c = 0; - do - { - int b = x[i] & 0xff; - x[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - b = x[i] & 0xff; - x[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - b = x[i] & 0xff; - x[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - b = x[i] & 0xff; - x[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - } - while (i < 16); - return (byte)c; - } - - static byte shiftRight(byte[] x, byte[] z) - { -// int c = 0; -// for (int i = 0; i < 16; ++i) -// { -// int b = x[i] & 0xff; -// z[i] = (byte) ((b >>> 1) | c); -// c = (b & 1) << 7; -// } -// return (byte) c; - - int i = 0, c = 0; - do - { - int b = x[i] & 0xff; - z[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - b = x[i] & 0xff; - z[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - b = x[i] & 0xff; - z[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - b = x[i] & 0xff; - z[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - } - while (i < 16); - return (byte)c; - } - static int shiftRight(int[] x) { // int c = 0; @@ -393,7 +310,7 @@ abstract class GCMUtil return b << nInv; } - static void xor(byte[] x, byte[] y) + public static void xor(byte[] x, byte[] y) { int i = 0; do @@ -406,15 +323,15 @@ abstract class GCMUtil while (i < 16); } - static void xor(byte[] x, byte[] y, int yOff, int yLen) + public static void xor(byte[] x, byte[] y, int yOff, int yLen) { - while (yLen-- > 0) + while (--yLen >= 0) { x[yLen] ^= y[yOff + yLen]; } } - static void xor(byte[] x, byte[] y, byte[] z) + public static void xor(byte[] x, byte[] y, byte[] z) { int i = 0; do @@ -427,7 +344,7 @@ abstract class GCMUtil while (i < 16); } - static void xor(int[] x, int[] y) + public static void xor(int[] x, int[] y) { x[0] ^= y[0]; x[1] ^= y[1]; @@ -435,7 +352,7 @@ abstract class GCMUtil x[3] ^= y[3]; } - static void xor(int[] x, int[] y, int[] z) + public static void xor(int[] x, int[] y, int[] z) { z[0] = x[0] ^ y[0]; z[1] = x[1] ^ y[1]; @@ -443,13 +360,13 @@ abstract class GCMUtil z[3] = x[3] ^ y[3]; } - static void xor(long[] x, long[] y) + public static void xor(long[] x, long[] y) { x[0] ^= y[0]; x[1] ^= y[1]; } - static void xor(long[] x, long[] y, long[] z) + public static void xor(long[] x, long[] y, long[] z) { z[0] = x[0] ^ y[0]; z[1] = x[1] ^ y[1]; diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables64kGCMMultiplier.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables64kGCMMultiplier.java index a34a6ea4..4f32a0d9 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables64kGCMMultiplier.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables64kGCMMultiplier.java @@ -1,7 +1,7 @@ package org.bouncycastle.crypto.modes.gcm; -import org.bouncycastle.crypto.util.Pack; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; public class Tables64kGCMMultiplier implements GCMMultiplier { diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java index 8535db5a..69c1dce8 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java @@ -1,7 +1,7 @@ package org.bouncycastle.crypto.modes.gcm; -import org.bouncycastle.crypto.util.Pack; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; public class Tables8kGCMMultiplier implements GCMMultiplier { diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/package.html b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/package.html new file mode 100644 index 00000000..09c42f03 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/package.html @@ -0,0 +1,5 @@ +<html> +<body bgcolor="#ffffff"> +GCM mode support classes. +</body> +</html> diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/package.html b/bcprov/src/main/java/org/bouncycastle/crypto/modes/package.html new file mode 100644 index 00000000..5402df44 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/package.html @@ -0,0 +1,5 @@ +<html> +<body bgcolor="#ffffff"> +Modes for symmetric ciphers. +</body> +</html> |