• 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("algorithm == null");
105         }
106         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
107         return new Mac((MacSpi) sap.spi, sap.provider, algorithm);
108     }
109 
110     /**
111      * Creates a new {@code Mac} instance that provides the specified MAC
112      * algorithm from the specified provider.
113      *
114      * @param algorithm
115      *            the name of the requested MAC algorithm.
116      * @param provider
117      *            the name of the provider that is providing the algorithm.
118      * @return the new {@code Mac} instance.
119      * @throws NoSuchAlgorithmException
120      *             if the specified algorithm is not provided by the specified
121      *             provider.
122      * @throws NoSuchProviderException
123      *             if the specified provider is not available.
124      * @throws IllegalArgumentException
125      *             if the specified provider name is {@code null} or empty.
126      * @throws NullPointerException
127      *             if {@code algorithm} is {@code null} (instead of
128      *             NoSuchAlgorithmException as in 1.4 release).
129      */
getInstance(String algorithm, String provider)130     public static final Mac getInstance(String algorithm, String provider)
131             throws NoSuchAlgorithmException, NoSuchProviderException {
132         if (provider == null || provider.isEmpty()) {
133             throw new IllegalArgumentException("Provider is null or empty");
134         }
135         Provider impProvider = Security.getProvider(provider);
136         if (impProvider == null) {
137             throw new NoSuchProviderException(provider);
138         }
139         return getInstance(algorithm, impProvider);
140     }
141 
142     /**
143      * Creates a new {@code Mac} instance that provides the specified MAC
144      * algorithm from the specified provider.
145      *
146      * @param algorithm
147      *            the name of the requested MAC algorithm.
148      * @param provider
149      *            the provider that is providing the algorithm.
150      * @return the new {@code Mac} instance.
151      * @throws NoSuchAlgorithmException
152      *             if the specified algorithm is not provided by the specified
153      *             provider.
154      * @throws IllegalArgumentException
155      *             if {@code provider} is {@code null}.
156      * @throws NullPointerException
157      *             if {@code algorithm} is {@code null} (instead of
158      *             NoSuchAlgorithmException as in 1.4 release).
159      */
getInstance(String algorithm, Provider provider)160     public static final Mac getInstance(String algorithm, Provider provider)
161             throws NoSuchAlgorithmException {
162         if (provider == null) {
163             throw new IllegalArgumentException("provider == null");
164         }
165         if (algorithm == null) {
166             throw new NullPointerException("algorithm == null");
167         }
168         Object spi = ENGINE.getInstance(algorithm, provider, null);
169         return new Mac((MacSpi) spi, provider, algorithm);
170     }
171 
172     /**
173      * Returns the length of this MAC (in bytes).
174      *
175      * @return the length of this MAC (in bytes).
176      */
getMacLength()177     public final int getMacLength() {
178         return spiImpl.engineGetMacLength();
179     }
180 
181     /**
182      * Initializes this {@code Mac} instance with the specified key and
183      * algorithm parameters.
184      *
185      * @param key
186      *            the key to initialize this algorithm.
187      * @param params
188      *            the parameters for this algorithm.
189      * @throws InvalidKeyException
190      *             if the specified key cannot be used to initialize this
191      *             algorithm, or it is null.
192      * @throws InvalidAlgorithmParameterException
193      *             if the specified parameters cannot be used to initialize this
194      *             algorithm.
195      */
init(Key key, AlgorithmParameterSpec params)196     public final void init(Key key, AlgorithmParameterSpec params)
197             throws InvalidKeyException, InvalidAlgorithmParameterException {
198         if (key == null) {
199             throw new InvalidKeyException("key == null");
200         }
201         spiImpl.engineInit(key, params);
202         isInitMac = true;
203     }
204 
205     /**
206      * Initializes this {@code Mac} instance with the specified key.
207      *
208      * @param key
209      *            the key to initialize this algorithm.
210      * @throws InvalidKeyException
211      *             if initialization fails because the provided key is {@code
212      *             null}.
213      * @throws RuntimeException
214      *             if the specified key cannot be used to initialize this
215      *             algorithm.
216      */
init(Key key)217     public final void init(Key key) throws InvalidKeyException {
218         if (key == null) {
219             throw new InvalidKeyException("key == null");
220         }
221         try {
222             spiImpl.engineInit(key, null);
223             isInitMac = true;
224         } catch (InvalidAlgorithmParameterException e) {
225             throw new RuntimeException(e);
226         }
227     }
228 
229     /**
230      * Updates this {@code Mac} instance with the specified byte.
231      *
232      * @param input
233      *            the byte
234      * @throws IllegalStateException
235      *             if this MAC is not initialized.
236      */
update(byte input)237     public final void update(byte input) throws IllegalStateException {
238         if (!isInitMac) {
239             throw new IllegalStateException();
240         }
241         spiImpl.engineUpdate(input);
242     }
243 
244     /**
245      * Updates this {@code Mac} instance with the data from the specified buffer
246      * {@code input} from the specified {@code offset} and length {@code len}.
247      *
248      * @param input
249      *            the buffer.
250      * @param offset
251      *            the offset in the buffer.
252      * @param len
253      *            the length of the data in the buffer.
254      * @throws IllegalStateException
255      *             if this MAC is not initialized.
256      * @throws IllegalArgumentException
257      *             if {@code offset} and {@code len} do not specified a valid
258      *             chunk in {@code input} buffer.
259      */
update(byte[] input, int offset, int len)260     public final void update(byte[] input, int offset, int len) throws IllegalStateException {
261         if (!isInitMac) {
262             throw new IllegalStateException();
263         }
264         if (input == null) {
265             return;
266         }
267         if ((offset < 0) || (len < 0) || ((offset + len) > input.length)) {
268             throw new IllegalArgumentException("Incorrect arguments."
269                                                + " input.length=" + input.length
270                                                + " offset=" + offset + ", len=" + len);
271         }
272         spiImpl.engineUpdate(input, offset, len);
273     }
274 
275     /**
276      * Copies the buffer provided as input for further processing.
277      *
278      * @param input
279      *            the buffer.
280      * @throws IllegalStateException
281      *             if this MAC is not initialized.
282      */
update(byte[] input)283     public final void update(byte[] input) throws IllegalStateException {
284         if (!isInitMac) {
285             throw new IllegalStateException();
286         }
287         if (input != null) {
288             spiImpl.engineUpdate(input, 0, input.length);
289         }
290     }
291 
292     /**
293      * Updates this {@code Mac} instance with the data from the specified
294      * buffer, starting at {@link ByteBuffer#position()}, including the next
295      * {@link ByteBuffer#remaining()} bytes.
296      *
297      * @param input
298      *            the buffer.
299      * @throws IllegalStateException
300      *             if this MAC is not initialized.
301      */
update(ByteBuffer input)302     public final void update(ByteBuffer input) {
303         if (!isInitMac) {
304             throw new IllegalStateException();
305         }
306         if (input != null) {
307             spiImpl.engineUpdate(input);
308         } else {
309             throw new IllegalArgumentException("input == null");
310         }
311     }
312 
313     /**
314      * Computes the digest of this MAC based on the data previously specified in
315      * {@link #update} calls.
316      * <p>
317      * This {@code Mac} instance is reverted to its initial state and can be
318      * used to start the next MAC computation with the same parameters or
319      * initialized with different parameters.
320      *
321      * @return the generated digest.
322      * @throws IllegalStateException
323      *             if this MAC is not initialized.
324      */
doFinal()325     public final byte[] doFinal() throws IllegalStateException {
326         if (!isInitMac) {
327             throw new IllegalStateException();
328         }
329         return spiImpl.engineDoFinal();
330     }
331 
332     /**
333      * Computes the digest of this MAC based on the data previously specified in
334      * {@link #update} calls and stores the digest in the specified {@code
335      * output} buffer at offset {@code outOffset}.
336      * <p>
337      * This {@code Mac} instance is reverted to its initial state and can be
338      * used to start the next MAC computation with the same parameters or
339      * initialized with different parameters.
340      *
341      * @param output
342      *            the output buffer
343      * @param outOffset
344      *            the offset in the output buffer
345      * @throws ShortBufferException
346      *             if the specified output buffer is either too small for the
347      *             digest to be stored, the specified output buffer is {@code
348      *             null}, or the specified offset is negative or past the length
349      *             of the output buffer.
350      * @throws IllegalStateException
351      *             if this MAC is not initialized.
352      */
doFinal(byte[] output, int outOffset)353     public final void doFinal(byte[] output, int outOffset)
354             throws ShortBufferException, IllegalStateException {
355         if (!isInitMac) {
356             throw new IllegalStateException();
357         }
358         if (output == null) {
359             throw new ShortBufferException("output == null");
360         }
361         if ((outOffset < 0) || (outOffset >= output.length)) {
362             throw new ShortBufferException("Incorrect outOffset: " + outOffset);
363         }
364         int t = spiImpl.engineGetMacLength();
365         if (t > (output.length - outOffset)) {
366             throw new ShortBufferException("Output buffer is short. Needed " + t + " bytes.");
367         }
368         byte[] result = spiImpl.engineDoFinal();
369         System.arraycopy(result, 0, output, outOffset, result.length);
370 
371     }
372 
373     /**
374      * Computes the digest of this MAC based on the data previously specified on
375      * {@link #update} calls and on the final bytes specified by {@code input}
376      * (or based on those bytes only).
377      * <p>
378      * This {@code Mac} instance is reverted to its initial state and can be
379      * used to start the next MAC computation with the same parameters or
380      * initialized with different parameters.
381      *
382      * @param input
383      *            the final bytes.
384      * @return the generated digest.
385      * @throws IllegalStateException
386      *             if this MAC is not initialized.
387      */
doFinal(byte[] input)388     public final byte[] doFinal(byte[] input) throws IllegalStateException {
389         if (!isInitMac) {
390             throw new IllegalStateException();
391         }
392         if (input != null) {
393             spiImpl.engineUpdate(input, 0, input.length);
394         }
395         return spiImpl.engineDoFinal();
396     }
397 
398     /**
399      * Resets this {@code Mac} instance to its initial state.
400      * <p>
401      * This {@code Mac} instance is reverted to its initial state and can be
402      * used to start the next MAC computation with the same parameters or
403      * initialized with different parameters.
404      */
reset()405     public final void reset() {
406         spiImpl.engineReset();
407     }
408 
409     /**
410      * Clones this {@code Mac} instance and the underlying implementation.
411      *
412      * @return the cloned instance.
413      * @throws CloneNotSupportedException
414      *             if the underlying implementation does not support cloning.
415      */
416     @Override
clone()417     public final Object clone() throws CloneNotSupportedException {
418         MacSpi newSpiImpl = (MacSpi)spiImpl.clone();
419         Mac mac = new Mac(newSpiImpl, this.provider, this.algorithm);
420         mac.isInitMac = this.isInitMac;
421         return mac;
422     }
423 }
424