1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47:
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53:
54:
65: public class OMAC
66: implements IMac
67: {
68: private static final Logger log = Configuration.DEBUG ?
69: Logger.getLogger(OMAC.class.getName()) : null;
70: private static final byte C1 = (byte) 0x87;
71: private static final byte C2 = 0x1b;
72:
73: private static final byte[] KEY0 =
74: Util.toBytesFromString("2b7e151628aed2a6abf7158809cf4f3c");
75:
76: private static final byte[] DIGEST0 =
77: Util.toBytesFromString("bb1d6929e95937287fa37d129b756746");
78: private static Boolean valid;
79: private final IBlockCipher cipher;
80: private final String name;
81: private IMode mode;
82: private int blockSize;
83: private int outputSize;
84: private byte[] Lu, Lu2;
85: private byte[] M;
86: private byte[] Y;
87: private boolean init;
88: private int index;
89:
90: public OMAC(IBlockCipher cipher)
91: {
92: this.cipher = cipher;
93: this.name = "OMAC-" + cipher.name();
94: }
95:
96: public Object clone()
97: {
98: return new OMAC(cipher);
99: }
100:
101: public String name()
102: {
103: return name;
104: }
105:
106: public int macSize()
107: {
108: return outputSize;
109: }
110:
111: public void init(Map attrib) throws InvalidKeyException
112: {
113: HashMap attrib2 = new HashMap();
114: attrib2.put(IBlockCipher.KEY_MATERIAL, attrib.get(MAC_KEY_MATERIAL));
115: cipher.reset();
116: cipher.init(attrib2);
117: blockSize = cipher.currentBlockSize();
118: Integer os = (Integer) attrib.get(TRUNCATED_SIZE);
119: if (os != null)
120: {
121: outputSize = os.intValue();
122: if (outputSize < 0 || outputSize > blockSize)
123: throw new IllegalArgumentException("truncated size out of range");
124: }
125: else
126: outputSize = blockSize;
127:
128: byte[] L = new byte[blockSize];
129: cipher.encryptBlock(L, 0, L, 0);
130: if (Configuration.DEBUG)
131: log.fine("L = " + Util.toString(L).toLowerCase());
132: if (Lu != null)
133: {
134: Arrays.fill(Lu, (byte) 0);
135: if (Lu.length != blockSize)
136: Lu = new byte[blockSize];
137: }
138: else
139: Lu = new byte[blockSize];
140: if (Lu2 != null)
141: {
142: Arrays.fill(Lu2, (byte) 0);
143: if (Lu2.length != blockSize)
144: Lu2 = new byte[blockSize];
145: }
146: else
147: Lu2 = new byte[blockSize];
148:
149: boolean msb = (L[0] & 0x80) != 0;
150: for (int i = 0; i < blockSize; i++)
151: {
152: Lu[i] = (byte)(L[i] << 1 & 0xFF);
153: if (i + 1 < blockSize)
154: Lu[i] |= (byte)((L[i + 1] & 0x80) >> 7);
155: }
156: if (msb)
157: {
158: if (blockSize == 16)
159: Lu[Lu.length - 1] ^= C1;
160: else if (blockSize == 8)
161: Lu[Lu.length - 1] ^= C2;
162: else
163: throw new IllegalArgumentException("unsupported cipher block size: "
164: + blockSize);
165: }
166: if (Configuration.DEBUG)
167: log.fine("Lu = " + Util.toString(Lu).toLowerCase());
168: msb = (Lu[0] & 0x80) != 0;
169: for (int i = 0; i < blockSize; i++)
170: {
171: Lu2[i] = (byte)(Lu[i] << 1 & 0xFF);
172: if (i + 1 < blockSize)
173: Lu2[i] |= (byte)((Lu[i + 1] & 0x80) >> 7);
174: }
175: if (msb)
176: {
177: if (blockSize == 16)
178: Lu2[Lu2.length - 1] ^= C1;
179: else
180: Lu2[Lu2.length - 1] ^= C2;
181: }
182: if (Configuration.DEBUG)
183: log.fine("Lu2 = " + Util.toString(Lu2).toLowerCase());
184: if (M != null)
185: {
186: Arrays.fill(M, (byte) 0);
187: if (M.length != blockSize)
188: M = new byte[blockSize];
189: }
190: else
191: M = new byte[blockSize];
192: if (Y != null)
193: {
194: Arrays.fill(Y, (byte) 0);
195: if (Y.length != blockSize)
196: Y = new byte[blockSize];
197: }
198: else
199: Y = new byte[blockSize];
200:
201: index = 0;
202: init = true;
203: }
204:
205: public void update(byte b)
206: {
207: if (! init)
208: throw new IllegalStateException("not initialized");
209: if (index == M.length)
210: {
211: process();
212: index = 0;
213: }
214: M[index++] = b;
215: }
216:
217: public void update(byte[] buf, int off, int len)
218: {
219: if (! init)
220: throw new IllegalStateException("not initialized");
221: if (off < 0 || len < 0 || off + len > buf.length)
222: throw new IndexOutOfBoundsException("size=" + buf.length + "; off=" + off
223: + "; len=" + len);
224: for (int i = 0; i < len;)
225: {
226: if (index == blockSize)
227: {
228: process();
229: index = 0;
230: }
231: int count = Math.min(blockSize - index, len - i);
232: System.arraycopy(buf, off + i, M, index, count);
233: index += count;
234: i += count;
235: }
236: }
237:
238: public byte[] digest()
239: {
240: byte[] b = new byte[outputSize];
241: digest(b, 0);
242: return b;
243: }
244:
245: public void digest(byte[] out, int off)
246: {
247: if (! init)
248: throw new IllegalStateException("not initialized");
249: if (off < 0 || off + outputSize > out.length)
250: throw new IndexOutOfBoundsException("size=" + out.length + "; off=" + off
251: + "; len=" + outputSize);
252: byte[] T = new byte[blockSize];
253: byte[] L = Lu;
254: if (index < blockSize)
255: {
256: M[index++] = (byte) 0x80;
257: while (index < blockSize)
258: M[index++] = 0;
259: L = Lu2;
260: }
261: for (int i = 0; i < blockSize; i++)
262: T[i] = (byte)(M[i] ^ Y[i] ^ L[i]);
263: cipher.encryptBlock(T, 0, T, 0);
264: System.arraycopy(T, 0, out, off, outputSize);
265: reset();
266: }
267:
268: public void reset()
269: {
270: index = 0;
271: if (Y != null)
272: Arrays.fill(Y, (byte) 0);
273: if (M != null)
274: Arrays.fill(M, (byte) 0);
275: }
276:
277: public boolean selfTest()
278: {
279: OMAC mac = new OMAC(CipherFactory.getInstance(Registry.AES_CIPHER));
280: mac.reset();
281: Map attr = new HashMap();
282: attr.put(MAC_KEY_MATERIAL, KEY0);
283: byte[] digest = null;
284: try
285: {
286: mac.init(attr);
287: digest = mac.digest();
288: }
289: catch (Exception x)
290: {
291: return false;
292: }
293: if (digest == null)
294: return false;
295: return Arrays.equals(DIGEST0, digest);
296: }
297:
298: private void process()
299: {
300: for (int i = 0; i < blockSize; i++)
301: M[i] = (byte)(M[i] ^ Y[i]);
302: cipher.encryptBlock(M, 0, Y, 0);
303: }
304: }