1 package org.bouncycastle.crypto.macs; 2 3 import org.bouncycastle.crypto.BlockCipher; 4 import org.bouncycastle.crypto.CipherParameters; 5 import org.bouncycastle.crypto.Mac; 6 import org.bouncycastle.crypto.modes.CBCBlockCipher; 7 8 public class BlockCipherMac 9 implements Mac 10 { 11 private byte[] mac; 12 13 private byte[] buf; 14 private int bufOff; 15 private BlockCipher cipher; 16 17 private int macSize; 18 19 /** 20 * create a standard MAC based on a block cipher. This will produce an 21 * authentication code half the length of the block size of the cipher. 22 * 23 * @param cipher the cipher to be used as the basis of the MAC generation. 24 * @deprecated use CBCBlockCipherMac 25 */ BlockCipherMac( BlockCipher cipher)26 public BlockCipherMac( 27 BlockCipher cipher) 28 { 29 this(cipher, (cipher.getBlockSize() * 8) / 2); 30 } 31 32 /** 33 * create a standard MAC based on a block cipher with the size of the 34 * MAC been given in bits. 35 * <p> 36 * Note: the size of the MAC must be at least 16 bits (FIPS Publication 113), 37 * and in general should be less than the size of the block cipher as it reduces 38 * the chance of an exhaustive attack (see Handbook of Applied Cryptography). 39 * 40 * @param cipher the cipher to be used as the basis of the MAC generation. 41 * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8. 42 * @deprecated use CBCBlockCipherMac 43 */ BlockCipherMac( BlockCipher cipher, int macSizeInBits)44 public BlockCipherMac( 45 BlockCipher cipher, 46 int macSizeInBits) 47 { 48 if ((macSizeInBits % 8) != 0) 49 { 50 throw new IllegalArgumentException("MAC size must be multiple of 8"); 51 } 52 53 this.cipher = new CBCBlockCipher(cipher); 54 this.macSize = macSizeInBits / 8; 55 56 mac = new byte[cipher.getBlockSize()]; 57 58 buf = new byte[cipher.getBlockSize()]; 59 bufOff = 0; 60 } 61 getAlgorithmName()62 public String getAlgorithmName() 63 { 64 return cipher.getAlgorithmName(); 65 } 66 init( CipherParameters params)67 public void init( 68 CipherParameters params) 69 { 70 reset(); 71 72 cipher.init(true, params); 73 } 74 getMacSize()75 public int getMacSize() 76 { 77 return macSize; 78 } 79 update( byte in)80 public void update( 81 byte in) 82 { 83 if (bufOff == buf.length) 84 { 85 cipher.processBlock(buf, 0, mac, 0); 86 bufOff = 0; 87 } 88 89 buf[bufOff++] = in; 90 } 91 update( byte[] in, int inOff, int len)92 public void update( 93 byte[] in, 94 int inOff, 95 int len) 96 { 97 if (len < 0) 98 { 99 throw new IllegalArgumentException("Can't have a negative input length!"); 100 } 101 102 int blockSize = cipher.getBlockSize(); 103 int resultLen = 0; 104 int gapLen = blockSize - bufOff; 105 106 if (len > gapLen) 107 { 108 System.arraycopy(in, inOff, buf, bufOff, gapLen); 109 110 resultLen += cipher.processBlock(buf, 0, mac, 0); 111 112 bufOff = 0; 113 len -= gapLen; 114 inOff += gapLen; 115 116 while (len > blockSize) 117 { 118 resultLen += cipher.processBlock(in, inOff, mac, 0); 119 120 len -= blockSize; 121 inOff += blockSize; 122 } 123 } 124 125 System.arraycopy(in, inOff, buf, bufOff, len); 126 127 bufOff += len; 128 } 129 doFinal( byte[] out, int outOff)130 public int doFinal( 131 byte[] out, 132 int outOff) 133 { 134 int blockSize = cipher.getBlockSize(); 135 136 // 137 // pad with zeroes 138 // 139 while (bufOff < blockSize) 140 { 141 buf[bufOff] = 0; 142 bufOff++; 143 } 144 145 cipher.processBlock(buf, 0, mac, 0); 146 147 System.arraycopy(mac, 0, out, outOff, macSize); 148 149 reset(); 150 151 return macSize; 152 } 153 154 /** 155 * Reset the mac generator. 156 */ reset()157 public void reset() 158 { 159 /* 160 * clean the buffer. 161 */ 162 for (int i = 0; i < buf.length; i++) 163 { 164 buf[i] = 0; 165 } 166 167 bufOff = 0; 168 169 /* 170 * reset the underlying cipher. 171 */ 172 cipher.reset(); 173 } 174 } 175