diff options
author | Brian Carlstrom <bdc@google.com> | 2013-01-30 18:26:40 -0800 |
---|---|---|
committer | Brian Carlstrom <bdc@google.com> | 2013-02-12 15:18:12 -0800 |
commit | 70c8287138e69a98c2f950036f9f703ee37228c8 (patch) | |
tree | 4bfe4bc15b03aa8d8500a76bc6829d7511a69653 /bcprov/src/main/java/org/bouncycastle/crypto | |
parent | cb59b9889be18464ca3b9a78ea142c3bafdb289f (diff) | |
download | bouncycastle-70c8287138e69a98c2f950036f9f703ee37228c8.tar.gz |
bouncycastle 1.48 upgrade
(cherry-picked from e1142c149e244797ce73b0e7fad40816e447a817)
Change-Id: Idb04baf42de07b18ddb162e5cd1f98cdadf366f4
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto')
28 files changed, 782 insertions, 336 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java b/bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java index 85bec735..ddee7019 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java @@ -1,12 +1,14 @@ package org.bouncycastle.crypto; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; + /** * a holding class for public/private parameter pairs. */ public class AsymmetricCipherKeyPair { - private CipherParameters publicParam; - private CipherParameters privateParam; + private AsymmetricKeyParameter publicParam; + private AsymmetricKeyParameter privateParam; /** * basic constructor. @@ -15,19 +17,34 @@ public class AsymmetricCipherKeyPair * @param privateParam the corresponding private key parameters. */ public AsymmetricCipherKeyPair( - CipherParameters publicParam, - CipherParameters privateParam) + AsymmetricKeyParameter publicParam, + AsymmetricKeyParameter privateParam) { this.publicParam = publicParam; this.privateParam = privateParam; } /** + * basic constructor. + * + * @param publicParam a public key parameters object. + * @param privateParam the corresponding private key parameters. + * @deprecated use AsymmetricKeyParameter + */ + public AsymmetricCipherKeyPair( + CipherParameters publicParam, + CipherParameters privateParam) + { + this.publicParam = (AsymmetricKeyParameter)publicParam; + this.privateParam = (AsymmetricKeyParameter)privateParam; + } + + /** * return the public key parameters. * * @return the public key parameters. */ - public CipherParameters getPublic() + public AsymmetricKeyParameter getPublic() { return publicParam; } @@ -37,7 +54,7 @@ public class AsymmetricCipherKeyPair * * @return the private key parameters. */ - public CipherParameters getPrivate() + public AsymmetricKeyParameter getPrivate() { return privateParam; } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/BasicAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/BasicAgreement.java index 49074272..8e5ff0da 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/BasicAgreement.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/BasicAgreement.java @@ -11,11 +11,16 @@ public interface BasicAgreement /** * initialise the agreement engine. */ - public void init(CipherParameters param); + void init(CipherParameters param); + + /** + * return the field size for the agreement algorithm in bytes. + */ + int getFieldSize(); /** * given a public key from a given party calculate the next * message in the agreement sequence. */ - public BigInteger calculateAgreement(CipherParameters pubKey); + BigInteger calculateAgreement(CipherParameters pubKey); } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java index 4878786c..bdb694d4 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java @@ -201,7 +201,7 @@ public class BufferedBlockCipher { if ((outOff + length) > out.length) { - throw new DataLengthException("output buffer too short"); + throw new OutputLengthException("output buffer too short"); } } @@ -265,7 +265,7 @@ public class BufferedBlockCipher if (outOff + bufOff > out.length) { - throw new DataLengthException("output buffer too short for doFinal()"); + throw new OutputLengthException("output buffer too short for doFinal()"); } if (bufOff != 0) diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/InvalidCipherTextException.java b/bcprov/src/main/java/org/bouncycastle/crypto/InvalidCipherTextException.java index 59e4b26b..21c150d9 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/InvalidCipherTextException.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/InvalidCipherTextException.java @@ -24,4 +24,17 @@ public class InvalidCipherTextException { super(message); } + + /** + * create a InvalidCipherTextException with the given message. + * + * @param message the message to be carried with the exception. + * @param cause the root cause of the exception. + */ + public InvalidCipherTextException( + String message, + Throwable cause) + { + super(message, cause); + } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/OutputLengthException.java b/bcprov/src/main/java/org/bouncycastle/crypto/OutputLengthException.java new file mode 100644 index 00000000..62811a2b --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/OutputLengthException.java @@ -0,0 +1,10 @@ +package org.bouncycastle.crypto; + +public class OutputLengthException + extends DataLengthException +{ + public OutputLengthException(String msg) + { + super(msg); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java index dbf550da..2543b59c 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java @@ -103,14 +103,21 @@ public abstract class PBEParametersGenerator public static byte[] PKCS5PasswordToBytes( char[] password) { - byte[] bytes = new byte[password.length]; + if (password != null) + { + byte[] bytes = new byte[password.length]; - for (int i = 0; i != bytes.length; i++) + for (int i = 0; i != bytes.length; i++) + { + bytes[i] = (byte)password[i]; + } + + return bytes; + } + else { - bytes[i] = (byte)password[i]; + return new byte[0]; } - - return bytes; } /** @@ -136,7 +143,6 @@ public abstract class PBEParametersGenerator public static byte[] PKCS12PasswordToBytes( char[] password) { - // BEGIN android-changed if (password != null && password.length > 0) { // +1 for extra 2 pad bytes. @@ -154,6 +160,5 @@ public abstract class PBEParametersGenerator { return new byte[0]; } - // END android-changed } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java index 40893bf3..d2e2a09f 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java @@ -4,10 +4,10 @@ import java.math.BigInteger; import org.bouncycastle.crypto.BasicAgreement; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.DHParameters; -import org.bouncycastle.crypto.params.DHPublicKeyParameters; import org.bouncycastle.crypto.params.DHPrivateKeyParameters; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.DHPublicKeyParameters; import org.bouncycastle.crypto.params.ParametersWithRandom; /** @@ -47,6 +47,11 @@ public class DHBasicAgreement this.dhParams = key.getParameters(); } + public int getFieldSize() + { + return (key.getParameters().getP().bitLength() + 7) / 8; + } + /** * given a short term public key from a given party calculate the next * message in the agreement sequence. diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java index 3ad3e1ca..59944e07 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java @@ -2,12 +2,11 @@ package org.bouncycastle.crypto.agreement; import java.math.BigInteger; -import org.bouncycastle.math.ec.ECPoint; - import org.bouncycastle.crypto.BasicAgreement; import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.math.ec.ECPoint; /** * P1363 7.2.1 ECSVDP-DH @@ -34,6 +33,11 @@ public class ECDHBasicAgreement this.key = (ECPrivateKeyParameters)key; } + public int getFieldSize() + { + return (key.getParameters().getCurve().getFieldSize() + 7) / 8; + } + public BigInteger calculateAgreement( CipherParameters pubKey) { diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java index 8bcfe260..d8ec62b1 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java @@ -201,10 +201,20 @@ public class PKCS1Encoding } byte type = block[0]; - - if (type != 1 && type != 2) + + if (forPrivateKey) + { + if (type != 2) + { + throw new InvalidCipherTextException("unknown block type"); + } + } + else { - throw new InvalidCipherTextException("unknown block type"); + if (type != 1) + { + throw new InvalidCipherTextException("unknown block type"); + } } // BEGIN android-added if ((type == 1 && forPrivateKey) || (type == 2 && !forPrivateKey)) diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java index d9bb482e..1bc9aaea 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java @@ -219,9 +219,7 @@ private static final int[] Tinv0 = 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0}; - private int shift( - int r, - int shift) + private static int shift(int r, int shift) { return (r >>> shift) | (r << -shift); } @@ -232,7 +230,7 @@ private static final int[] Tinv0 = private static final int m2 = 0x7f7f7f7f; private static final int m3 = 0x0000001b; - private int FFmulX(int x) + private static int FFmulX(int x) { return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3)); } @@ -247,7 +245,7 @@ private static final int[] Tinv0 = */ - private int inv_mcol(int x) + private static int inv_mcol(int x) { int f2 = FFmulX(x); int f4 = FFmulX(f2); @@ -257,7 +255,7 @@ private static final int[] Tinv0 = return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24); } - private int subWord(int x) + private static int subWord(int x) { return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24); } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java index 2374be1f..7e91973d 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java @@ -3,6 +3,9 @@ package org.bouncycastle.crypto.engines; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; +// BEGIN android-added +import org.bouncycastle.crypto.OutputLengthException; +// END android-added import org.bouncycastle.crypto.params.KeyParameter; /** @@ -549,9 +552,7 @@ public class AESFastEngine 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8}; - private int shift( - int r, - int shift) + private static int shift(int r, int shift) { return (r >>> shift) | (r << -shift); } @@ -562,7 +563,7 @@ public class AESFastEngine private static final int m2 = 0x7f7f7f7f; private static final int m3 = 0x0000001b; - private int FFmulX(int x) + private static int FFmulX(int x) { return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3)); } @@ -577,7 +578,7 @@ public class AESFastEngine */ - private int inv_mcol(int x) + private static int inv_mcol(int x) { int f2 = FFmulX(x); int f4 = FFmulX(f2); @@ -588,7 +589,7 @@ public class AESFastEngine } - private int subWord(int x) + private static int subWord(int x) { return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24); } @@ -725,7 +726,9 @@ public class AESFastEngine if ((outOff + (32 / 2)) > out.length) { - throw new DataLengthException("output buffer too short"); + // BEGIN android-changed + throw new OutputLengthException("output buffer too short"); + // END android-changed } if (forEncryption) diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java index d1935eca..c9082183 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java @@ -2,6 +2,9 @@ package org.bouncycastle.crypto.engines; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; +// BEGIN android-added +import org.bouncycastle.crypto.OutputLengthException; +// END android-added import org.bouncycastle.crypto.params.KeyParameter; /** @@ -99,7 +102,9 @@ public class DESedeEngine if ((outOff + BLOCK_SIZE) > out.length) { - throw new DataLengthException("output buffer too short"); + // BEGIN android-changed + throw new OutputLengthException("output buffer too short"); + // END android-changed } byte[] temp = new byte[BLOCK_SIZE]; diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/macs/HMac.java b/bcprov/src/main/java/org/bouncycastle/crypto/macs/HMac.java index c0c83335..f5b931de 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/macs/HMac.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/macs/HMac.java @@ -7,6 +7,7 @@ import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.ExtendedDigest; import org.bouncycastle.crypto.Mac; import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.util.Integers; /** * HMAC implementation based on RFC2104 @@ -33,29 +34,29 @@ public class HMac blockLengths = new Hashtable(); // BEGIN android-removed - // blockLengths.put("GOST3411", Integer.valueOf(32)); + // blockLengths.put("GOST3411", Integers.valueOf(32)); // - // blockLengths.put("MD2", Integer.valueOf(16)); - // blockLengths.put("MD4", Integer.valueOf(64)); + // blockLengths.put("MD2", Integers.valueOf(16)); + // blockLengths.put("MD4", Integers.valueOf(64)); // END android-removed - blockLengths.put("MD5", Integer.valueOf(64)); + blockLengths.put("MD5", Integers.valueOf(64)); // BEGIN android-removed - // blockLengths.put("RIPEMD128", Integer.valueOf(64)); - // blockLengths.put("RIPEMD160", Integer.valueOf(64)); + // blockLengths.put("RIPEMD128", Integers.valueOf(64)); + // blockLengths.put("RIPEMD160", Integers.valueOf(64)); // END android-removed - blockLengths.put("SHA-1", Integer.valueOf(64)); + blockLengths.put("SHA-1", Integers.valueOf(64)); // BEGIN android-removed - // blockLengths.put("SHA-224", Integer.valueOf(64)); + // blockLengths.put("SHA-224", Integers.valueOf(64)); // END android-removed - blockLengths.put("SHA-256", Integer.valueOf(64)); - blockLengths.put("SHA-384", Integer.valueOf(128)); - blockLengths.put("SHA-512", Integer.valueOf(128)); + blockLengths.put("SHA-256", Integers.valueOf(64)); + blockLengths.put("SHA-384", Integers.valueOf(128)); + blockLengths.put("SHA-512", Integers.valueOf(128)); // BEGIN android-removed - // blockLengths.put("Tiger", Integer.valueOf(64)); - // blockLengths.put("Whirlpool", Integer.valueOf(64)); + // blockLengths.put("Tiger", Integers.valueOf(64)); + // blockLengths.put("Whirlpool", Integers.valueOf(64)); // END android-removed } 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 3c3bf341..71b75954 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java @@ -36,6 +36,24 @@ public interface AEADBlockCipher public BlockCipher getUnderlyingCipher(); /** + * Add a single byte to the associated data check. + * <br>If the implementation supports it, this will be an online operation and will not retain the associated data. + * + * @param in the byte to be processed. + */ + public void processAADByte(byte in); + + /** + * Add a sequence of bytes to the associated data check. + * <br>If the implementation supports it, this will be an online operation and will not retain the associated data. + * + * @param in the input byte array. + * @param inOff the offset into the in array where the data to be processed starts. + * @param len the number of bytes to be processed. + */ + public void processAADBytes(byte[] in, int inOff, int len); + + /** * encrypt/decrypt a single byte. * * @param in the byte to be processed. diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java index 1219f6db..d4800e62 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java @@ -93,7 +93,7 @@ public class CBCBlockCipher { reset(); - // if it;s null key is to be reused. + // if it's null, key is to be reused. if (params != null) { cipher.init(encrypting, params); 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 bedc3d13..18a34253 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java @@ -25,10 +25,11 @@ public class CCMBlockCipher private int blockSize; private boolean forEncryption; private byte[] nonce; - private byte[] associatedText; + private byte[] initialAssociatedText; private int macSize; private CipherParameters keyParam; private byte[] macBlock; + private ByteArrayOutputStream associatedText = new ByteArrayOutputStream(); private ByteArrayOutputStream data = new ByteArrayOutputStream(); /** @@ -69,7 +70,7 @@ public class CCMBlockCipher AEADParameters param = (AEADParameters)params; nonce = param.getNonce(); - associatedText = param.getAssociatedText(); + initialAssociatedText = param.getAssociatedText(); macSize = param.getMacSize() / 8; keyParam = param.getKey(); } @@ -78,7 +79,7 @@ public class CCMBlockCipher ParametersWithIV param = (ParametersWithIV)params; nonce = param.getIV(); - associatedText = null; + initialAssociatedText = null; macSize = macBlock.length / 2; keyParam = param.getParameters(); } @@ -93,6 +94,17 @@ public class CCMBlockCipher return cipher.getAlgorithmName() + "/CCM"; } + public void processAADByte(byte in) + { + associatedText.write(in); + } + + public void processAADBytes(byte[] in, int inOff, int len) + { + // TODO: Process AAD online + associatedText.write(in, inOff, len); + } + public int processByte(byte in, byte[] out, int outOff) throws DataLengthException, IllegalStateException { @@ -125,6 +137,7 @@ public class CCMBlockCipher public void reset() { cipher.reset(); + associatedText.reset(); data.reset(); } @@ -150,60 +163,62 @@ public class CCMBlockCipher public int getOutputSize(int len) { + int totalData = len + data.size(); + if (forEncryption) { - return data.size() + len + macSize; - } - else - { - return data.size() + len - macSize; + return totalData + macSize; } + + return totalData < macSize ? 0 : totalData - macSize; } public byte[] processPacket(byte[] in, int inOff, int inLen) throws IllegalStateException, InvalidCipherTextException { + // TODO: handle null keyParam (e.g. via RepeatedKeySpec) + // Need to keep the CTR and CBC Mac parts around and reset if (keyParam == null) { throw new IllegalStateException("CCM cipher unitialized."); } - + BlockCipher ctrCipher = new SICBlockCipher(cipher); byte[] iv = new byte[blockSize]; byte[] out; iv[0] = (byte)(((15 - nonce.length) - 1) & 0x7); - + System.arraycopy(nonce, 0, iv, 1, nonce.length); - + ctrCipher.init(forEncryption, new ParametersWithIV(keyParam, iv)); - + if (forEncryption) { int index = inOff; int outOff = 0; - + out = new byte[inLen + macSize]; - + calculateMac(in, inOff, inLen, macBlock); - + ctrCipher.processBlock(macBlock, 0, macBlock, 0); // S0 - + while (index < inLen - blockSize) // S1... { ctrCipher.processBlock(in, index, out, outOff); outOff += blockSize; index += blockSize; } - + byte[] block = new byte[blockSize]; - + System.arraycopy(in, index, block, 0, inLen - index); - + ctrCipher.processBlock(block, 0, block, 0); - + System.arraycopy(block, 0, out, outOff, inLen - index); - + outOff += inLen - index; System.arraycopy(macBlock, 0, out, outOff, out.length - outOff); @@ -212,49 +227,49 @@ public class CCMBlockCipher { int index = inOff; int outOff = 0; - + out = new byte[inLen - macSize]; - + System.arraycopy(in, inOff + inLen - macSize, macBlock, 0, macSize); - + ctrCipher.processBlock(macBlock, 0, macBlock, 0); - + for (int i = macSize; i != macBlock.length; i++) { macBlock[i] = 0; } - + while (outOff < out.length - blockSize) { ctrCipher.processBlock(in, index, out, outOff); outOff += blockSize; index += blockSize; } - + byte[] block = new byte[blockSize]; - + System.arraycopy(in, index, block, 0, out.length - outOff); - + ctrCipher.processBlock(block, 0, block, 0); - + System.arraycopy(block, 0, out, outOff, out.length - outOff); - + byte[] calculatedMacBlock = new byte[blockSize]; - + calculateMac(out, 0, out.length, calculatedMacBlock); - + if (!Arrays.constantTimeAreEqual(macBlock, calculatedMacBlock)) { throw new InvalidCipherTextException("mac check in CCM failed"); } } - + return out; } - + private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock) { - Mac cMac = new CBCBlockCipherMac(cipher, macSize * 8); + Mac cMac = new CBCBlockCipherMac(cipher, macSize * 8); cMac.init(keyParam); @@ -292,10 +307,11 @@ public class CCMBlockCipher { int extra; - if (associatedText.length < ((1 << 16) - (1 << 8))) + int textLength = getAssociatedTextLength(); + if (textLength < ((1 << 16) - (1 << 8))) { - cMac.update((byte)(associatedText.length >> 8)); - cMac.update((byte)associatedText.length); + cMac.update((byte)(textLength >> 8)); + cMac.update((byte)textLength); extra = 2; } @@ -303,17 +319,25 @@ public class CCMBlockCipher { cMac.update((byte)0xff); cMac.update((byte)0xfe); - cMac.update((byte)(associatedText.length >> 24)); - cMac.update((byte)(associatedText.length >> 16)); - cMac.update((byte)(associatedText.length >> 8)); - cMac.update((byte)associatedText.length); + cMac.update((byte)(textLength >> 24)); + cMac.update((byte)(textLength >> 16)); + cMac.update((byte)(textLength >> 8)); + cMac.update((byte)textLength); extra = 6; } - - cMac.update(associatedText, 0, associatedText.length); - - extra = (extra + associatedText.length) % 16; + + if (initialAssociatedText != null) + { + cMac.update(initialAssociatedText, 0, initialAssociatedText.length); + } + if (associatedText.size() > 0) + { + byte[] tmp = associatedText.toByteArray(); + cMac.update(tmp, 0, tmp.length); + } + + extra = (extra + textLength) % 16; if (extra != 0) { for (int i = 0; i != 16 - extra; i++) @@ -331,8 +355,13 @@ public class CCMBlockCipher return cMac.doFinal(macBlock, 0); } + private int getAssociatedTextLength() + { + return associatedText.size() + ((initialAssociatedText == null) ? 0 : initialAssociatedText.length); + } + private boolean hasAssociatedText() { - return associatedText != null && associatedText.length != 0; + return getAssociatedTextLength() > 0; } } 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 0af49f4d..d0fb9bb6 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java @@ -68,36 +68,40 @@ public class CFBBlockCipher if (params instanceof ParametersWithIV) { - ParametersWithIV ivParam = (ParametersWithIV)params; - byte[] iv = ivParam.getIV(); + ParametersWithIV ivParam = (ParametersWithIV)params; + byte[] iv = ivParam.getIV(); - if (iv.length < IV.length) + if (iv.length < IV.length) + { + // prepend the supplied IV with zeros (per FIPS PUB 81) + System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length); + for (int i = 0; i < IV.length - iv.length; i++) { - // prepend the supplied IV with zeros (per FIPS PUB 81) - System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length); - for (int i = 0; i < IV.length - iv.length; i++) - { - IV[i] = 0; - } - } - else - { - System.arraycopy(iv, 0, IV, 0, IV.length); + IV[i] = 0; } + } + else + { + System.arraycopy(iv, 0, IV, 0, IV.length); + } - reset(); + 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()); + } } else { - reset(); + reset(); + // if it's null, key is to be reused. + if (params != null) + { cipher.init(true, params); + } } } 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 7c98efae..9e617ec9 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java @@ -4,7 +4,9 @@ import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.modes.gcm.GCMExponentiator; import org.bouncycastle.crypto.modes.gcm.GCMMultiplier; +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; @@ -20,28 +22,31 @@ public class GCMBlockCipher implements AEADBlockCipher { private static final int BLOCK_SIZE = 16; - private static final byte[] ZEROES = new byte[BLOCK_SIZE]; // not final due to a compiler bug private BlockCipher cipher; private GCMMultiplier multiplier; + private GCMExponentiator exp; // These fields are set by init and not modified by processing private boolean forEncryption; private int macSize; private byte[] nonce; - private byte[] A; + private byte[] initialAssociatedText; private byte[] H; - private byte[] initS; private byte[] J0; // These fields are modified during processing private byte[] bufBlock; private byte[] macBlock; - private byte[] S; + private byte[] S, S_at, S_atPre; private byte[] counter; private int bufOff; private long totalLength; + private byte[] atBlock; + private int atBlockPos; + private long atLength; + private long atLengthPre; public GCMBlockCipher(BlockCipher c) { @@ -82,14 +87,14 @@ public class GCMBlockCipher this.forEncryption = forEncryption; this.macBlock = null; - KeyParameter keyParam; + KeyParameter keyParam; if (params instanceof AEADParameters) { AEADParameters param = (AEADParameters)params; nonce = param.getNonce(); - A = param.getAssociatedText(); + initialAssociatedText = param.getAssociatedText(); int macSizeBits = param.getMacSize(); if (macSizeBits < 96 || macSizeBits > 128 || macSizeBits % 8 != 0) @@ -105,7 +110,7 @@ public class GCMBlockCipher ParametersWithIV param = (ParametersWithIV)params; nonce = param.getIV(); - A = null; + initialAssociatedText = null; macSize = 16; keyParam = (KeyParameter)param.getParameters(); } @@ -122,48 +127,54 @@ public class GCMBlockCipher throw new IllegalArgumentException("IV must be at least 1 byte"); } - if (A == null) - { - // Avoid lots of null checks - A = new byte[0]; - } + // TODO This should be configurable by init parameters + // (but must be 16 if nonce length not 12) (BLOCK_SIZE?) +// this.tagLength = 16; // Cipher always used in forward mode // if keyParam is null we're reusing the last key. if (keyParam != null) { cipher.init(true, keyParam); - } - // TODO This should be configurable by init parameters - // (but must be 16 if nonce length not 12) (BLOCK_SIZE?) -// this.tagLength = 16; + this.H = new byte[BLOCK_SIZE]; + cipher.processBlock(H, 0, H, 0); - this.H = new byte[BLOCK_SIZE]; - cipher.processBlock(ZEROES, 0, H, 0); - multiplier.init(H); + // GCMMultiplier tables don't change unless the key changes (and are expensive to init) + multiplier.init(H); + exp = null; + } - this.initS = gHASH(A); + this.J0 = new byte[BLOCK_SIZE]; if (nonce.length == 12) { - this.J0 = new byte[16]; System.arraycopy(nonce, 0, J0, 0, nonce.length); - this.J0[15] = 0x01; + this.J0[BLOCK_SIZE - 1] = 0x01; } else { - this.J0 = gHASH(nonce); - byte[] X = new byte[16]; - packLength((long)nonce.length * 8, X, 8); - xor(this.J0, X); - multiplier.multiplyH(this.J0); + gHASH(J0, nonce, nonce.length); + byte[] X = new byte[BLOCK_SIZE]; + Pack.longToBigEndian((long)nonce.length * 8, X, 8); + gHASHBlock(J0, X); } - this.S = Arrays.clone(initS); + this.S = new byte[BLOCK_SIZE]; + this.S_at = new byte[BLOCK_SIZE]; + this.S_atPre = new byte[BLOCK_SIZE]; + this.atBlock = new byte[BLOCK_SIZE]; + this.atBlockPos = 0; + this.atLength = 0; + this.atLengthPre = 0; this.counter = Arrays.clone(J0); this.bufOff = 0; this.totalLength = 0; + + if (initialAssociatedText != null) + { + processAADBytes(initialAssociatedText, 0, initialAssociatedText.length); + } } public byte[] getMac() @@ -173,23 +184,88 @@ public class GCMBlockCipher public int getOutputSize(int len) { + int totalData = len + bufOff; + if (forEncryption) { - return len + bufOff + macSize; + return totalData + macSize; } - return len + bufOff - macSize; + return totalData < macSize ? 0 : totalData - macSize; } public int getUpdateOutputSize(int len) { - return ((len + bufOff) / BLOCK_SIZE) * BLOCK_SIZE; + int totalData = len + bufOff; + if (!forEncryption) + { + if (totalData < macSize) + { + return 0; + } + totalData -= macSize; + } + return totalData - totalData % BLOCK_SIZE; + } + + public void processAADByte(byte in) + { + atBlock[atBlockPos] = in; + if (++atBlockPos == BLOCK_SIZE) + { + // Hash each block as it fills + gHASHBlock(S_at, atBlock); + atBlockPos = 0; + atLength += BLOCK_SIZE; + } + } + + public void processAADBytes(byte[] in, int inOff, int len) + { + for (int i = 0; i < len; ++i) + { + atBlock[atBlockPos] = in[inOff + i]; + if (++atBlockPos == BLOCK_SIZE) + { + // Hash each block as it fills + gHASHBlock(S_at, atBlock); + atBlockPos = 0; + atLength += BLOCK_SIZE; + } + } + } + + private void initCipher() + { + if (atLength > 0) + { + System.arraycopy(S_at, 0, S_atPre, 0, BLOCK_SIZE); + atLengthPre = atLength; + } + + // Finish hash for partial AAD block + if (atBlockPos > 0) + { + gHASHPartial(S_atPre, atBlock, 0, atBlockPos); + atLengthPre += atBlockPos; + } + + if (atLengthPre > 0) + { + System.arraycopy(S_atPre, 0, S, 0, BLOCK_SIZE); + } } public int processByte(byte in, byte[] out, int outOff) throws DataLengthException { - return process(in, out, outOff); + bufBlock[bufOff] = in; + if (++bufOff == bufBlock.length) + { + outputBlock(out, outOff); + return BLOCK_SIZE; + } + return 0; } public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) @@ -197,21 +273,12 @@ public class GCMBlockCipher { int resultLen = 0; - for (int i = 0; i != len; i++) + for (int i = 0; i < len; ++i) { -// resultLen += process(in[inOff + i], out, outOff + resultLen); - bufBlock[bufOff++] = in[inOff + i]; - - if (bufOff == bufBlock.length) + bufBlock[bufOff] = in[inOff + i]; + if (++bufOff == bufBlock.length) { - gCTRBlock(bufBlock, BLOCK_SIZE, out, outOff + resultLen); - if (!forEncryption) - { - System.arraycopy(bufBlock, BLOCK_SIZE, bufBlock, 0, macSize); - } -// bufOff = 0; - bufOff = bufBlock.length - BLOCK_SIZE; -// return bufBlock.Length; + outputBlock(out, outOff + resultLen); resultLen += BLOCK_SIZE; } } @@ -219,30 +286,32 @@ public class GCMBlockCipher return resultLen; } - private int process(byte in, byte[] out, int outOff) - throws DataLengthException + private void outputBlock(byte[] output, int offset) { - bufBlock[bufOff++] = in; - - if (bufOff == bufBlock.length) + if (totalLength == 0) { - gCTRBlock(bufBlock, BLOCK_SIZE, out, outOff); - if (!forEncryption) - { - System.arraycopy(bufBlock, BLOCK_SIZE, bufBlock, 0, macSize); - } -// bufOff = 0; - bufOff = bufBlock.length - BLOCK_SIZE; -// return bufBlock.length; - return BLOCK_SIZE; + initCipher(); + } + gCTRBlock(bufBlock, output, offset); + if (forEncryption) + { + bufOff = 0; + } + else + { + System.arraycopy(bufBlock, BLOCK_SIZE, bufBlock, 0, macSize); + bufOff = macSize; } - - return 0; } public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException { + if (totalLength == 0) + { + initCipher(); + } + int extra = bufOff; if (!forEncryption) { @@ -255,18 +324,57 @@ public class GCMBlockCipher if (extra > 0) { - byte[] tmp = new byte[BLOCK_SIZE]; - System.arraycopy(bufBlock, 0, tmp, 0, extra); - gCTRBlock(tmp, extra, out, outOff); + gCTRPartial(bufBlock, 0, extra, out, outOff); + } + + atLength += atBlockPos; + + if (atLength > atLengthPre) + { + /* + * Some AAD was sent after the cipher started. We determine the difference b/w the hash value + * we actually used when the cipher started (S_atPre) and the final hash value calculated (S_at). + * Then we carry this difference forward by multiplying by H^c, where c is the number of (full or + * partial) cipher-text blocks produced, and adjust the current hash. + */ + + // Finish hash for partial AAD block + if (atBlockPos > 0) + { + gHASHPartial(S_at, atBlock, 0, atBlockPos); + } + + // Find the difference between the AAD hashes + if (atLengthPre > 0) + { + xor(S_at, S_atPre); + } + + // Number of cipher-text blocks produced + long c = ((totalLength * 8) + 127) >>> 7; + + // Calculate the adjustment factor + byte[] H_c = new byte[16]; + if (exp == null) + { + exp = new Tables1kGCMExponentiator(); + exp.init(H); + } + exp.exponentiateX(c, H_c); + + // Carry the difference forward + multiply(S_at, H_c); + + // Adjust the current hash + xor(S, S_at); } // Final gHASH - byte[] X = new byte[16]; - packLength((long)A.length * 8, X, 0); - packLength(totalLength * 8, X, 8); + byte[] X = new byte[BLOCK_SIZE]; + Pack.longToBigEndian(atLength * 8, X, 0); + Pack.longToBigEndian(totalLength * 8, X, 8); - xor(S, X); - multiplier.multiplyH(S); + gHASHBlock(S, X); // TODO Fix this if tagLength becomes configurable // T = MSBt(GCTRk(J0,S)) @@ -310,7 +418,15 @@ public class GCMBlockCipher private void reset( boolean clearMac) { - S = Arrays.clone(initS); + cipher.reset(); + + S = new byte[BLOCK_SIZE]; + S_at = new byte[BLOCK_SIZE]; + S_atPre = new byte[BLOCK_SIZE]; + atBlock = new byte[BLOCK_SIZE]; + atBlockPos = 0; + atLength = 0; + atLengthPre = 0; counter = Arrays.clone(J0); bufOff = 0; totalLength = 0; @@ -325,12 +441,59 @@ public class GCMBlockCipher macBlock = null; } - cipher.reset(); + if (initialAssociatedText != null) + { + processAADBytes(initialAssociatedText, 0, initialAssociatedText.length); + } + } + + private void gCTRBlock(byte[] block, byte[] out, int outOff) + { + byte[] tmp = getNextCounterBlock(); + + xor(tmp, block); + System.arraycopy(tmp, 0, out, outOff, BLOCK_SIZE); + + gHASHBlock(S, forEncryption ? tmp : block); + + totalLength += BLOCK_SIZE; + } + + private void gCTRPartial(byte[] buf, int off, int len, byte[] out, int outOff) + { + byte[] tmp = getNextCounterBlock(); + + xor(tmp, buf, off, len); + System.arraycopy(tmp, 0, out, outOff, len); + + gHASHPartial(S, forEncryption ? tmp : buf, 0, len); + + totalLength += len; + } + + private void gHASH(byte[] Y, byte[] b, int len) + { + for (int pos = 0; pos < len; pos += BLOCK_SIZE) + { + int num = Math.min(len - pos, BLOCK_SIZE); + gHASHPartial(Y, b, pos, num); + } + } + + private void gHASHBlock(byte[] Y, byte[] b) + { + xor(Y, b); + multiplier.multiplyH(Y); + } + + private void gHASHPartial(byte[] Y, byte[] b, int off, int len) + { + xor(Y, b, off, len); + multiplier.multiplyH(Y); } - private void gCTRBlock(byte[] buf, int bufCount, byte[] out, int outOff) + private byte[] getNextCounterBlock() { -// inc(counter); for (int i = 15; i >= 12; --i) { byte b = (byte)((counter[i] + 1) & 0xff); @@ -343,68 +506,56 @@ public class GCMBlockCipher } byte[] tmp = new byte[BLOCK_SIZE]; + // TODO Sure would be nice if ciphers could operate on int[] cipher.processBlock(counter, 0, tmp, 0); + return tmp; + } - byte[] hashBytes; - if (forEncryption) - { - System.arraycopy(ZEROES, bufCount, tmp, bufCount, BLOCK_SIZE - bufCount); - hashBytes = tmp; - } - else - { - hashBytes = buf; - } + private static void multiply(byte[] block, byte[] val) + { + byte[] tmp = Arrays.clone(block); + byte[] c = new byte[16]; - for (int i = bufCount - 1; i >= 0; --i) + for (int i = 0; i < 16; ++i) { - tmp[i] ^= buf[i]; - out[outOff + i] = tmp[i]; - } + byte bits = val[i]; + for (int j = 7; j >= 0; --j) + { + if ((bits & (1 << j)) != 0) + { + xor(c, tmp); + } -// gHASHBlock(hashBytes); - xor(S, hashBytes); - multiplier.multiplyH(S); + boolean lsb = (tmp[15] & 1) != 0; + shiftRight(tmp); + if (lsb) + { + // R = new byte[]{ 0xe1, ... }; +// xor(v, R); + tmp[0] ^= (byte)0xe1; + } + } + } - totalLength += bufCount; + System.arraycopy(c, 0, block, 0, 16); } - private byte[] gHASH(byte[] b) + private static void shiftRight(byte[] block) { - byte[] Y = new byte[16]; - - for (int pos = 0; pos < b.length; pos += 16) + int i = 0; + int bit = 0; + for (;;) { - byte[] X = new byte[16]; - int num = Math.min(b.length - pos, 16); - System.arraycopy(b, pos, X, 0, num); - xor(Y, X); - multiplier.multiplyH(Y); + int b = block[i] & 0xff; + block[i] = (byte) ((b >>> 1) | bit); + if (++i == 16) + { + break; + } + bit = (b & 1) << 7; } - - return Y; } -// private void gHASHBlock(byte[] block) -// { -// xor(S, block); -// multiplier.multiplyH(S); -// } - -// private static void inc(byte[] block) -// { -// for (int i = 15; i >= 12; --i) -// { -// byte b = (byte)((block[i] + 1) & 0xff); -// block[i] = b; -// -// if (b != 0) -// { -// break; -// } -// } -// } - private static void xor(byte[] block, byte[] val) { for (int i = 15; i >= 0; --i) @@ -413,9 +564,11 @@ public class GCMBlockCipher } } - private static void packLength(long count, byte[] bs, int off) + private static void xor(byte[] block, byte[] val, int off, int len) { - Pack.intToBigEndian((int)(count >>> 32), bs, off); - Pack.intToBigEndian((int)count, bs, off + 4); + while (len-- > 0) + { + block[len] ^= val[off + len]; + } } } 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 728a2e7a..5297698f 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java @@ -65,36 +65,40 @@ public class OFBBlockCipher { if (params instanceof ParametersWithIV) { - ParametersWithIV ivParam = (ParametersWithIV)params; - byte[] iv = ivParam.getIV(); - - if (iv.length < IV.length) - { - // prepend the supplied IV with zeros (per FIPS PUB 81) - System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length); - for (int i = 0; i < IV.length - iv.length; i++) - { - IV[i] = 0; - } - } - else - { - System.arraycopy(iv, 0, IV, 0, IV.length); - } - - reset(); - - // if null it's an IV changed only. - if (ivParam.getParameters() != null) + ParametersWithIV ivParam = (ParametersWithIV)params; + byte[] iv = ivParam.getIV(); + + if (iv.length < IV.length) + { + // prepend the supplied IV with zeros (per FIPS PUB 81) + System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length); + for (int i = 0; i < IV.length - iv.length; i++) { - cipher.init(true, ivParam.getParameters()); + IV[i] = 0; } + } + else + { + 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()); + } } else { - reset(); + reset(); + // if it's null, key is to be reused. + if (params != null) + { cipher.init(true, params); + } } } 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 af9f18db..da8c4ae1 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java @@ -9,7 +9,8 @@ import org.bouncycastle.crypto.params.ParametersWithIV; * 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 +public class SICBlockCipher + implements BlockCipher { private final BlockCipher cipher; private final int blockSize; @@ -94,22 +95,10 @@ public class SICBlockCipher implements BlockCipher out[outOff + i] = (byte)(counterOut[i] ^ in[inOff + i]); } - int carry = 1; - - for (int i = counter.length - 1; i >= 0; i--) + // increment counter by 1. + for (int i = counter.length - 1; i >= 0 && ++counter[i] == 0; i--) { - int x = (counter[i] & 0xff) + carry; - - if (x > 0xff) - { - carry = 1; - } - else - { - carry = 0; - } - - counter[i] = (byte)x; + ; // do nothing - pre-increment and test for 0 in counter does the job. } return counter.length; diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMExponentiator.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMExponentiator.java new file mode 100644 index 00000000..e1cc5c76 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMExponentiator.java @@ -0,0 +1,7 @@ +package org.bouncycastle.crypto.modes.gcm; + +public interface GCMExponentiator +{ + void init(byte[] x); + void exponentiateX(long pow, byte[] 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 ce02be4d..48753011 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 @@ -19,14 +19,23 @@ abstract class GCMUtil return tmp; } + static byte[] asBytes(int[] ns) + { + byte[] output = new byte[16]; + Pack.intToBigEndian(ns, output, 0); + return output; + } + static int[] asInts(byte[] bs) { - int[] us = new int[4]; - us[0] = Pack.bigEndianToInt(bs, 0); - us[1] = Pack.bigEndianToInt(bs, 4); - us[2] = Pack.bigEndianToInt(bs, 8); - us[3] = Pack.bigEndianToInt(bs, 12); - return us; + int[] output = new int[4]; + Pack.bigEndianToInt(bs, 0, output); + return output; + } + + static void asInts(byte[] bs, int[] output) + { + Pack.bigEndianToInt(bs, 0, output); } static void multiply(byte[] block, byte[] val) @@ -71,6 +80,17 @@ abstract class GCMUtil } } + static void multiplyP(int[] x, int[] output) + { + boolean lsb = (x[3] & 1) != 0; + shiftRight(x, output); + if (lsb) + { + output[0] ^= 0xe1000000; + } + } + + // P is the value with only bit i=1 set static void multiplyP8(int[] x) { // for (int i = 8; i != 0; --i) @@ -89,6 +109,19 @@ abstract class GCMUtil } } + static void multiplyP8(int[] x, int[] output) + { + 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)); + } + } + } + static void shiftRight(byte[] block) { int i = 0; @@ -105,6 +138,22 @@ abstract class GCMUtil } } + static void shiftRight(byte[] block, byte[] output) + { + int i = 0; + int bit = 0; + for (;;) + { + int b = block[i] & 0xff; + output[i] = (byte) ((b >>> 1) | bit); + if (++i == 16) + { + break; + } + bit = (b & 1) << 7; + } + } + static void shiftRight(int[] block) { int i = 0; @@ -121,6 +170,22 @@ abstract class GCMUtil } } + static void shiftRight(int[] block, int[] output) + { + int i = 0; + int bit = 0; + for (;;) + { + int b = block[i]; + output[i] = (b >>> 1) | bit; + if (++i == 4) + { + break; + } + bit = b << 31; + } + } + static void shiftRightN(int[] block, int n) { int i = 0; @@ -137,6 +202,22 @@ abstract class GCMUtil } } + static void shiftRightN(int[] block, int n, int[] output) + { + int i = 0; + int bits = 0; + for (;;) + { + int b = block[i]; + output[i] = (b >>> n) | bits; + if (++i == 4) + { + break; + } + bits = b << (32 - n); + } + } + static void xor(byte[] block, byte[] val) { for (int i = 15; i >= 0; --i) @@ -145,6 +226,22 @@ abstract class GCMUtil } } + static void xor(byte[] block, byte[] val, int off, int len) + { + while (len-- > 0) + { + block[len] ^= val[off + len]; + } + } + + static void xor(byte[] block, byte[] val, byte[] output) + { + for (int i = 15; i >= 0; --i) + { + output[i] = (byte)(block[i] ^ val[i]); + } + } + static void xor(int[] block, int[] val) { for (int i = 3; i >= 0; --i) @@ -152,4 +249,12 @@ abstract class GCMUtil block[i] ^= val[i]; } } + + static void xor(int[] block, int[] val, int[] output) + { + for (int i = 3; i >= 0; --i) + { + output[i] = block[i] ^ val[i]; + } + } } 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 new file mode 100644 index 00000000..a0512086 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java @@ -0,0 +1,57 @@ +package org.bouncycastle.crypto.modes.gcm; + +import java.util.Vector; + +import org.bouncycastle.util.Arrays; + +public class Tables1kGCMExponentiator implements GCMExponentiator +{ + // A lookup table of the power-of-two powers of 'x' + // - lookupPowX2[i] = x^(2^i) + private Vector lookupPowX2; + + public void init(byte[] x) + { + if (lookupPowX2 != null && Arrays.areEqual(x, (byte[])lookupPowX2.elementAt(0))) + { + return; + } + + lookupPowX2 = new Vector(8); + lookupPowX2.addElement(Arrays.clone(x)); + } + + public void exponentiateX(long pow, byte[] output) + { + byte[] y = GCMUtil.oneAsBytes(); + int bit = 0; + while (pow > 0) + { + if ((pow & 1L) != 0) + { + ensureAvailable(bit); + GCMUtil.multiply(y, (byte[])lookupPowX2.elementAt(bit)); + } + ++bit; + pow >>>= 1; + } + + System.arraycopy(y, 0, output, 0, 16); + } + + private void ensureAvailable(int bit) + { + int count = lookupPowX2.size(); + if (count <= bit) + { + byte[] tmp = (byte[])lookupPowX2.elementAt(count - 1); + do + { + tmp = Arrays.clone(tmp); + GCMUtil.multiply(tmp, tmp); + lookupPowX2.addElement(tmp); + } + while (++count <= bit); + } + } +} 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 9d21cf0e..8535db5a 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,41 +1,40 @@ package org.bouncycastle.crypto.modes.gcm; import org.bouncycastle.crypto.util.Pack; +import org.bouncycastle.util.Arrays; -public class Tables8kGCMMultiplier implements GCMMultiplier +public class Tables8kGCMMultiplier implements GCMMultiplier { - private final int[][][] M = new int[32][16][]; + private byte[] H; + private int[][][] M; public void init(byte[] H) { - M[0][0] = new int[4]; - M[1][0] = new int[4]; - M[1][8] = GCMUtil.asInts(H); - - for (int j = 4; j >= 1; j >>= 1) + if (M == null) { - int[] tmp = new int[4]; - System.arraycopy(M[1][j + j], 0, tmp, 0, 4); - - GCMUtil.multiplyP(tmp); - M[1][j] = tmp; + M = new int[32][16][4]; } - + else if (Arrays.areEqual(this.H, H)) { - int[] tmp = new int[4]; - System.arraycopy(M[1][1], 0, tmp, 0, 4); - - GCMUtil.multiplyP(tmp); - M[0][8] = tmp; + return; } + this.H = Arrays.clone(H); + + // M[0][0] is ZEROES; + // M[1][0] is ZEROES; + GCMUtil.asInts(H, M[1][8]); + for (int j = 4; j >= 1; j >>= 1) { - int[] tmp = new int[4]; - System.arraycopy(M[0][j + j], 0, tmp, 0, 4); + GCMUtil.multiplyP(M[1][j + j], M[1][j]); + } + + GCMUtil.multiplyP(M[1][1], M[0][8]); - GCMUtil.multiplyP(tmp); - M[0][j] = tmp; + for (int j = 4; j >= 1; j >>= 1) + { + GCMUtil.multiplyP(M[0][j + j], M[0][j]); } int i = 0; @@ -45,11 +44,7 @@ public class Tables8kGCMMultiplier implements GCMMultiplier { for (int k = 1; k < j; ++k) { - int[] tmp = new int[4]; - System.arraycopy(M[i][j], 0, tmp, 0, 4); - - GCMUtil.xor(tmp, M[i][k]); - M[i][j + k] = tmp; + GCMUtil.xor(M[i][j], M[i][k], M[i][j + k]); } } @@ -60,14 +55,10 @@ public class Tables8kGCMMultiplier implements GCMMultiplier if (i > 1) { - M[i][0] = new int[4]; + // M[i][0] is ZEROES; for(int j = 8; j > 0; j >>= 1) { - int[] tmp = new int[4]; - System.arraycopy(M[i - 2][j], 0, tmp, 0, 4); - - GCMUtil.multiplyP8(tmp); - M[i][j] = tmp; + GCMUtil.multiplyP8(M[i - 2][j], M[i][j]); } } } @@ -96,4 +87,4 @@ public class Tables8kGCMMultiplier implements GCMMultiplier Pack.intToBigEndian(z, x, 0); } -} +}
\ No newline at end of file diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java index ec412b95..ee3fd60e 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java @@ -5,6 +5,7 @@ import org.bouncycastle.crypto.BufferedBlockCipher; 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.ParametersWithRandom; /** @@ -191,7 +192,7 @@ public class PaddedBufferedBlockCipher { if ((outOff + length) > out.length) { - throw new DataLengthException("output buffer too short"); + throw new OutputLengthException("output buffer too short"); } } @@ -254,7 +255,7 @@ public class PaddedBufferedBlockCipher { reset(); - throw new DataLengthException("output buffer too short"); + throw new OutputLengthException("output buffer too short"); } resultLen = cipher.processBlock(buf, 0, out, outOff); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/AEADParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/AEADParameters.java index b60ef400..9a9272ba 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/params/AEADParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/AEADParameters.java @@ -16,7 +16,19 @@ public class AEADParameters * @param key key to be used by underlying cipher * @param macSize macSize in bits * @param nonce nonce to be used - * @param associatedText associated text, if any + */ + public AEADParameters(KeyParameter key, int macSize, byte[] nonce) + { + this(key, macSize, nonce, null); + } + + /** + * Base constructor. + * + * @param key key to be used by underlying cipher + * @param macSize macSize in bits + * @param nonce nonce to be used + * @param associatedText initial associated text, if any */ public AEADParameters(KeyParameter key, int macSize, byte[] nonce, byte[] associatedText) { diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java index 8ddfac85..394f2c2f 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java @@ -6,10 +6,10 @@ import java.math.BigInteger; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERInteger; import org.bouncycastle.asn1.nist.NISTNamedCurves; // BEGIN android-removed // import org.bouncycastle.asn1.oiw.ElGamalParameter; @@ -98,7 +98,7 @@ public class PrivateKeyFactory else if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.dhKeyAgreement)) { DHParameter params = DHParameter.getInstance(algId.getParameters()); - DERInteger derX = (DERInteger)keyInfo.parsePrivateKey(); + ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey(); BigInteger lVal = params.getL(); int l = lVal == null ? 0 : lVal.intValue(); @@ -110,7 +110,7 @@ public class PrivateKeyFactory // else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm)) // { // ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters()); - // DERInteger derX = (DERInteger)keyInfo.parsePrivateKey(); + // ASN1Integer = (ASN1Integer)keyInfo.parsePrivateKey(); // // return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters( // params.getP(), params.getG())); @@ -118,7 +118,7 @@ public class PrivateKeyFactory // END android-removed else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa)) { - DERInteger derX = (DERInteger)keyInfo.parsePrivateKey(); + ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey(); ASN1Encodable de = algId.getParameters(); DSAParameters parameters = null; diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java index 05520f0e..6a5c88e0 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java @@ -6,11 +6,11 @@ import java.math.BigInteger; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERInteger; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.nist.NISTNamedCurves; // BEGIN android-removed @@ -133,7 +133,7 @@ public class PublicKeyFactory else if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.dhKeyAgreement)) { DHParameter params = DHParameter.getInstance(algId.getParameters()); - DERInteger derY = (DERInteger)keyInfo.parsePublicKey(); + ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey(); BigInteger lVal = params.getL(); int l = lVal == null ? 0 : lVal.intValue(); @@ -145,7 +145,7 @@ public class PublicKeyFactory // else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm)) // { // ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters()); - // DERInteger derY = (DERInteger)keyInfo.parsePublicKey(); + // ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey(); // // return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters( // params.getP(), params.getG())); @@ -154,7 +154,7 @@ public class PublicKeyFactory else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa) || algId.getAlgorithm().equals(OIWObjectIdentifiers.dsaWithSHA1)) { - DERInteger derY = (DERInteger)keyInfo.parsePublicKey(); + ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey(); ASN1Encodable de = algId.getParameters(); DSAParameters parameters = null; |