diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2013-07-07 07:16:28 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2013-07-07 07:16:28 +0700 |
commit | c2ee11dea6e2e044479185b81730bda06c244407 (patch) | |
tree | 7abfb37491ad9a5f15028da69f45ebb4b33047d2 /crypto/src | |
parent | Fix Platform references in tests (diff) | |
download | BouncyCastle.NET-ed25519-c2ee11dea6e2e044479185b81730bda06c244407.tar.xz |
Guard against passing IV thru CMac
Diffstat (limited to 'crypto/src')
-rw-r--r-- | crypto/src/crypto/macs/CMac.cs | 446 |
1 files changed, 226 insertions, 220 deletions
diff --git a/crypto/src/crypto/macs/CMac.cs b/crypto/src/crypto/macs/CMac.cs index c51a550c9..997145a4d 100644 --- a/crypto/src/crypto/macs/CMac.cs +++ b/crypto/src/crypto/macs/CMac.cs @@ -2,129 +2,130 @@ using System; using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Paddings; +using Org.BouncyCastle.Crypto.Parameters; namespace Org.BouncyCastle.Crypto.Macs { - /** - * CMAC - as specified at www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/omac.html - * <p> - * CMAC is analogous to OMAC1 - see also en.wikipedia.org/wiki/CMAC - * </p><p> - * CMAC is a NIST recomendation - see - * csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf - * </p><p> - * CMAC/OMAC1 is a blockcipher-based message authentication code designed and - * analyzed by Tetsu Iwata and Kaoru Kurosawa. - * </p><p> - * CMAC/OMAC1 is a simple variant of the CBC MAC (Cipher Block Chaining Message - * Authentication Code). OMAC stands for One-Key CBC MAC. - * </p><p> - * It supports 128- or 64-bits block ciphers, with any key size, and returns - * a MAC with dimension less or equal to the block size of the underlying - * cipher. - * </p> - */ - public class CMac - : IMac - { - private const byte CONSTANT_128 = (byte)0x87; - private const byte CONSTANT_64 = (byte)0x1b; - - private byte[] ZEROES; - - private byte[] mac; - - private byte[] buf; - private int bufOff; - private IBlockCipher cipher; - - private int macSize; - - private byte[] L, Lu, Lu2; - - /** - * create a standard MAC based on a CBC block cipher (64 or 128 bit block). - * This will produce an authentication code the length of the block size - * of the cipher. - * - * @param cipher the cipher to be used as the basis of the MAC generation. - */ - public CMac( - IBlockCipher cipher) - : this(cipher, cipher.GetBlockSize() * 8) - { - } - - /** - * create a standard MAC based on a block cipher with the size of the - * MAC been given in bits. - * <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 @lt;= 128. - */ - public CMac( - IBlockCipher cipher, - int macSizeInBits) - { - if ((macSizeInBits % 8) != 0) - throw new ArgumentException("MAC size must be multiple of 8"); - - if (macSizeInBits > (cipher.GetBlockSize() * 8)) - { - throw new ArgumentException( - "MAC size must be less or equal to " - + (cipher.GetBlockSize() * 8)); - } - - if (cipher.GetBlockSize() != 8 && cipher.GetBlockSize() != 16) - { - throw new ArgumentException( - "Block size must be either 64 or 128 bits"); - } - - this.cipher = new CbcBlockCipher(cipher); - this.macSize = macSizeInBits / 8; - - mac = new byte[cipher.GetBlockSize()]; - - buf = new byte[cipher.GetBlockSize()]; - - ZEROES = new byte[cipher.GetBlockSize()]; - - bufOff = 0; - } - - public string AlgorithmName - { - get { return cipher.AlgorithmName; } - } - - private static byte[] doubleLu( - byte[] inBytes) - { - int FirstBit = (inBytes[0] & 0xFF) >> 7; - byte[] ret = new byte[inBytes.Length]; - for (int i = 0; i < inBytes.Length - 1; i++) - { - ret[i] = (byte)((inBytes[i] << 1) + ((inBytes[i + 1] & 0xFF) >> 7)); - } - ret[inBytes.Length - 1] = (byte)(inBytes[inBytes.Length - 1] << 1); - if (FirstBit == 1) - { - ret[inBytes.Length - 1] ^= inBytes.Length == 16 ? CONSTANT_128 : CONSTANT_64; - } - return ret; - } - - public void Init( - ICipherParameters parameters) - { - if (parameters != null) + /** + * CMAC - as specified at www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/omac.html + * <p> + * CMAC is analogous to OMAC1 - see also en.wikipedia.org/wiki/CMAC + * </p><p> + * CMAC is a NIST recomendation - see + * csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf + * </p><p> + * CMAC/OMAC1 is a blockcipher-based message authentication code designed and + * analyzed by Tetsu Iwata and Kaoru Kurosawa. + * </p><p> + * CMAC/OMAC1 is a simple variant of the CBC MAC (Cipher Block Chaining Message + * Authentication Code). OMAC stands for One-Key CBC MAC. + * </p><p> + * It supports 128- or 64-bits block ciphers, with any key size, and returns + * a MAC with dimension less or equal to the block size of the underlying + * cipher. + * </p> + */ + public class CMac + : IMac + { + private const byte CONSTANT_128 = (byte)0x87; + private const byte CONSTANT_64 = (byte)0x1b; + + private byte[] ZEROES; + + private byte[] mac; + + private byte[] buf; + private int bufOff; + private IBlockCipher cipher; + + private int macSize; + + private byte[] L, Lu, Lu2; + + /** + * create a standard MAC based on a CBC block cipher (64 or 128 bit block). + * This will produce an authentication code the length of the block size + * of the cipher. + * + * @param cipher the cipher to be used as the basis of the MAC generation. + */ + public CMac( + IBlockCipher cipher) + : this(cipher, cipher.GetBlockSize() * 8) + { + } + + /** + * create a standard MAC based on a block cipher with the size of the + * MAC been given in bits. + * <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 @lt;= 128. + */ + public CMac( + IBlockCipher cipher, + int macSizeInBits) + { + if ((macSizeInBits % 8) != 0) + throw new ArgumentException("MAC size must be multiple of 8"); + + if (macSizeInBits > (cipher.GetBlockSize() * 8)) + { + throw new ArgumentException( + "MAC size must be less or equal to " + + (cipher.GetBlockSize() * 8)); + } + + if (cipher.GetBlockSize() != 8 && cipher.GetBlockSize() != 16) + { + throw new ArgumentException( + "Block size must be either 64 or 128 bits"); + } + + this.cipher = new CbcBlockCipher(cipher); + this.macSize = macSizeInBits / 8; + + mac = new byte[cipher.GetBlockSize()]; + + buf = new byte[cipher.GetBlockSize()]; + + ZEROES = new byte[cipher.GetBlockSize()]; + + bufOff = 0; + } + + public string AlgorithmName + { + get { return cipher.AlgorithmName; } + } + + private static byte[] doubleLu( + byte[] inBytes) + { + int FirstBit = (inBytes[0] & 0xFF) >> 7; + byte[] ret = new byte[inBytes.Length]; + for (int i = 0; i < inBytes.Length - 1; i++) + { + ret[i] = (byte)((inBytes[i] << 1) + ((inBytes[i + 1] & 0xFF) >> 7)); + } + ret[inBytes.Length - 1] = (byte)(inBytes[inBytes.Length - 1] << 1); + if (FirstBit == 1) + { + ret[inBytes.Length - 1] ^= inBytes.Length == 16 ? CONSTANT_128 : CONSTANT_64; + } + return ret; + } + + public void Init( + ICipherParameters parameters) + { + if (parameters is KeyParameter) { cipher.Init(true, parameters); @@ -134,108 +135,113 @@ namespace Org.BouncyCastle.Crypto.Macs Lu = doubleLu(L); Lu2 = doubleLu(Lu); } + else if (parameters != null) + { + // CMAC mode does not permit IV to underlying CBC mode + throw new ArgumentException("CMac mode only permits key to be set.", "parameters"); + } Reset(); - } + } public int GetMacSize() - { - return macSize; - } - - public void Update( - byte input) - { - if (bufOff == buf.Length) - { - cipher.ProcessBlock(buf, 0, mac, 0); - bufOff = 0; - } - - buf[bufOff++] = input; - } - - public void BlockUpdate( - byte[] inBytes, - int inOff, - int len) - { - if (len < 0) - throw new ArgumentException("Can't have a negative input length!"); - - int blockSize = cipher.GetBlockSize(); - int gapLen = blockSize - bufOff; - - if (len > gapLen) - { - Array.Copy(inBytes, inOff, buf, bufOff, gapLen); - - cipher.ProcessBlock(buf, 0, mac, 0); - - bufOff = 0; - len -= gapLen; - inOff += gapLen; - - while (len > blockSize) - { - cipher.ProcessBlock(inBytes, inOff, mac, 0); - - len -= blockSize; - inOff += blockSize; - } - } - - Array.Copy(inBytes, inOff, buf, bufOff, len); - - bufOff += len; - } - - public int DoFinal( - byte[] outBytes, - int outOff) - { - int blockSize = cipher.GetBlockSize(); - - byte[] lu; - if (bufOff == blockSize) - { - lu = Lu; - } - else - { - new ISO7816d4Padding().AddPadding(buf, bufOff); - lu = Lu2; - } - - for (int i = 0; i < mac.Length; i++) - { - buf[i] ^= lu[i]; - } - - cipher.ProcessBlock(buf, 0, mac, 0); - - Array.Copy(mac, 0, outBytes, outOff, macSize); - - Reset(); - - return macSize; - } - - /** - * Reset the mac generator. - */ - public void Reset() - { - /* - * clean the buffer. - */ - Array.Clear(buf, 0, buf.Length); - bufOff = 0; - - /* - * Reset the underlying cipher. - */ - cipher.Reset(); - } - } + { + return macSize; + } + + public void Update( + byte input) + { + if (bufOff == buf.Length) + { + cipher.ProcessBlock(buf, 0, mac, 0); + bufOff = 0; + } + + buf[bufOff++] = input; + } + + public void BlockUpdate( + byte[] inBytes, + int inOff, + int len) + { + if (len < 0) + throw new ArgumentException("Can't have a negative input length!"); + + int blockSize = cipher.GetBlockSize(); + int gapLen = blockSize - bufOff; + + if (len > gapLen) + { + Array.Copy(inBytes, inOff, buf, bufOff, gapLen); + + cipher.ProcessBlock(buf, 0, mac, 0); + + bufOff = 0; + len -= gapLen; + inOff += gapLen; + + while (len > blockSize) + { + cipher.ProcessBlock(inBytes, inOff, mac, 0); + + len -= blockSize; + inOff += blockSize; + } + } + + Array.Copy(inBytes, inOff, buf, bufOff, len); + + bufOff += len; + } + + public int DoFinal( + byte[] outBytes, + int outOff) + { + int blockSize = cipher.GetBlockSize(); + + byte[] lu; + if (bufOff == blockSize) + { + lu = Lu; + } + else + { + new ISO7816d4Padding().AddPadding(buf, bufOff); + lu = Lu2; + } + + for (int i = 0; i < mac.Length; i++) + { + buf[i] ^= lu[i]; + } + + cipher.ProcessBlock(buf, 0, mac, 0); + + Array.Copy(mac, 0, outBytes, outOff, macSize); + + Reset(); + + return macSize; + } + + /** + * Reset the mac generator. + */ + public void Reset() + { + /* + * clean the buffer. + */ + Array.Clear(buf, 0, buf.Length); + bufOff = 0; + + /* + * Reset the underlying cipher. + */ + cipher.Reset(); + } + } } |