1 /* Mac.java -- The message authentication code interface.
2 Copyright (C) 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
41 import gnu
.java
.security
.Engine
;
43 import java
.lang
.reflect
.InvocationTargetException
;
44 import java
.security
.InvalidAlgorithmParameterException
;
45 import java
.security
.InvalidKeyException
;
46 import java
.security
.Key
;
47 import java
.security
.NoSuchAlgorithmException
;
48 import java
.security
.NoSuchProviderException
;
49 import java
.security
.Provider
;
50 import java
.security
.Security
;
51 import java
.security
.spec
.AlgorithmParameterSpec
;
54 * This class implements a "message authentication code" (MAC), a method
55 * to ensure the integrity of data transmitted between two parties who
56 * share a common secret key.
58 * <p>The best way to describe a MAC is as a <i>keyed one-way hash
59 * function</i>, which looks like:
61 * <blockquote><p><code>D = MAC(K, M)</code></blockquote>
63 * <p>where <code>K</code> is the key, <code>M</code> is the message,
64 * and <code>D</code> is the resulting digest. One party will usually
65 * send the concatenation <code>M || D</code> to the other party, who
66 * will then verify <code>D</code> by computing <code>D'</code> in a
67 * similar fashion. If <code>D == D'</code>, then the message is assumed
70 * @author Casey Marshall (csm@gnu.org)
72 public class Mac
implements Cloneable
76 // ------------------------------------------------------------------------
78 private static final String SERVICE
= "Mac";
80 /** The underlying MAC implementation. */
81 private MacSpi macSpi
;
83 /** The provider we got our implementation from. */
84 private Provider provider
;
86 /** The name of the algorithm. */
87 private String algorithm
;
89 /** Whether or not we've been initialized. */
90 private boolean virgin
;
93 // ------------------------------------------------------------------------
96 * Creates a new Mac instance.
98 * @param macSpi The underlying MAC implementation.
99 * @param provider The provider of this implementation.
100 * @param algorithm The name of this MAC algorithm.
102 protected Mac(MacSpi macSpi
, Provider provider
, String algorithm
)
104 this.macSpi
= macSpi
;
105 this.provider
= provider
;
106 this.algorithm
= algorithm
;
111 // ------------------------------------------------------------------------
114 * Get an instance of the named algorithm from the first provider with
115 * an appropriate implementation.
117 * @param algorithm The name of the algorithm.
118 * @return An appropriate Mac instance, if the specified algorithm
119 * is implemented by a provider.
120 * @throws java.security.NoSuchAlgorithmException If no implementation
121 * of the named algorithm is installed.
123 public static final Mac
getInstance(String algorithm
)
124 throws NoSuchAlgorithmException
126 Provider
[] provs
= Security
.getProviders();
128 for (int i
= 0; i
< provs
.length
; i
++)
132 return getInstance(algorithm
, provs
[i
]);
134 catch (NoSuchAlgorithmException nsae
)
136 msg
= nsae
.getMessage();
139 throw new NoSuchAlgorithmException(msg
);
143 * Get an instance of the named algorithm from the named provider.
145 * @param algorithm The name of the algorithm.
146 * @param provider The name of the provider.
147 * @return An appropriate Mac instance, if the specified algorithm is
148 * implemented by the named provider.
149 * @throws java.security.NoSuchAlgorithmException If the named provider
150 * has no implementation of the algorithm.
151 * @throws java.security.NoSuchProviderException If the named provider
154 public static final Mac
getInstance(String algorithm
, String provider
)
155 throws NoSuchAlgorithmException
, NoSuchProviderException
157 Provider p
= Security
.getProvider(provider
);
160 throw new NoSuchProviderException(provider
);
162 return getInstance(algorithm
, p
);
166 * Get an instance of the named algorithm from a provider.
168 * @param algorithm The name of the algorithm.
169 * @param provider The provider.
170 * @return An appropriate Mac instance, if the specified algorithm is
171 * implemented by the provider.
172 * @throws java.security.NoSuchAlgorithmException If the provider
173 * has no implementation of the algorithm.
175 public static final Mac
getInstance(String algorithm
, Provider provider
)
176 throws NoSuchAlgorithmException
180 return new Mac((MacSpi
) Engine
.getInstance(SERVICE
, algorithm
, provider
),
181 provider
, algorithm
);
183 catch (InvocationTargetException ite
)
185 if (ite
.getCause() == null)
186 throw new NoSuchAlgorithmException(algorithm
);
187 if (ite
.getCause() instanceof NoSuchAlgorithmException
)
188 throw (NoSuchAlgorithmException
) ite
.getCause();
189 throw new NoSuchAlgorithmException(algorithm
);
191 catch (ClassCastException cce
)
193 throw new NoSuchAlgorithmException(algorithm
);
198 // ------------------------------------------------------------------------
201 * Finishes the computation of a MAC and returns the digest.
203 * <p>After this method succeeds, it may be used again as just after a
204 * call to <code>init</code>, and can compute another MAC using the
205 * same key and parameters.
207 * @return The message authentication code.
208 * @throws java.lang.IllegalStateException If this instnace has not
211 public final byte[] doFinal() throws IllegalStateException
215 throw new IllegalStateException("not initialized");
217 byte[] digest
= macSpi
.engineDoFinal();
223 * Finishes the computation of a MAC with a final byte array (or
224 * computes a MAC over those bytes only) and returns the digest.
226 * <p>After this method succeeds, it may be used again as just after a
227 * call to <code>init</code>, and can compute another MAC using the
228 * same key and parameters.
230 * @param input The bytes to add.
231 * @return The message authentication code.
232 * @throws java.lang.IllegalStateException If this instnace has not
235 public final byte[] doFinal(byte[] input
) throws IllegalStateException
238 byte[] digest
= macSpi
.engineDoFinal();
244 * Finishes the computation of a MAC and places the result into the
247 * <p>After this method succeeds, it may be used again as just after a
248 * call to <code>init</code>, and can compute another MAC using the
249 * same key and parameters.
251 * @param output The destination for the result.
252 * @param outOffset The index in the output array to start.
253 * @return The message authentication code.
254 * @throws java.lang.IllegalStateException If this instnace has not
256 * @throws javax.crypto.ShortBufferException If <code>output</code> is
257 * not large enough to hold the result.
259 public final void doFinal(byte[] output
, int outOffset
)
260 throws IllegalStateException
, ShortBufferException
264 throw new IllegalStateException("not initialized");
266 if (output
.length
- outOffset
< getMacLength())
268 throw new ShortBufferException();
270 byte[] mac
= macSpi
.engineDoFinal();
271 System
.arraycopy(mac
, 0, output
, outOffset
, getMacLength());
276 * Returns the name of this MAC algorithm.
278 * @return The MAC name.
280 public final String
getAlgorithm()
286 * Get the size of the MAC. This is the size of the array returned by
287 * {@link #doFinal()} and {@link #doFinal(byte[])}, and the minimum
288 * number of bytes that must be available in the byte array passed to
289 * {@link #doFinal(byte[],int)}.
291 * @return The MAC length.
293 public final int getMacLength()
295 return macSpi
.engineGetMacLength();
299 * Get the provider of the underlying implementation.
301 * @return The provider.
303 public final Provider
getProvider()
309 * Initialize this MAC with a key and no parameters.
311 * @param key The key to initialize this instance with.
312 * @throws java.security.InvalidKeyException If the key is
315 public final void init(Key key
) throws InvalidKeyException
321 catch (InvalidAlgorithmParameterException iape
)
323 throw new IllegalArgumentException(algorithm
+ " needs parameters");
328 * Initialize this MAC with a key and parameters.
330 * @param key The key to initialize this instance with.
331 * @param params The algorithm-specific parameters.
332 * @throws java.security.InvalidAlgorithmParameterException If the
333 * algorithm parameters are unacceptable.
334 * @throws java.security.InvalidKeyException If the key is
337 public final void init(Key key
, AlgorithmParameterSpec params
)
338 throws InvalidAlgorithmParameterException
, InvalidKeyException
340 macSpi
.engineInit(key
, params
);
341 virgin
= false; // w00t!
345 * Reset this instance. A call to this method returns this instance
346 * back to the state it was in just after it was initialized.
348 public final void reset()
350 macSpi
.engineReset();
354 * Update the computation with a single byte.
356 * @param input The next byte.
357 * @throws java.lang.IllegalStateException If this instance has not
360 public final void update(byte input
) throws IllegalStateException
364 throw new IllegalStateException("not initialized");
366 macSpi
.engineUpdate(input
);
370 * Update the computation with a byte array.
372 * @param input The next bytes.
373 * @throws java.lang.IllegalStateException If this instance has not
376 public final void update(byte[] input
) throws IllegalStateException
378 update(input
, 0, input
.length
);
382 * Update the computation with a portion of a byte array.
384 * @param input The next bytes.
385 * @param offset The index in <code>input</code> to start.
386 * @param length The number of bytes to update.
387 * @throws java.lang.IllegalStateException If this instance has not
390 public final void update(byte[] input
, int offset
, int length
)
391 throws IllegalStateException
395 throw new IllegalStateException("not initialized");
397 macSpi
.engineUpdate(input
, offset
, length
);
401 * Clone this instance, if the underlying implementation supports it.
403 * @return A clone of this instance.
404 * @throws java.lang.CloneNotSupportedException If the underlying
405 * implementation is not cloneable.
407 public final Object
clone() throws CloneNotSupportedException
409 Mac result
= new Mac((MacSpi
) macSpi
.clone(), provider
, algorithm
);
410 result
.virgin
= virgin
;