• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 package javax.crypto;
19 
20 import java.nio.ByteBuffer;
21 import java.security.InvalidAlgorithmParameterException;
22 import java.security.InvalidKeyException;
23 import java.security.Key;
24 import java.security.NoSuchAlgorithmException;
25 import java.security.NoSuchProviderException;
26 import java.security.Provider;
27 import java.security.Security;
28 import java.security.spec.AlgorithmParameterSpec;
29 import org.apache.harmony.security.fortress.Engine;
30 
31 
32 /**
33  * This class provides the public API for <i>Message Authentication Code</i>
34  * (MAC) algorithms.
35  */
36 public class Mac implements Cloneable {
37 
38     //Used to access common engine functionality
39     private static final Engine engine = new Engine("Mac");
40 
41     // Store used provider
42     private final Provider provider;
43 
44     // Store used spi implementation
45     private final MacSpi spiImpl;
46 
47     // Store used algorithm name
48     private final String algorithm;
49 
50     // Store Mac state (initialized or not initialized)
51     private boolean isInitMac;
52 
53     /**
54      * Creates a new {@code Mac} instance.
55      *
56      * @param macSpi
57      *            the implementation delegate.
58      * @param provider
59      *            the implementation provider.
60      * @param algorithm
61      *            the name of the MAC algorithm.
62      */
Mac(MacSpi macSpi, Provider provider, String algorithm)63     protected Mac(MacSpi macSpi, Provider provider, String algorithm) {
64         this.provider = provider;
65         this.algorithm = algorithm;
66         this.spiImpl = macSpi;
67         this.isInitMac = false;
68     }
69 
70     /**
71      * Returns the name of the MAC algorithm.
72      *
73      * @return the name of the MAC algorithm.
74      */
getAlgorithm()75     public final String getAlgorithm() {
76         return algorithm;
77     }
78 
79     /**
80      * Returns the provider of this {@code Mac} instance.
81      *
82      * @return the provider of this {@code Mac} instance.
83      */
getProvider()84     public final Provider getProvider() {
85         return provider;
86     }
87 
88     /**
89      * Creates a new {@code Mac} instance that provides the specified MAC
90      * algorithm.
91      *
92      * @param algorithm
93      *            the name of the requested MAC algorithm.
94      * @return the new {@code Mac} instance.
95      * @throws NoSuchAlgorithmException
96      *             if the specified algorithm is not available by any provider.
97      * @throws NullPointerException
98      *             if {@code algorithm} is {@code null} (instead of
99      *             NoSuchAlgorithmException as in 1.4 release).
100      */
getInstance(String algorithm)101     public static final Mac getInstance(String algorithm)
102             throws NoSuchAlgorithmException {
103         if (algorithm == null) {
104             throw new NullPointerException();
105         }
106         synchronized (engine) {
107             engine.getInstance(algorithm, null);
108             return new Mac((MacSpi) engine.spi, engine.provider, algorithm);
109         }
110     }
111 
112     /**
113      * Creates a new {@code Mac} instance that provides the specified MAC
114      * algorithm from the specified provider.
115      *
116      * @param algorithm
117      *            the name of the requested MAC algorithm.
118      * @param provider
119      *            the name of the provider that is providing the algorithm.
120      * @return the new {@code Mac} instance.
121      * @throws NoSuchAlgorithmException
122      *             if the specified algorithm is not provided by the specified
123      *             provider.
124      * @throws NoSuchProviderException
125      *             if the specified provider is not available.
126      * @throws IllegalArgumentException
127      *             if the specified provider name is {@code null} or empty.
128      * @throws NullPointerException
129      *             if {@code algorithm} is {@code null} (instead of
130      *             NoSuchAlgorithmException as in 1.4 release).
131      */
getInstance(String algorithm, String provider)132     public static final Mac getInstance(String algorithm, String provider)
133             throws NoSuchAlgorithmException, NoSuchProviderException {
134         if (provider == null || provider.isEmpty()) {
135             throw new IllegalArgumentException("Provider is null or empty");
136         }
137         Provider impProvider = Security.getProvider(provider);
138         if (impProvider == null) {
139             throw new NoSuchProviderException(provider);
140         }
141         return getInstance(algorithm, impProvider);
142     }
143 
144     /**
145      * Creates a new {@code Mac} instance that provides the specified MAC
146      * algorithm from the specified provider.
147      *
148      * @param algorithm
149      *            the name of the requested MAC algorithm.
150      * @param provider
151      *            the provider that is providing the algorithm.
152      * @return the new {@code Mac} instance.
153      * @throws NoSuchAlgorithmException
154      *             if the specified algorithm is not provided by the specified
155      *             provider.
156      * @throws IllegalArgumentException
157      *             if {@code provider} is {@code null}.
158      * @throws NullPointerException
159      *             if {@code algorithm} is {@code null} (instead of
160      *             NoSuchAlgorithmException as in 1.4 release).
161      */
getInstance(String algorithm, Provider provider)162     public static final Mac getInstance(String algorithm, Provider provider)
163             throws NoSuchAlgorithmException {
164         if (provider == null) {
165             throw new IllegalArgumentException("provider == null");
166         }
167         if (algorithm == null) {
168             throw new NullPointerException();
169         }
170         synchronized (engine) {
171             engine.getInstance(algorithm, provider, null);
172             return new Mac((MacSpi) engine.spi, provider, algorithm);
173         }
174     }
175 
176     /**
177      * Returns the length of this MAC (in bytes).
178      *
179      * @return the length of this MAC (in bytes).
180      */
getMacLength()181     public final int getMacLength() {
182         return spiImpl.engineGetMacLength();
183     }
184 
185     /**
186      * Initializes this {@code Mac} instance with the specified key and
187      * algorithm parameters.
188      *
189      * @param key
190      *            the key to initialize this algorithm.
191      * @param params
192      *            the parameters for this algorithm.
193      * @throws InvalidKeyException
194      *             if the specified key cannot be used to initialize this
195      *             algorithm, or it is null.
196      * @throws InvalidAlgorithmParameterException
197      *             if the specified parameters cannot be used to initialize this
198      *             algorithm.
199      */
init(Key key, AlgorithmParameterSpec params)200     public final void init(Key key, AlgorithmParameterSpec params)
201             throws InvalidKeyException, InvalidAlgorithmParameterException {
202         if (key == null) {
203             throw new InvalidKeyException("key == null");
204         }
205         spiImpl.engineInit(key, params);
206         isInitMac = true;
207     }
208 
209     /**
210      * Initializes this {@code Mac} instance with the specified key.
211      *
212      * @param key
213      *            the key to initialize this algorithm.
214      * @throws InvalidKeyException
215      *             if initialization fails because the provided key is {@code
216      *             null}.
217      * @throws RuntimeException
218      *             if the specified key cannot be used to initialize this
219      *             algorithm.
220      */
init(Key key)221     public final void init(Key key) throws InvalidKeyException {
222         if (key == null) {
223             throw new InvalidKeyException("key == null");
224         }
225         try {
226             spiImpl.engineInit(key, null);
227             isInitMac = true;
228         } catch (InvalidAlgorithmParameterException e) {
229             throw new RuntimeException(e);
230         }
231     }
232 
233     /**
234      * Updates this {@code Mac} instance with the specified byte.
235      *
236      * @param input
237      *            the byte
238      * @throws IllegalStateException
239      *             if this MAC is not initialized.
240      */
update(byte input)241     public final void update(byte input) throws IllegalStateException {
242         if (!isInitMac) {
243             throw new IllegalStateException();
244         }
245         spiImpl.engineUpdate(input);
246     }
247 
248     /**
249      * Updates this {@code Mac} instance with the data from the specified buffer
250      * {@code input} from the specified {@code offset} and length {@code len}.
251      *
252      * @param input
253      *            the buffer.
254      * @param offset
255      *            the offset in the buffer.
256      * @param len
257      *            the length of the data in the buffer.
258      * @throws IllegalStateException
259      *             if this MAC is not initialized.
260      * @throws IllegalArgumentException
261      *             if {@code offset} and {@code len} do not specified a valid
262      *             chunk in {@code input} buffer.
263      */
update(byte[] input, int offset, int len)264     public final void update(byte[] input, int offset, int len) throws IllegalStateException {
265         if (!isInitMac) {
266             throw new IllegalStateException();
267         }
268         if (input == null) {
269             return;
270         }
271         if ((offset < 0) || (len < 0) || ((offset + len) > input.length)) {
272             throw new IllegalArgumentException("Incorrect arguments");
273         }
274         spiImpl.engineUpdate(input, offset, len);
275     }
276 
277     /**
278      * Copies the buffer provided as input for further processing.
279      *
280      * @param input
281      *            the buffer.
282      * @throws IllegalStateException
283      *             if this MAC is not initialized.
284      */
update(byte[] input)285     public final void update(byte[] input) throws IllegalStateException {
286         if (!isInitMac) {
287             throw new IllegalStateException();
288         }
289         if (input != null) {
290             spiImpl.engineUpdate(input, 0, input.length);
291         }
292     }
293 
294     /**
295      * Updates this {@code Mac} instance with the data from the specified
296      * buffer, starting at {@link ByteBuffer#position()}, including the next
297      * {@link ByteBuffer#remaining()} bytes.
298      *
299      * @param input
300      *            the buffer.
301      * @throws IllegalStateException
302      *             if this MAC is not initialized.
303      */
update(ByteBuffer input)304     public final void update(ByteBuffer input) {
305         if (!isInitMac) {
306             throw new IllegalStateException();
307         }
308         if (input != null) {
309             spiImpl.engineUpdate(input);
310         } else {
311             throw new IllegalArgumentException("input == null");
312         }
313     }
314 
315     /**
316      * Computes the digest of this MAC based on the data previously specified in
317      * {@link #update} calls.
318      * <p>
319      * This {@code Mac} instance is reverted to its initial state and can be
320      * used to start the next MAC computation with the same parameters or
321      * initialized with different parameters.
322      *
323      * @return the generated digest.
324      * @throws IllegalStateException
325      *             if this MAC is not initialized.
326      */
doFinal()327     public final byte[] doFinal() throws IllegalStateException {
328         if (!isInitMac) {
329             throw new IllegalStateException();
330         }
331         return spiImpl.engineDoFinal();
332     }
333 
334     /**
335      * Computes the digest of this MAC based on the data previously specified in
336      * {@link #update} calls and stores the digest in the specified {@code
337      * output} buffer at offset {@code outOffset}.
338      * <p>
339      * This {@code Mac} instance is reverted to its initial state and can be
340      * used to start the next MAC computation with the same parameters or
341      * initialized with different parameters.
342      *
343      * @param output
344      *            the output buffer
345      * @param outOffset
346      *            the offset in the output buffer
347      * @throws ShortBufferException
348      *             if the specified output buffer is either too small for the
349      *             digest to be stored, the specified output buffer is {@code
350      *             null}, or the specified offset is negative or past the length
351      *             of the output buffer.
352      * @throws IllegalStateException
353      *             if this MAC is not initialized.
354      */
doFinal(byte[] output, int outOffset)355     public final void doFinal(byte[] output, int outOffset)
356             throws ShortBufferException, IllegalStateException {
357         if (!isInitMac) {
358             throw new IllegalStateException();
359         }
360         if (output == null) {
361             throw new ShortBufferException("output == null");
362         }
363         if ((outOffset < 0) || (outOffset >= output.length)) {
364             throw new ShortBufferException("Incorrect outOffset: " + outOffset);
365         }
366         int t = spiImpl.engineGetMacLength();
367         if (t > (output.length - outOffset)) {
368             throw new ShortBufferException("Output buffer is short. Needed " + t + " bytes.");
369         }
370         byte[] result = spiImpl.engineDoFinal();
371         System.arraycopy(result, 0, output, outOffset, result.length);
372 
373     }
374 
375     /**
376      * Computes the digest of this MAC based on the data previously specified on
377      * {@link #update} calls and on the final bytes specified by {@code input}
378      * (or based on those bytes only).
379      * <p>
380      * This {@code Mac} instance is reverted to its initial state and can be
381      * used to start the next MAC computation with the same parameters or
382      * initialized with different parameters.
383      *
384      * @param input
385      *            the final bytes.
386      * @return the generated digest.
387      * @throws IllegalStateException
388      *             if this MAC is not initialized.
389      */
doFinal(byte[] input)390     public final byte[] doFinal(byte[] input) throws IllegalStateException {
391         if (!isInitMac) {
392             throw new IllegalStateException();
393         }
394         if (input != null) {
395             spiImpl.engineUpdate(input, 0, input.length);
396         }
397         return spiImpl.engineDoFinal();
398     }
399 
400     /**
401      * Resets this {@code Mac} instance to its initial state.
402      * <p>
403      * This {@code Mac} instance is reverted to its initial state and can be
404      * used to start the next MAC computation with the same parameters or
405      * initialized with different parameters.
406      */
reset()407     public final void reset() {
408         spiImpl.engineReset();
409     }
410 
411     /**
412      * Clones this {@code Mac} instance and the underlying implementation.
413      *
414      * @return the cloned instance.
415      * @throws CloneNotSupportedException
416      *             if the underlying implementation does not support cloning.
417      */
418     @Override
clone()419     public final Object clone() throws CloneNotSupportedException {
420         MacSpi newSpiImpl = (MacSpi)spiImpl.clone();
421         Mac mac = new Mac(newSpiImpl, this.provider, this.algorithm);
422         mac.isInitMac = this.isInitMac;
423         return mac;
424     }
425 }
426