1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45:
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52:
53:
71: public class EAX
72: implements IAuthenticatedMode
73: {
74:
75: private int tagSize;
76:
77: private IMac nonceOmac;
78:
79: private IMac headerOmac;
80:
81: private IMac msgOmac;
82:
83: private IMode ctr;
84:
85: private int state;
86:
87: private boolean init;
88:
89: private int cipherBlockSize;
90:
91: private IBlockCipher cipher;
92:
93: private byte[] t_n;
94: private static boolean valid = false;
95:
96: public EAX(IBlockCipher cipher, int cipherBlockSize)
97: {
98: this.cipher = cipher;
99: this.cipherBlockSize = cipherBlockSize;
100: String name = cipher.name();
101: int i = name.indexOf('-');
102: if (i >= 0)
103: name = name.substring(0, i);
104: String omacname = Registry.OMAC_PREFIX + name;
105: nonceOmac = MacFactory.getInstance(omacname);
106: headerOmac = MacFactory.getInstance(omacname);
107: msgOmac = MacFactory.getInstance(omacname);
108: ctr = ModeFactory.getInstance(Registry.CTR_MODE, cipher, cipherBlockSize);
109: t_n = new byte[cipherBlockSize];
110: init = false;
111: }
112:
113: public Object clone()
114: {
115: return new EAX((IBlockCipher) cipher.clone(), cipherBlockSize);
116: }
117:
118: public String name()
119: {
120: return Registry.EAX_MODE + "(" + cipher.name() + ")";
121: }
122:
123: public int defaultBlockSize()
124: {
125: return ctr.defaultBlockSize();
126: }
127:
128: public int defaultKeySize()
129: {
130: return ctr.defaultKeySize();
131: }
132:
133: public Iterator blockSizes()
134: {
135: return ctr.blockSizes();
136: }
137:
138: public Iterator keySizes()
139: {
140: return ctr.keySizes();
141: }
142:
143: public void init(Map attrib) throws InvalidKeyException
144: {
145: byte[] nonce = (byte[]) attrib.get(IV);
146: if (nonce == null)
147: throw new IllegalArgumentException("no nonce provided");
148: byte[] key = (byte[]) attrib.get(KEY_MATERIAL);
149: if (key == null)
150: throw new IllegalArgumentException("no key provided");
151:
152: Arrays.fill(t_n, (byte) 0);
153: nonceOmac.reset();
154: nonceOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key));
155: nonceOmac.update(t_n, 0, t_n.length);
156: nonceOmac.update(nonce, 0, nonce.length);
157: byte[] N = nonceOmac.digest();
158: nonceOmac.reset();
159: nonceOmac.update(t_n, 0, t_n.length);
160: nonceOmac.update(nonce, 0, nonce.length);
161: t_n[t_n.length - 1] = 1;
162: headerOmac.reset();
163: headerOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key));
164: headerOmac.update(t_n, 0, t_n.length);
165: t_n[t_n.length - 1] = 2;
166: msgOmac.reset();
167: msgOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key));
168: msgOmac.update(t_n, 0, t_n.length);
169: Integer modeSize = (Integer) attrib.get(MODE_BLOCK_SIZE);
170: if (modeSize == null)
171: modeSize = Integer.valueOf(cipherBlockSize);
172: HashMap ctrAttr = new HashMap();
173: ctrAttr.put(KEY_MATERIAL, key);
174: ctrAttr.put(IV, N);
175: ctrAttr.put(STATE, Integer.valueOf(ENCRYPTION));
176: ctrAttr.put(MODE_BLOCK_SIZE, modeSize);
177: ctr.reset();
178: ctr.init(ctrAttr);
179: Integer st = (Integer) attrib.get(STATE);
180: if (st != null)
181: {
182: state = st.intValue();
183: if (state != ENCRYPTION && state != DECRYPTION)
184: throw new IllegalArgumentException("invalid state");
185: }
186: else
187: state = ENCRYPTION;
188:
189: Integer ts = (Integer) attrib.get(TRUNCATED_SIZE);
190: if (ts != null)
191: tagSize = ts.intValue();
192: else
193: tagSize = cipherBlockSize;
194: if (tagSize < 0 || tagSize > cipherBlockSize)
195: throw new IllegalArgumentException("tag size out of range");
196: init = true;
197: }
198:
199: public int currentBlockSize()
200: {
201: return ctr.currentBlockSize();
202: }
203:
204: public void encryptBlock(byte[] in, int inOff, byte[] out, int outOff)
205: {
206: if (! init)
207: throw new IllegalStateException("not initialized");
208: if (state != ENCRYPTION)
209: throw new IllegalStateException("not encrypting");
210: ctr.update(in, inOff, out, outOff);
211: msgOmac.update(out, outOff, ctr.currentBlockSize());
212: }
213:
214: public void decryptBlock(byte[] in, int inOff, byte[] out, int outOff)
215: {
216: if (! init)
217: throw new IllegalStateException("not initialized");
218: if (state != DECRYPTION)
219: throw new IllegalStateException("not decrypting");
220: msgOmac.update(in, inOff, ctr.currentBlockSize());
221: ctr.update(in, inOff, out, outOff);
222: }
223:
224: public void update(byte[] in, int inOff, byte[] out, int outOff)
225: {
226: switch (state)
227: {
228: case ENCRYPTION:
229: encryptBlock(in, inOff, out, outOff);
230: break;
231: case DECRYPTION:
232: decryptBlock(in, inOff, out, outOff);
233: break;
234: default:
235: throw new IllegalStateException("impossible state " + state);
236: }
237: }
238:
239: public void reset()
240: {
241: nonceOmac.reset();
242: headerOmac.reset();
243: msgOmac.reset();
244: ctr.reset();
245: }
246:
247: public boolean selfTest()
248: {
249: return true;
250: }
251:
252: public int macSize()
253: {
254: return tagSize;
255: }
256:
257: public byte[] digest()
258: {
259: byte[] tag = new byte[tagSize];
260: digest(tag, 0);
261: return tag;
262: }
263:
264: public void digest(byte[] out, int outOffset)
265: {
266: if (outOffset < 0 || outOffset + tagSize > out.length)
267: throw new IndexOutOfBoundsException();
268: byte[] N = nonceOmac.digest();
269: byte[] H = headerOmac.digest();
270: byte[] M = msgOmac.digest();
271: for (int i = 0; i < tagSize; i++)
272: out[outOffset + i] = (byte)(N[i] ^ H[i] ^ M[i]);
273: reset();
274: }
275:
276: public void update(byte b)
277: {
278: if (! init)
279: throw new IllegalStateException("not initialized");
280: headerOmac.update(b);
281: }
282:
283: public void update(byte[] buf, int off, int len)
284: {
285: if (! init)
286: throw new IllegalStateException("not initialized");
287: headerOmac.update(buf, off, len);
288: }
289: }