diff options
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto/macs')
7 files changed, 179 insertions, 89 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/macs/CMac.java b/bcprov/src/main/java/org/bouncycastle/crypto/macs/CMac.java index 1aa8ede4..0492ae69 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/macs/CMac.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/macs/CMac.java @@ -58,14 +58,14 @@ public class CMac implements Mac /** * create a standard MAC based on a block cipher with the size of the * MAC been given in bits. - * <p/> + * <p> * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81), * or 16 bits if being used as a data authenticator (FIPS Publication 113), * and in general should be less than the size of the block cipher as it reduces * the chance of an exhaustive attack (see Handbook of Applied Cryptography). * * @param cipher the cipher to be used as the basis of the MAC generation. - * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8 and <= 128. + * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8 and <= 128. */ public CMac(BlockCipher cipher, int macSizeInBits) { @@ -133,24 +133,31 @@ public class CMac implements Mac public void init(CipherParameters params) { - if (params instanceof KeyParameter) - { - cipher.init(true, params); - - //initializes the L, Lu, Lu2 numbers - L = new byte[ZEROES.length]; - cipher.processBlock(ZEROES, 0, L, 0); - Lu = doubleLu(L); - Lu2 = doubleLu(Lu); - } else if (params != null) - { - // CMAC mode does not permit IV to underlying CBC mode - throw new IllegalArgumentException("CMac mode only permits key to be set."); - } + validate(params); + + cipher.init(true, params); + + //initializes the L, Lu, Lu2 numbers + L = new byte[ZEROES.length]; + cipher.processBlock(ZEROES, 0, L, 0); + Lu = doubleLu(L); + Lu2 = doubleLu(Lu); reset(); } + void validate(CipherParameters params) + { + if (params != null) + { + if (!(params instanceof KeyParameter)) + { + // CMAC mode does not permit IV to underlying CBC mode + throw new IllegalArgumentException("CMac mode only permits key to be set."); + } + } + } + public int getMacSize() { return macSize; diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/macs/CMacWithIV.java b/bcprov/src/main/java/org/bouncycastle/crypto/macs/CMacWithIV.java new file mode 100644 index 00000000..a0371d95 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/macs/CMacWithIV.java @@ -0,0 +1,27 @@ +package org.bouncycastle.crypto.macs; + +import org.bouncycastle.crypto.BlockCipher; +import org.bouncycastle.crypto.CipherParameters; + +/** + * A non-NIST variant which allows passing of an IV to the underlying CBC cipher. + * <p>Note: there isn't really a good reason to use an IV here, use the regular CMac where possible.</p> + */ +public class CMacWithIV + extends CMac +{ + public CMacWithIV(BlockCipher cipher) + { + super(cipher); + } + + public CMacWithIV(BlockCipher cipher, int macSizeInBits) + { + super(cipher, macSizeInBits); + } + + void validate(CipherParameters params) + { + // accept all + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/macs/GMac.java b/bcprov/src/main/java/org/bouncycastle/crypto/macs/GMac.java index 8aae1e26..b34f9ea5 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/macs/GMac.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/macs/GMac.java @@ -23,7 +23,7 @@ public class GMac implements Mac /** * Creates a GMAC based on the operation of a block cipher in GCM mode. - * <p/> + * <p> * This will produce an authentication code the length of the block size of the cipher. * * @param cipher @@ -40,7 +40,8 @@ public class GMac implements Mac * Creates a GMAC based on the operation of a 128 bit block cipher in GCM mode. * * @param macSizeBits - * the mac size to generate, in bits. Must be a multiple of 8 and >= 96 and <= 128. + * the mac size to generate, in bits. Must be a multiple of 8 and >= 32 and <= 128. + * Sizes less than 96 are not recommended, but are supported for specialized applications. * @param cipher * the cipher to be used in GCM mode to generate the MAC. */ diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/macs/Poly1305.java b/bcprov/src/main/java/org/bouncycastle/crypto/macs/Poly1305.java index 150eb617..7a346f1e 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/macs/Poly1305.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/macs/Poly1305.java @@ -7,7 +7,7 @@ import org.bouncycastle.crypto.Mac; import org.bouncycastle.crypto.generators.Poly1305KeyGenerator; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.crypto.util.Pack; +import org.bouncycastle.util.Pack; /** * Poly1305 message authentication code, designed by D. J. Bernstein. @@ -53,6 +53,14 @@ public class Poly1305 private int h0, h1, h2, h3, h4; /** + * Constructs a Poly1305 MAC, where the key passed to init() will be used directly. + */ + public Poly1305() + { + this.cipher = null; + } + + /** * Constructs a Poly1305 MAC, using a 128 bit block cipher. */ public Poly1305(final BlockCipher cipher) @@ -66,35 +74,48 @@ public class Poly1305 /** * Initialises the Poly1305 MAC. - * - * @param a {@link ParametersWithIV} containing a 128 bit nonce and a {@link KeyParameter} with - * a 256 bit key complying to the {@link Poly1305KeyGenerator Poly1305 key format}. + * + * @param params if used with a block cipher, then a {@link ParametersWithIV} containing a 128 bit + * nonce and a {@link KeyParameter} with a 256 bit key complying to the + * {@link Poly1305KeyGenerator Poly1305 key format}, otherwise just the + * {@link KeyParameter}. */ - public void init(final CipherParameters params) + public void init(CipherParameters params) throws IllegalArgumentException { - final byte[] nonce; - final byte[] key; - if ((params instanceof ParametersWithIV) && ((ParametersWithIV)params).getParameters() instanceof KeyParameter) + byte[] nonce = null; + + if (cipher != null) { - nonce = ((ParametersWithIV)params).getIV(); - key = ((KeyParameter)((ParametersWithIV)params).getParameters()).getKey(); + if (!(params instanceof ParametersWithIV)) + { + throw new IllegalArgumentException("Poly1305 requires an IV when used with a block cipher."); + } + + ParametersWithIV ivParams = (ParametersWithIV)params; + nonce = ivParams.getIV(); + params = ivParams.getParameters(); } - else + + if (!(params instanceof KeyParameter)) { - throw new IllegalArgumentException("Poly1305 requires a key and and IV."); + throw new IllegalArgumentException("Poly1305 requires a key."); } - setKey(key, nonce); + KeyParameter keyParams = (KeyParameter)params; + + setKey(keyParams.getKey(), nonce); + reset(); } private void setKey(final byte[] key, final byte[] nonce) { - if (nonce.length != BLOCK_SIZE) + if (cipher != null && (nonce == null || nonce.length != BLOCK_SIZE)) { throw new IllegalArgumentException("Poly1305 requires a 128 bit IV."); } + Poly1305KeyGenerator.checkKey(key); // Extract r portion of key @@ -115,22 +136,28 @@ public class Poly1305 s3 = r3 * 5; s4 = r4 * 5; - // Compute encrypted nonce - final byte[] cipherKey = new byte[BLOCK_SIZE]; - System.arraycopy(key, 0, cipherKey, 0, cipherKey.length); - - cipher.init(true, new KeyParameter(cipherKey)); - cipher.processBlock(nonce, 0, cipherKey, 0); + final byte[] kBytes; + if (cipher == null) + { + kBytes = key; + } + else + { + // Compute encrypted nonce + kBytes = new byte[BLOCK_SIZE]; + cipher.init(true, new KeyParameter(key, 0, BLOCK_SIZE)); + cipher.processBlock(nonce, 0, kBytes, 0); + } - k0 = Pack.littleEndianToInt(cipherKey, 0); - k1 = Pack.littleEndianToInt(cipherKey, 4); - k2 = Pack.littleEndianToInt(cipherKey, 8); - k3 = Pack.littleEndianToInt(cipherKey, 12); + k0 = Pack.littleEndianToInt(kBytes, 0); + k1 = Pack.littleEndianToInt(kBytes, 4); + k2 = Pack.littleEndianToInt(kBytes, 8); + k3 = Pack.littleEndianToInt(kBytes, 12); } public String getAlgorithmName() { - return "Poly1305-" + cipher.getAlgorithmName(); + return cipher == null ? "Poly1305" : "Poly1305-" + cipher.getAlgorithmName(); } public int getMacSize() diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/macs/SipHash.java b/bcprov/src/main/java/org/bouncycastle/crypto/macs/SipHash.java index 527c8040..d6b9dbb8 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/macs/SipHash.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/macs/SipHash.java @@ -4,13 +4,12 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.Mac; import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.crypto.util.Pack; -import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; /** * Implementation of SipHash as specified in "SipHash: a fast short-input PRF", by Jean-Philippe * Aumasson and Daniel J. Bernstein (https://131002.net/siphash/siphash.pdf). - * <p/> + * <p> * "SipHash is a family of PRFs SipHash-c-d where the integer parameters c and d are the number of * compression rounds and the number of finalization rounds. A compression round is identical to a * finalization round and this round function is called SipRound. Given a 128-bit key k and a @@ -19,14 +18,13 @@ import org.bouncycastle.util.Arrays; public class SipHash implements Mac { - protected final int c, d; protected long k0, k1; - protected long v0, v1, v2, v3, v4; + protected long v0, v1, v2, v3; - protected byte[] buf = new byte[8]; - protected int bufPos = 0; + protected long m = 0; + protected int wordPos = 0; protected int wordCount = 0; /** @@ -34,7 +32,7 @@ public class SipHash */ public SipHash() { - // use of this confuses flow analyser on earlier JDKs. + // use of 'this' confuses the flow analyser on earlier JDKs. this.c = 2; this.d = 4; } @@ -84,12 +82,13 @@ public class SipHash public void update(byte input) throws IllegalStateException { + m >>>= 8; + m |= (input & 0xffL) << 56; - buf[bufPos] = input; - if (++bufPos == buf.length) + if (++wordPos == 8) { processMessageWord(); - bufPos = 0; + wordPos = 0; } } @@ -97,14 +96,41 @@ public class SipHash throws DataLengthException, IllegalStateException { - - for (int i = 0; i < length; ++i) + int i = 0, fullWords = length & ~7; + if (wordPos == 0) { - buf[bufPos] = input[offset + i]; - if (++bufPos == buf.length) + for (; i < fullWords; i += 8) { + m = Pack.littleEndianToLong(input, offset + i); processMessageWord(); - bufPos = 0; + } + for (; i < length; ++i) + { + m >>>= 8; + m |= (input[offset + i] & 0xffL) << 56; + } + wordPos = length - fullWords; + } + else + { + int bits = wordPos << 3; + for (; i < fullWords; i += 8) + { + long n = Pack.littleEndianToLong(input, offset + i); + m = (n << bits) | (m >>> -bits); + processMessageWord(); + m = n; + } + for (; i < length; ++i) + { + m >>>= 8; + m |= (input[offset + i] & 0xffL) << 56; + + if (++wordPos == 8) + { + processMessageWord(); + wordPos = 0; + } } } } @@ -112,12 +138,10 @@ public class SipHash public long doFinal() throws DataLengthException, IllegalStateException { - - buf[7] = (byte)(((wordCount << 3) + bufPos) & 0xff); - while (bufPos < 7) - { - buf[bufPos++] = 0; - } + // NOTE: 2 distinct shifts to avoid "64-bit shift" when wordPos == 0 + m >>>= ((7 - wordPos) << 3); + m >>>= 8; + m |= (((wordCount << 3) + wordPos) & 0xffL) << 56; processMessageWord(); @@ -135,7 +159,6 @@ public class SipHash public int doFinal(byte[] out, int outOff) throws DataLengthException, IllegalStateException { - long result = doFinal(); Pack.longToLittleEndian(result, out, outOff); return 8; @@ -143,22 +166,19 @@ public class SipHash public void reset() { - v0 = k0 ^ 0x736f6d6570736575L; v1 = k1 ^ 0x646f72616e646f6dL; v2 = k0 ^ 0x6c7967656e657261L; v3 = k1 ^ 0x7465646279746573L; - Arrays.fill(buf, (byte)0); - bufPos = 0; + m = 0; + wordPos = 0; wordCount = 0; } protected void processMessageWord() { - ++wordCount; - long m = Pack.littleEndianToLong(buf, 0); v3 ^= m; applySipRounds(c); v0 ^= m; @@ -166,27 +186,31 @@ public class SipHash protected void applySipRounds(int n) { + long r0 = v0, r1 = v1, r2 = v2, r3 = v3; + for (int r = 0; r < n; ++r) { - v0 += v1; - v2 += v3; - v1 = rotateLeft(v1, 13); - v3 = rotateLeft(v3, 16); - v1 ^= v0; - v3 ^= v2; - v0 = rotateLeft(v0, 32); - v2 += v1; - v0 += v3; - v1 = rotateLeft(v1, 17); - v3 = rotateLeft(v3, 21); - v1 ^= v2; - v3 ^= v0; - v2 = rotateLeft(v2, 32); + r0 += r1; + r2 += r3; + r1 = rotateLeft(r1, 13); + r3 = rotateLeft(r3, 16); + r1 ^= r0; + r3 ^= r2; + r0 = rotateLeft(r0, 32); + r2 += r1; + r0 += r3; + r1 = rotateLeft(r1, 17); + r3 = rotateLeft(r3, 21); + r1 ^= r2; + r3 ^= r0; + r2 = rotateLeft(r2, 32); } + + v0 = r0; v1 = r1; v2 = r2; v3 = r3; } protected static long rotateLeft(long x, int n) { - return (x << n) | (x >>> (64 - n)); + return (x << n) | (x >>> -n); } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/macs/SkeinMac.java b/bcprov/src/main/java/org/bouncycastle/crypto/macs/SkeinMac.java index 60972470..7115b510 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/macs/SkeinMac.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/macs/SkeinMac.java @@ -10,13 +10,12 @@ import org.bouncycastle.crypto.params.SkeinParameters; /** * Implementation of the Skein parameterised MAC function in 256, 512 and 1024 bit block sizes, * based on the {@link ThreefishEngine Threefish} tweakable block cipher. - * <p/> + * <p> * This is the 1.3 version of Skein defined in the Skein hash function submission to the NIST SHA-3 * competition in October 2010. - * <p/> + * <p> * Skein was designed by Niels Ferguson - Stefan Lucks - Bruce Schneier - Doug Whiting - Mihir * Bellare - Tadayoshi Kohno - Jon Callas - Jesse Walker. - * <p/> * * @see SkeinEngine * @see SkeinParameters diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/macs/package.html b/bcprov/src/main/java/org/bouncycastle/crypto/macs/package.html new file mode 100644 index 00000000..0b1f86dd --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/macs/package.html @@ -0,0 +1,5 @@ +<html> +<body bgcolor="#ffffff"> +Classes for creating MACs and HMACs. +</body> +</html> |