001: package org.bouncycastle.crypto.macs;
002:
003: import org.bouncycastle.crypto.BlockCipher;
004: import org.bouncycastle.crypto.CipherParameters;
005: import org.bouncycastle.crypto.Mac;
006: import org.bouncycastle.crypto.modes.CBCBlockCipher;
007:
008: public class BlockCipherMac implements Mac {
009: private byte[] mac;
010:
011: private byte[] buf;
012: private int bufOff;
013: private BlockCipher cipher;
014:
015: private int macSize;
016:
017: /**
018: * create a standard MAC based on a block cipher. This will produce an
019: * authentication code half the length of the block size of the cipher.
020: *
021: * @param cipher the cipher to be used as the basis of the MAC generation.
022: * @deprecated use CBCBlockCipherMac
023: */
024: public BlockCipherMac(BlockCipher cipher) {
025: this (cipher, (cipher.getBlockSize() * 8) / 2);
026: }
027:
028: /**
029: * create a standard MAC based on a block cipher with the size of the
030: * MAC been given in bits.
031: * <p>
032: * Note: the size of the MAC must be at least 16 bits (FIPS Publication 113),
033: * and in general should be less than the size of the block cipher as it reduces
034: * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
035: *
036: * @param cipher the cipher to be used as the basis of the MAC generation.
037: * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
038: * @deprecated use CBCBlockCipherMac
039: */
040: public BlockCipherMac(BlockCipher cipher, int macSizeInBits) {
041: if ((macSizeInBits % 8) != 0) {
042: throw new IllegalArgumentException(
043: "MAC size must be multiple of 8");
044: }
045:
046: this .cipher = new CBCBlockCipher(cipher);
047: this .macSize = macSizeInBits / 8;
048:
049: mac = new byte[cipher.getBlockSize()];
050:
051: buf = new byte[cipher.getBlockSize()];
052: bufOff = 0;
053: }
054:
055: public String getAlgorithmName() {
056: return cipher.getAlgorithmName();
057: }
058:
059: public void init(CipherParameters params) {
060: reset();
061:
062: cipher.init(true, params);
063: }
064:
065: public int getMacSize() {
066: return macSize;
067: }
068:
069: public void update(byte in) {
070: if (bufOff == buf.length) {
071: cipher.processBlock(buf, 0, mac, 0);
072: bufOff = 0;
073: }
074:
075: buf[bufOff++] = in;
076: }
077:
078: public void update(byte[] in, int inOff, int len) {
079: if (len < 0) {
080: throw new IllegalArgumentException(
081: "Can't have a negative input length!");
082: }
083:
084: int blockSize = cipher.getBlockSize();
085: int resultLen = 0;
086: int gapLen = blockSize - bufOff;
087:
088: if (len > gapLen) {
089: System.arraycopy(in, inOff, buf, bufOff, gapLen);
090:
091: resultLen += cipher.processBlock(buf, 0, mac, 0);
092:
093: bufOff = 0;
094: len -= gapLen;
095: inOff += gapLen;
096:
097: while (len > blockSize) {
098: resultLen += cipher.processBlock(in, inOff, mac, 0);
099:
100: len -= blockSize;
101: inOff += blockSize;
102: }
103: }
104:
105: System.arraycopy(in, inOff, buf, bufOff, len);
106:
107: bufOff += len;
108: }
109:
110: public int doFinal(byte[] out, int outOff) {
111: int blockSize = cipher.getBlockSize();
112:
113: //
114: // pad with zeroes
115: //
116: while (bufOff < blockSize) {
117: buf[bufOff] = 0;
118: bufOff++;
119: }
120:
121: cipher.processBlock(buf, 0, mac, 0);
122:
123: System.arraycopy(mac, 0, out, outOff, macSize);
124:
125: reset();
126:
127: return macSize;
128: }
129:
130: /**
131: * Reset the mac generator.
132: */
133: public void reset() {
134: /*
135: * clean the buffer.
136: */
137: for (int i = 0; i < buf.length; i++) {
138: buf[i] = 0;
139: }
140:
141: bufOff = 0;
142:
143: /*
144: * reset the underlying cipher.
145: */
146: cipher.reset();
147: }
148: }
|