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