diff options
author | Sergio Giro <sgiro@google.com> | 2016-01-27 20:40:41 +0000 |
---|---|---|
committer | Sergio Giro <sgiro@google.com> | 2016-01-28 15:30:59 +0000 |
commit | 80261dd2d1824bb3862e90e77a5412d56ad88b1f (patch) | |
tree | d89e670054247d0a050ac1b0d9a7918cbe3498d6 /bcprov/src/main/java/org/bouncycastle/crypto/modes | |
parent | 9be78fe4c709f1e585b5ed7e99b21084045b7fba (diff) | |
download | android_external_bouncycastle-80261dd2d1824bb3862e90e77a5412d56ad88b1f.tar.gz android_external_bouncycastle-80261dd2d1824bb3862e90e77a5412d56ad88b1f.tar.bz2 android_external_bouncycastle-80261dd2d1824bb3862e90e77a5412d56ad88b1f.zip |
bouncycastle: Android tree with upstream code for version 1.50
Android tree as of c0d8909a6c6a4ac075a9dee7ac1fe6baff34acc0
Change-Id: I8d381554d6edec32aae8ff5bab5d5314f0954440
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto/modes')
13 files changed, 937 insertions, 265 deletions
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 9a6e2e0..fef51fd 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java @@ -29,8 +29,8 @@ public class CCMBlockCipher private int macSize; private CipherParameters keyParam; private byte[] macBlock; - private ByteArrayOutputStream associatedText = new ByteArrayOutputStream(); - private ByteArrayOutputStream data = new ByteArrayOutputStream(); + private ExposedByteArrayOutputStream associatedText = new ExposedByteArrayOutputStream(); + private ExposedByteArrayOutputStream data = new ExposedByteArrayOutputStream(); /** * Basic constructor. @@ -65,6 +65,7 @@ public class CCMBlockCipher { this.forEncryption = forEncryption; + CipherParameters cipherParameters; if (params instanceof AEADParameters) { AEADParameters param = (AEADParameters)params; @@ -72,7 +73,7 @@ public class CCMBlockCipher nonce = param.getNonce(); initialAssociatedText = param.getAssociatedText(); macSize = param.getMacSize() / 8; - keyParam = param.getKey(); + cipherParameters = param.getKey(); } else if (params instanceof ParametersWithIV) { @@ -81,17 +82,25 @@ public class CCMBlockCipher nonce = param.getIV(); initialAssociatedText = null; macSize = macBlock.length / 2; - keyParam = param.getParameters(); + 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() @@ -129,14 +138,11 @@ public class CCMBlockCipher public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException { - byte[] text = data.toByteArray(); - byte[] enc = processPacket(text, 0, text.length); - - System.arraycopy(enc, 0, out, outOff, enc.length); + int len = processPacket(data.getBuffer(), 0, data.size(), out, outOff); reset(); - return enc.length; + return len; } public void reset() @@ -178,9 +184,55 @@ public class CCMBlockCipher 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) @@ -206,42 +258,52 @@ public class CCMBlockCipher BlockCipher ctrCipher = new SICBlockCipher(cipher); ctrCipher.init(forEncryption, new ParametersWithIV(keyParam, iv)); - int index = inOff; - int outOff = 0; - byte[] output; + int outputLen; + int inIndex = inOff; + int outIndex = outOff; if (forEncryption) { - output = new byte[inLen + macSize]; + outputLen = inLen + macSize; + if (output.length < (outputLen + outOff)) + { + throw new DataLengthException("Output buffer too short."); + } calculateMac(in, inOff, inLen, macBlock); ctrCipher.processBlock(macBlock, 0, macBlock, 0); // S0 - while (index < inLen - blockSize) // S1... + while (inIndex < (inOff + inLen - blockSize)) // S1... { - ctrCipher.processBlock(in, index, output, outOff); - outOff += blockSize; - index += blockSize; + ctrCipher.processBlock(in, inIndex, output, outIndex); + outIndex += blockSize; + inIndex += blockSize; } byte[] block = new byte[blockSize]; - System.arraycopy(in, index, block, 0, inLen - index); + System.arraycopy(in, inIndex, block, 0, inLen + inOff - inIndex); ctrCipher.processBlock(block, 0, block, 0); - System.arraycopy(block, 0, output, outOff, inLen - index); + System.arraycopy(block, 0, output, outIndex, inLen + inOff - inIndex); - outOff += inLen - index; - - System.arraycopy(macBlock, 0, output, outOff, output.length - outOff); + System.arraycopy(macBlock, 0, output, outOff + inLen, macSize); } else { - output = new byte[inLen - macSize]; + if (inLen < macSize) + { + throw new InvalidCipherTextException("data too short"); + } + outputLen = inLen - macSize; + if (output.length < (outputLen + outOff)) + { + throw new DataLengthException("Output buffer too short."); + } - System.arraycopy(in, inOff + inLen - macSize, macBlock, 0, macSize); + System.arraycopy(in, inOff + outputLen, macBlock, 0, macSize); ctrCipher.processBlock(macBlock, 0, macBlock, 0); @@ -250,24 +312,24 @@ public class CCMBlockCipher macBlock[i] = 0; } - while (outOff < output.length - blockSize) + while (inIndex < (inOff + outputLen - blockSize)) { - ctrCipher.processBlock(in, index, output, outOff); - outOff += blockSize; - index += blockSize; + ctrCipher.processBlock(in, inIndex, output, outIndex); + outIndex += blockSize; + inIndex += blockSize; } byte[] block = new byte[blockSize]; - System.arraycopy(in, index, block, 0, output.length - outOff); + System.arraycopy(in, inIndex, block, 0, outputLen - (inIndex - inOff)); ctrCipher.processBlock(block, 0, block, 0); - System.arraycopy(block, 0, output, outOff, output.length - outOff); + System.arraycopy(block, 0, output, outIndex, outputLen - (inIndex - inOff)); byte[] calculatedMacBlock = new byte[blockSize]; - calculateMac(output, 0, output.length, calculatedMacBlock); + calculateMac(output, outOff, outputLen, calculatedMacBlock); if (!Arrays.constantTimeAreEqual(macBlock, calculatedMacBlock)) { @@ -275,7 +337,7 @@ public class CCMBlockCipher } } - return output; + return outputLen; } private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock) @@ -344,8 +406,7 @@ public class CCMBlockCipher } if (associatedText.size() > 0) { - byte[] tmp = associatedText.toByteArray(); - cMac.update(tmp, 0, tmp.length); + cMac.update(associatedText.getBuffer(), 0, associatedText.size()); } extra = (extra + textLength) % 16; @@ -375,4 +436,17 @@ public class CCMBlockCipher { return getAssociatedTextLength() > 0; } + + private class ExposedByteArrayOutputStream + extends ByteArrayOutputStream + { + public ExposedByteArrayOutputStream() + { + } + + public byte[] getBuffer() + { + return this.buf; + } + } } 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 d0fb9bb..a885169 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java @@ -4,6 +4,7 @@ import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.Arrays; /** * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher. @@ -246,6 +247,16 @@ public class CFBBlockCipher } /** + * Return the current state of the initialisation vector. + * + * @return current IV + */ + public byte[] getCurrentIV() + { + return Arrays.clone(cfbV); + } + + /** * reset the chaining vector back to the IV and reset the underlying * cipher. */ 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 b8e5b61..5388b40 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java @@ -22,8 +22,9 @@ public class CTSBlockCipher public CTSBlockCipher( BlockCipher cipher) { - if ((cipher instanceof OFBBlockCipher) || (cipher instanceof CFBBlockCipher)) + if ((cipher instanceof OFBBlockCipher) || (cipher instanceof CFBBlockCipher) || (cipher instanceof SICBlockCipher)) { + // 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"); } @@ -72,7 +73,7 @@ public class CTSBlockCipher } /** - * process a single byte, producing an output block if neccessary. + * 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. @@ -200,60 +201,81 @@ public class CTSBlockCipher if (forEncryption) { - cipher.processBlock(buf, 0, block, 0); - if (bufOff < blockSize) { throw new DataLengthException("need at least one block of input for CTS"); } - for (int i = bufOff; i != buf.length; i++) - { - buf[i] = block[i - blockSize]; - } - - for (int i = blockSize; i != bufOff; i++) - { - buf[i] ^= block[i - blockSize]; - } + cipher.processBlock(buf, 0, block, 0); - if (cipher instanceof CBCBlockCipher) + if (bufOff > blockSize) { - BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher(); - - c.processBlock(buf, blockSize, out, outOff); + for (int i = bufOff; i != buf.length; i++) + { + buf[i] = block[i - blockSize]; + } + + for (int i = blockSize; i != bufOff; i++) + { + buf[i] ^= block[i - blockSize]; + } + + if (cipher instanceof CBCBlockCipher) + { + BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher(); + + c.processBlock(buf, blockSize, out, outOff); + } + else + { + cipher.processBlock(buf, blockSize, out, outOff); + } + + System.arraycopy(block, 0, out, outOff + blockSize, len); } else { - cipher.processBlock(buf, blockSize, out, outOff); + System.arraycopy(block, 0, out, outOff, blockSize); } - - System.arraycopy(block, 0, out, outOff + blockSize, len); } else { + if (bufOff < blockSize) + { + throw new DataLengthException("need at least one block of input for CTS"); + } + byte[] lastBlock = new byte[blockSize]; - if (cipher instanceof CBCBlockCipher) + if (bufOff > blockSize) { - BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher(); - - c.processBlock(buf, 0, block, 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 { cipher.processBlock(buf, 0, block, 0); - } - for (int i = blockSize; i != bufOff; i++) - { - lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]); + System.arraycopy(block, 0, out, outOff, blockSize); } - - System.arraycopy(buf, blockSize, block, 0, len); - - cipher.processBlock(block, 0, out, outOff); - System.arraycopy(lastBlock, 0, out, outOff + blockSize, len); } int offset = bufOff; 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 4999caa..8f74000 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java @@ -123,16 +123,10 @@ public class EAXBlockCipher mac.update(nonce, 0, nonce.length); mac.doFinal(nonceMac, 0); - tag[blockSize - 1] = hTAG; - mac.update(tag, 0, blockSize); - - if (initialAssociatedText != null) - { - processAADBytes(initialAssociatedText, 0, initialAssociatedText.length); - } - // Same BlockCipher underlies this and the mac, so reuse last key on cipher cipher.init(true, new ParametersWithIV(null, nonceMac)); + + reset(); } private void initCipher() @@ -206,7 +200,7 @@ public class EAXBlockCipher { if (cipherInitialized) { - throw new IllegalStateException("AAD data cannot be added after encryption/decription processing has begun."); + throw new IllegalStateException("AAD data cannot be added after encryption/decryption processing has begun."); } mac.update(in, inOff, len); } @@ -246,6 +240,10 @@ public class EAXBlockCipher if (forEncryption) { + if (out.length < (outOff + extra)) + { + throw new DataLengthException("Output buffer too short"); + } cipher.processBlock(bufBlock, 0, tmp, 0); cipher.processBlock(bufBlock, blockSize, tmp, blockSize); @@ -263,6 +261,10 @@ public class EAXBlockCipher } else { + if (extra < macSize) + { + throw new InvalidCipherTextException("data too short"); + } if (extra > macSize) { mac.update(bufBlock, 0, extra - macSize); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCFBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCFBBlockCipher.java new file mode 100644 index 0000000..887c169 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCFBBlockCipher.java @@ -0,0 +1,109 @@ +package org.bouncycastle.crypto.modes; + +import org.bouncycastle.crypto.BlockCipher; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.crypto.params.ParametersWithRandom; +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 +{ + private static final byte[] C = + { + 0x69, 0x00, 0x72, 0x22, 0x64, (byte)0xC9, 0x04, 0x23, + (byte)0x8D, 0x3A, (byte)0xDB, (byte)0x96, 0x46, (byte)0xE9, 0x2A, (byte)0xC4, + 0x18, (byte)0xFE, (byte)0xAC, (byte)0x94, 0x00, (byte)0xED, 0x07, 0x12, + (byte)0xC0, (byte)0x86, (byte)0xDC, (byte)0xC2, (byte)0xEF, 0x4C, (byte)0xA9, 0x2B + }; + + private final CFBBlockCipher cfbEngine; + + private KeyParameter key; + private long counter = 0; + private boolean forEncryption; + + public GCFBBlockCipher(BlockCipher engine) + { + this.cfbEngine = new CFBBlockCipher(engine, engine.getBlockSize() * 8); + } + + public void init(boolean forEncryption, CipherParameters params) + throws IllegalArgumentException + { + counter = 0; + cfbEngine.init(forEncryption, params); + + this.forEncryption = forEncryption; + + if (params instanceof ParametersWithIV) + { + params = ((ParametersWithIV)params).getParameters(); + } + + if (params instanceof ParametersWithRandom) + { + params = ((ParametersWithRandom)params).getParameters(); + } + + if (params instanceof ParametersWithSBox) + { + params = ((ParametersWithSBox)params).getParameters(); + } + + key = (KeyParameter)params; + } + + public String getAlgorithmName() + { + return "G" + cfbEngine.getAlgorithmName(); + } + + public int getBlockSize() + { + return cfbEngine.getBlockSize(); + } + + public int processBlock(byte[] in, int inOff, byte[] out, int outOff) + throws DataLengthException, IllegalStateException + { + if (counter > 0 && counter % 1024 == 0) + { + BlockCipher base = cfbEngine.getUnderlyingCipher(); + + base.init(false, key); + + byte[] nextKey = new byte[32]; + + base.processBlock(C, 0, nextKey, 0); + base.processBlock(C, 8, nextKey, 8); + base.processBlock(C, 16, nextKey, 16); + base.processBlock(C, 24, nextKey, 24); + + key = new KeyParameter(nextKey); + + byte[] iv = new byte[8]; + + base.init(true, key); + + base.processBlock(cfbEngine.getCurrentIV(), 0, iv, 0); + + cfbEngine.init(forEncryption, new ParametersWithIV(key, iv)); + } + + counter += cfbEngine.getBlockSize(); + + return cfbEngine.processBlock(in, inOff, out, outOff); + } + + public void reset() + { + counter = 0; + cfbEngine.reset(); + } +} 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 1178974..0e66cf3 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GOFBBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GOFBBlockCipher.java @@ -206,6 +206,9 @@ public class GOFBBlockCipher */ public void reset() { + firstStep = true; + N3 = 0; + N4 = 0; System.arraycopy(IV, 0, ofbV, 0, IV.length); cipher.reset(); 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 d4d2910..6dc7148 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java @@ -13,7 +13,7 @@ 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-00">The OCB Authenticated-Encryption + * href="http://tools.ietf.org/html/draft-irtf-cfrg-ocb-03">The OCB Authenticated-Encryption * Algorithm</a>, licensed per: * <p/> * <blockquote> <a href="http://www.cs.ucdavis.edu/~rogaway/ocb/license1.pdf">License for @@ -111,7 +111,6 @@ public class OCBBlockCipher public void init(boolean forEncryption, CipherParameters parameters) throws IllegalArgumentException { - this.forEncryption = forEncryption; this.macBlock = null; @@ -156,23 +155,18 @@ public class OCBBlockCipher N = new byte[0]; } - if (N.length > 16 || (N.length == 16 && (N[0] & 0x80) != 0)) + if (N.length > 15) { - /* - * NOTE: We don't just ignore bit 128 because it would hide from the caller the fact - * that two nonces differing only in bit 128 are not different. - */ - throw new IllegalArgumentException("IV must be no more than 127 bits"); + throw new IllegalArgumentException("IV must be no more than 15 bytes"); } /* * KEY-DEPENDENT INITIALISATION */ - // if keyParam is null we're reusing the last key. - if (keyParameter != null) + if (keyParameter == null) { - // TODO + // TODO If 'keyParameter' is null we're re-using the last key. } // hashCipher always used in forward mode @@ -193,17 +187,10 @@ public class OCBBlockCipher byte[] nonce = new byte[16]; System.arraycopy(N, 0, nonce, nonce.length - N.length, N.length); - if (N.length == 16) - { - nonce[0] &= 0x80; - } - else - { - nonce[15 - N.length] = 1; - } + nonce[0] = (byte)(macSize << 4); + nonce[15 - N.length] |= 1; int bottom = nonce[15] & 0x3F; - // System.out.println("bottom: " + bottom); byte[] Ktop = new byte[16]; nonce[15] &= 0xC0; @@ -314,7 +301,6 @@ public class OCBBlockCipher public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) throws DataLengthException { - int resultLen = 0; for (int i = 0; i < len; ++i) @@ -334,7 +320,6 @@ public class OCBBlockCipher throws IllegalStateException, InvalidCipherTextException { - /* * For decryption, get the tag from the end of the message */ @@ -483,7 +468,6 @@ public class OCBBlockCipher protected void reset(boolean clearMac) { - hashCipher.reset(); mainCipher.reset(); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/OldCTSBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OldCTSBlockCipher.java new file mode 100644 index 0000000..b34432a --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OldCTSBlockCipher.java @@ -0,0 +1,269 @@ +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; + +/** + * 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 version applies the CTS algorithm from one block up, rather than following the errata update issued in 2004, where CTS mode is applied + * from greater than 1 block up and the first block is processed using CBC mode. + * </p> + */ +public class OldCTSBlockCipher + extends BufferedBlockCipher +{ + private int blockSize; + + /** + * Create a buffered block cipher that uses Cipher Text Stealing + * + * @param cipher the underlying block cipher this buffering object wraps. + */ + public OldCTSBlockCipher( + BlockCipher cipher) + { + if ((cipher instanceof OFBBlockCipher) || (cipher instanceof CFBBlockCipher)) + { + throw new IllegalArgumentException("CTSBlockCipher can only accept ECB, or CBC ciphers"); + } + + this.cipher = 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) + { + cipher.processBlock(buf, 0, block, 0); + + if (bufOff < blockSize) + { + throw new DataLengthException("need at least one block of input for CTS"); + } + + for (int i = bufOff; i != buf.length; i++) + { + buf[i] = block[i - blockSize]; + } + + for (int i = blockSize; i != bufOff; i++) + { + buf[i] ^= block[i - blockSize]; + } + + if (cipher instanceof CBCBlockCipher) + { + BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher(); + + c.processBlock(buf, blockSize, out, outOff); + } + else + { + cipher.processBlock(buf, blockSize, out, outOff); + } + + System.arraycopy(block, 0, out, outOff + blockSize, len); + } + else + { + byte[] lastBlock = new byte[blockSize]; + + 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); + } + + int offset = bufOff; + + reset(); + + return offset; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/PGPCFBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/PGPCFBBlockCipher.java index 18e612b..4dee63a 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/PGPCFBBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/PGPCFBBlockCipher.java @@ -220,13 +220,13 @@ public class PGPCFBBlockCipher throw new DataLengthException("input buffer too short"); } - if ((outOff + blockSize) > out.length) - { - throw new DataLengthException("output buffer too short"); - } - if (count == 0) { + if ((outOff + 2 * blockSize + 2) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + cipher.processBlock(FR, 0, FRE, 0); for (int n = 0; n < blockSize; n++) @@ -258,6 +258,11 @@ public class PGPCFBBlockCipher } else if (count >= blockSize + 2) { + if ((outOff + blockSize) > out.length) + { + throw new DataLengthException("output buffer too short"); + } + cipher.processBlock(FR, 0, FRE, 0); for (int n = 0; n < blockSize; n++) diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java index f2be2fc..fc25810 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java @@ -4,21 +4,21 @@ import org.bouncycastle.util.Arrays; public class BasicGCMExponentiator implements GCMExponentiator { - private byte[] x; + private int[] x; public void init(byte[] x) { - this.x = Arrays.clone(x); + this.x = GCMUtil.asInts(x); } public void exponentiateX(long pow, byte[] output) { // Initial value is little-endian 1 - byte[] y = GCMUtil.oneAsBytes(); + int[] y = GCMUtil.oneAsInts(); if (pow > 0) { - byte[] powX = Arrays.clone(x); + int[] powX = Arrays.clone(x); do { if ((pow & 1L) != 0) @@ -31,6 +31,6 @@ public class BasicGCMExponentiator implements GCMExponentiator while (pow > 0); } - System.arraycopy(y, 0, output, 0, 16); + GCMUtil.asBytes(y, output); } } 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 4875301..3031a44 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 @@ -5,6 +5,32 @@ import org.bouncycastle.util.Arrays; 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 int[] generateLookup() + { + int[] lookup = new int[256]; + + for (int c = 0; c < 256; ++c) + { + int v = 0; + for (int i = 7; i >= 0; --i) + { + if ((c & (1 << i)) != 0) + { + v ^= (E1 >>> (7 - i)); + } + } + lookup[c] = v; + } + + return lookup; + } + + private static final int[] LOOKUP = generateLookup(); + static byte[] oneAsBytes() { byte[] tmp = new byte[16]; @@ -15,78 +41,155 @@ abstract class GCMUtil static int[] oneAsInts() { int[] tmp = new int[4]; - tmp[0] = 0x80000000; + tmp[0] = 1 << 31; + return tmp; + } + + static long[] oneAsLongs() + { + long[] tmp = new long[2]; + tmp[0] = 1L << 63; return tmp; } - static byte[] asBytes(int[] ns) + static byte[] asBytes(int[] x) + { + byte[] z = new byte[16]; + Pack.intToBigEndian(x, z, 0); + return z; + } + + static void asBytes(int[] x, byte[] z) + { + Pack.intToBigEndian(x, z, 0); + } + + static byte[] asBytes(long[] x) + { + byte[] z = new byte[16]; + Pack.longToBigEndian(x, z, 0); + return z; + } + + static void asBytes(long[] x, byte[] z) + { + Pack.longToBigEndian(x, z, 0); + } + + static int[] asInts(byte[] x) + { + int[] z = new int[4]; + Pack.bigEndianToInt(x, 0, z); + return z; + } + + static void asInts(byte[] x, int[] z) { - byte[] output = new byte[16]; - Pack.intToBigEndian(ns, output, 0); - return output; + Pack.bigEndianToInt(x, 0, z); } - static int[] asInts(byte[] bs) + static long[] asLongs(byte[] x) { - int[] output = new int[4]; - Pack.bigEndianToInt(bs, 0, output); - return output; + long[] z = new long[2]; + Pack.bigEndianToLong(x, 0, z); + return z; } - static void asInts(byte[] bs, int[] output) + static void asLongs(byte[] x, long[] z) { - Pack.bigEndianToInt(bs, 0, output); + Pack.bigEndianToLong(x, 0, z); } - static void multiply(byte[] block, byte[] val) + static void multiply(byte[] x, byte[] y) { - byte[] tmp = Arrays.clone(block); - byte[] c = new byte[16]; + byte[] r0 = Arrays.clone(x); + byte[] r1 = new byte[16]; for (int i = 0; i < 16; ++i) { - byte bits = val[i]; + byte bits = y[i]; for (int j = 7; j >= 0; --j) { if ((bits & (1 << j)) != 0) { - xor(c, tmp); + xor(r1, r0); } - boolean lsb = (tmp[15] & 1) != 0; - shiftRight(tmp); - if (lsb) + if (shiftRight(r0) != 0) { - // R = new byte[]{ 0xe1, ... }; -// GCMUtil.xor(v, R); - tmp[0] ^= (byte)0xe1; + r0[0] ^= E1B; } } } - System.arraycopy(c, 0, block, 0, 16); + System.arraycopy(r1, 0, x, 0, 16); + } + + static void multiply(int[] x, int[] y) + { + int[] r0 = Arrays.clone(x); + int[] r1 = new int[4]; + + for (int i = 0; i < 4; ++i) + { + int bits = y[i]; + for (int j = 31; j >= 0; --j) + { + if ((bits & (1 << j)) != 0) + { + xor(r1, r0); + } + + if (shiftRight(r0) != 0) + { + r0[0] ^= E1; + } + } + } + + System.arraycopy(r1, 0, x, 0, 4); + } + + static void multiply(long[] x, long[] y) + { + long[] r0 = new long[]{ x[0], x[1] }; + long[] r1 = new long[2]; + + for (int i = 0; i < 2; ++i) + { + long bits = y[i]; + for (int j = 63; j >= 0; --j) + { + if ((bits & (1L << j)) != 0) + { + xor(r1, r0); + } + + if (shiftRight(r0) != 0) + { + r0[0] ^= E1L; + } + } + } + + x[0] = r1[0]; + x[1] = r1[1]; } // P is the value with only bit i=1 set static void multiplyP(int[] x) { - boolean lsb = (x[3] & 1) != 0; - shiftRight(x); - if (lsb) + if (shiftRight(x) != 0) { - // R = new int[]{ 0xe1000000, 0, 0, 0 }; -// xor(v, R); - x[0] ^= 0xe1000000; + x[0] ^= E1; } } - static void multiplyP(int[] x, int[] output) + static void multiplyP(int[] x, int[] y) { - boolean lsb = (x[3] & 1) != 0; - shiftRight(x, output); - if (lsb) + if (shiftRight(x, y) != 0) { - output[0] ^= 0xe1000000; + y[0] ^= E1; } } @@ -98,163 +201,257 @@ abstract class GCMUtil // multiplyP(x); // } - int lsw = x[3]; - shiftRightN(x, 8); - for (int i = 7; i >= 0; --i) - { - if ((lsw & (1 << i)) != 0) - { - x[0] ^= (0xe1000000 >>> (7 - i)); - } - } + int c = shiftRightN(x, 8); + x[0] ^= LOOKUP[c >>> 24]; } - static void multiplyP8(int[] x, int[] output) + static void multiplyP8(int[] x, int[] y) { - int lsw = x[3]; - shiftRightN(x, 8, output); - for (int i = 7; i >= 0; --i) - { - if ((lsw & (1 << i)) != 0) - { - output[0] ^= (0xe1000000 >>> (7 - i)); - } - } + int c = shiftRightN(x, 8, y); + y[0] ^= LOOKUP[c >>> 24]; } - static void shiftRight(byte[] block) + static byte shiftRight(byte[] x) { - int i = 0; - int bit = 0; - for (;;) +// 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 = block[i] & 0xff; - block[i] = (byte) ((b >>> 1) | bit); - if (++i == 16) - { - break; - } - bit = (b & 1) << 7; + 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 void shiftRight(byte[] block, byte[] output) + static byte shiftRight(byte[] x, byte[] z) { - int i = 0; - int bit = 0; - for (;;) +// 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 = block[i] & 0xff; - output[i] = (byte) ((b >>> 1) | bit); - if (++i == 16) - { - break; - } - bit = (b & 1) << 7; + 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 void shiftRight(int[] block) + static int shiftRight(int[] x) { - int i = 0; - int bit = 0; - for (;;) - { - int b = block[i]; - block[i] = (b >>> 1) | bit; - if (++i == 4) - { - break; - } - bit = b << 31; - } +// int c = 0; +// for (int i = 0; i < 4; ++i) +// { +// int b = x[i]; +// x[i] = (b >>> 1) | c; +// c = b << 31; +// } +// return c; + + int b = x[0]; + x[0] = b >>> 1; + int c = b << 31; + b = x[1]; + x[1] = (b >>> 1) | c; + c = b << 31; + b = x[2]; + x[2] = (b >>> 1) | c; + c = b << 31; + b = x[3]; + x[3] = (b >>> 1) | c; + return b << 31; } - static void shiftRight(int[] block, int[] output) + static int shiftRight(int[] x, int[] z) { - int i = 0; - int bit = 0; - for (;;) - { - int b = block[i]; - output[i] = (b >>> 1) | bit; - if (++i == 4) - { - break; - } - bit = b << 31; - } +// int c = 0; +// for (int i = 0; i < 4; ++i) +// { +// int b = x[i]; +// z[i] = (b >>> 1) | c; +// c = b << 31; +// } +// return c; + + int b = x[0]; + z[0] = b >>> 1; + int c = b << 31; + b = x[1]; + z[1] = (b >>> 1) | c; + c = b << 31; + b = x[2]; + z[2] = (b >>> 1) | c; + c = b << 31; + b = x[3]; + z[3] = (b >>> 1) | c; + return b << 31; } - static void shiftRightN(int[] block, int n) + static long shiftRight(long[] x) { - int i = 0; - int bits = 0; - for (;;) - { - int b = block[i]; - block[i] = (b >>> n) | bits; - if (++i == 4) - { - break; - } - bits = b << (32 - n); - } + long b = x[0]; + x[0] = b >>> 1; + long c = b << 63; + b = x[1]; + x[1] = (b >>> 1) | c; + return b << 63; + } + + static long shiftRight(long[] x, long[] z) + { + long b = x[0]; + z[0] = b >>> 1; + long c = b << 63; + b = x[1]; + z[1] = (b >>> 1) | c; + return b << 63; + } + + static int shiftRightN(int[] x, int n) + { +// int c = 0, nInv = 32 - n; +// for (int i = 0; i < 4; ++i) +// { +// int b = x[i]; +// x[i] = (b >>> n) | c; +// c = b << nInv; +// } +// return c; + + int b = x[0], nInv = 32 - n; + x[0] = b >>> n; + int c = b << nInv; + b = x[1]; + x[1] = (b >>> n) | c; + c = b << nInv; + b = x[2]; + x[2] = (b >>> n) | c; + c = b << nInv; + b = x[3]; + x[3] = (b >>> n) | c; + return b << nInv; } - static void shiftRightN(int[] block, int n, int[] output) + static int shiftRightN(int[] x, int n, int[] z) + { +// int c = 0, nInv = 32 - n; +// for (int i = 0; i < 4; ++i) +// { +// int b = x[i]; +// z[i] = (b >>> n) | c; +// c = b << nInv; +// } +// return c; + + int b = x[0], nInv = 32 - n; + z[0] = b >>> n; + int c = b << nInv; + b = x[1]; + z[1] = (b >>> n) | c; + c = b << nInv; + b = x[2]; + z[2] = (b >>> n) | c; + c = b << nInv; + b = x[3]; + z[3] = (b >>> n) | c; + return b << nInv; + } + + static void xor(byte[] x, byte[] y) { int i = 0; - int bits = 0; - for (;;) + do { - int b = block[i]; - output[i] = (b >>> n) | bits; - if (++i == 4) - { - break; - } - bits = b << (32 - n); + x[i] ^= y[i]; ++i; + x[i] ^= y[i]; ++i; + x[i] ^= y[i]; ++i; + x[i] ^= y[i]; ++i; } + while (i < 16); } - static void xor(byte[] block, byte[] val) + static void xor(byte[] x, byte[] y, int yOff, int yLen) { - for (int i = 15; i >= 0; --i) + while (yLen-- > 0) { - block[i] ^= val[i]; + x[yLen] ^= y[yOff + yLen]; } } - static void xor(byte[] block, byte[] val, int off, int len) + static void xor(byte[] x, byte[] y, byte[] z) { - while (len-- > 0) + int i = 0; + do { - block[len] ^= val[off + len]; + z[i] = (byte)(x[i] ^ y[i]); ++i; + z[i] = (byte)(x[i] ^ y[i]); ++i; + z[i] = (byte)(x[i] ^ y[i]); ++i; + z[i] = (byte)(x[i] ^ y[i]); ++i; } + while (i < 16); } - static void xor(byte[] block, byte[] val, byte[] output) + static void xor(int[] x, int[] y) { - for (int i = 15; i >= 0; --i) - { - output[i] = (byte)(block[i] ^ val[i]); - } + x[0] ^= y[0]; + x[1] ^= y[1]; + x[2] ^= y[2]; + x[3] ^= y[3]; } - static void xor(int[] block, int[] val) + static void xor(int[] x, int[] y, int[] z) { - for (int i = 3; i >= 0; --i) - { - block[i] ^= val[i]; - } + z[0] = x[0] ^ y[0]; + z[1] = x[1] ^ y[1]; + z[2] = x[2] ^ y[2]; + z[3] = x[3] ^ y[3]; } - static void xor(int[] block, int[] val, int[] output) + static void xor(long[] x, long[] y) { - for (int i = 3; i >= 0; --i) - { - output[i] = block[i] ^ val[i]; - } + x[0] ^= y[0]; + x[1] ^= y[1]; + } + + 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/Tables1kGCMExponentiator.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java index a051208..6eff4e3 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java @@ -12,31 +12,32 @@ public class Tables1kGCMExponentiator implements GCMExponentiator public void init(byte[] x) { - if (lookupPowX2 != null && Arrays.areEqual(x, (byte[])lookupPowX2.elementAt(0))) + int[] y = GCMUtil.asInts(x); + if (lookupPowX2 != null && Arrays.areEqual(y, (int[])lookupPowX2.elementAt(0))) { return; } lookupPowX2 = new Vector(8); - lookupPowX2.addElement(Arrays.clone(x)); + lookupPowX2.addElement(y); } public void exponentiateX(long pow, byte[] output) { - byte[] y = GCMUtil.oneAsBytes(); + int[] y = GCMUtil.oneAsInts(); int bit = 0; while (pow > 0) { if ((pow & 1L) != 0) { ensureAvailable(bit); - GCMUtil.multiply(y, (byte[])lookupPowX2.elementAt(bit)); + GCMUtil.multiply(y, (int[])lookupPowX2.elementAt(bit)); } ++bit; pow >>>= 1; } - System.arraycopy(y, 0, output, 0, 16); + GCMUtil.asBytes(y, output); } private void ensureAvailable(int bit) @@ -44,7 +45,7 @@ public class Tables1kGCMExponentiator implements GCMExponentiator int count = lookupPowX2.size(); if (count <= bit) { - byte[] tmp = (byte[])lookupPowX2.elementAt(count - 1); + int[] tmp = (int[])lookupPowX2.elementAt(count - 1); do { tmp = Arrays.clone(tmp); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/package.html b/bcprov/src/main/java/org/bouncycastle/crypto/modes/package.html deleted file mode 100644 index 5402df4..0000000 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<html> -<body bgcolor="#ffffff"> -Modes for symmetric ciphers. -</body> -</html> |