History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/crypto/Mac.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/crypto/Mac.java+657−0
@@ -0,0 +1,657 @@
1/*
2 * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.crypto;
27
28import java.util.*;
29
30import java.security.*;
31import java.security.Provider.Service;
32import java.security.spec.AlgorithmParameterSpec;
33
34import java.nio.ByteBuffer;
35
36import sun.security.util.Debug;
37import sun.security.jca.*;
38import sun.security.jca.GetInstance.Instance;
39
40/**
41 * This class provides the functionality of a "Message Authentication Code"
42 * (MAC) algorithm.
43 *
44 * <p> A MAC provides a way to check
45 * the integrity of information transmitted over or stored in an unreliable
46 * medium, based on a secret key. Typically, message
47 * authentication codes are used between two parties that share a secret
48 * key in order to validate information transmitted between these
49 * parties.
50 *
51 * <p> A MAC mechanism that is based on cryptographic hash functions is
52 * referred to as HMAC. HMAC can be used with any cryptographic hash function,
53 * e.g., MD5 or SHA-1, in combination with a secret shared key. HMAC is
54 * specified in RFC 2104.
55 *
56 * <p> Every implementation of the Java platform is required to support
57 * the following standard <code>Mac</code> algorithms:
58 * <ul>
59 * <li><tt>HmacMD5</tt></li>
60 * <li><tt>HmacSHA1</tt></li>
61 * <li><tt>HmacSHA256</tt></li>
62 * </ul>
63 * These algorithms are described in the
64 * <a href="{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
65 * Mac section</a> of the
66 * Java Cryptography Architecture Standard Algorithm Name Documentation.
67 * Consult the release documentation for your implementation to see if any
68 * other algorithms are supported.
69 *
70 * @author Jan Luehe
71 *
72 * @since 1.4
73 */
74
75public class Mac implements Cloneable {
76
77 private static final Debug debug =
78 Debug.getInstance("jca", "Mac");
79
80 // The provider
81 private Provider provider;
82
83 // The provider implementation (delegate)
84 private MacSpi spi;
85
86 // The name of the MAC algorithm.
87 private final String algorithm;
88
89 // Has this object been initialized?
90 private boolean initialized = false;
91
92 // next service to try in provider selection
93 // null once provider is selected
94 private Service firstService;
95
96 // remaining services to try in provider selection
97 // null once provider is selected
98 private Iterator serviceIterator;
99
100 private final Object lock;
101
102 /**
103 * Creates a MAC object.
104 *
105 * @param macSpi the delegate
106 * @param provider the provider
107 * @param algorithm the algorithm
108 */
109 protected Mac(MacSpi macSpi, Provider provider, String algorithm) {
110 this.spi = macSpi;
111 this.provider = provider;
112 this.algorithm = algorithm;
113 serviceIterator = null;
114 lock = null;
115 }
116
117 private Mac(Service s, Iterator t, String algorithm) {
118 firstService = s;
119 serviceIterator = t;
120 this.algorithm = algorithm;
121 lock = new Object();
122 }
123
124 /**
125 * Returns the algorithm name of this <code>Mac</code> object.
126 *
127 * <p>This is the same name that was specified in one of the
128 * <code>getInstance</code> calls that created this
129 * <code>Mac</code> object.
130 *
131 * @return the algorithm name of this <code>Mac</code> object.
132 */
133 public final String getAlgorithm() {
134 return this.algorithm;
135 }
136
137 /**
138 * Returns a <code>Mac</code> object that implements the
139 * specified MAC algorithm.
140 *
141 * <p> This method traverses the list of registered security Providers,
142 * starting with the most preferred Provider.
143 * A new Mac object encapsulating the
144 * MacSpi implementation from the first
145 * Provider that supports the specified algorithm is returned.
146 *
147 * <p> Note that the list of registered providers may be retrieved via
148 * the {@link Security#getProviders() Security.getProviders()} method.
149 *
150 * @param algorithm the standard name of the requested MAC algorithm.
151 * See the Mac section in the <a href=
152 * "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
153 * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
154 * for information about standard algorithm names.
155 *
156 * @return the new <code>Mac</code> object.
157 *
158 * @exception NoSuchAlgorithmException if no Provider supports a
159 * MacSpi implementation for the
160 * specified algorithm.
161 *
162 * @see java.security.Provider
163 */
164 public static final Mac getInstance(String algorithm)
165 throws NoSuchAlgorithmException {
166 List services = GetInstance.getServices("Mac", algorithm);
167 // make sure there is at least one service from a signed provider
168 Iterator t = services.iterator();
169 while (t.hasNext()) {
170 Service s = (Service)t.next();
171 if (JceSecurity.canUseProvider(s.getProvider()) == false) {
172 continue;
173 }
174 return new Mac(s, t, algorithm);
175 }
176 throw new NoSuchAlgorithmException
177 ("Algorithm " + algorithm + " not available");
178 }
179
180 /**
181 * Returns a <code>Mac</code> object that implements the
182 * specified MAC algorithm.
183 *
184 * <p> A new Mac object encapsulating the
185 * MacSpi implementation from the specified provider
186 * is returned. The specified provider must be registered
187 * in the security provider list.
188 *
189 * <p> Note that the list of registered providers may be retrieved via
190 * the {@link Security#getProviders() Security.getProviders()} method.
191 *
192 * @param algorithm the standard name of the requested MAC algorithm.
193 * See the Mac section in the <a href=
194 * "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
195 * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
196 * for information about standard algorithm names.
197 *
198 * @param provider the name of the provider.
199 *
200 * @return the new <code>Mac</code> object.
201 *
202 * @exception NoSuchAlgorithmException if a MacSpi
203 * implementation for the specified algorithm is not
204 * available from the specified provider.
205 *
206 * @exception NoSuchProviderException if the specified provider is not
207 * registered in the security provider list.
208 *
209 * @exception IllegalArgumentException if the <code>provider</code>
210 * is null or empty.
211 *
212 * @see java.security.Provider
213 */
214 public static final Mac getInstance(String algorithm, String provider)
215 throws NoSuchAlgorithmException, NoSuchProviderException {
216 Instance instance = JceSecurity.getInstance
217 ("Mac", MacSpi.class, algorithm, provider);
218 return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
219 }
220
221 /**
222 * Returns a <code>Mac</code> object that implements the
223 * specified MAC algorithm.
224 *
225 * <p> A new Mac object encapsulating the
226 * MacSpi implementation from the specified Provider
227 * object is returned. Note that the specified Provider object
228 * does not have to be registered in the provider list.
229 *
230 * @param algorithm the standard name of the requested MAC algorithm.
231 * See the Mac section in the <a href=
232 * "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
233 * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
234 * for information about standard algorithm names.
235 *
236 * @param provider the provider.
237 *
238 * @return the new <code>Mac</code> object.
239 *
240 * @exception NoSuchAlgorithmException if a MacSpi
241 * implementation for the specified algorithm is not available
242 * from the specified Provider object.
243 *
244 * @exception IllegalArgumentException if the <code>provider</code>
245 * is null.
246 *
247 * @see java.security.Provider
248 */
249 public static final Mac getInstance(String algorithm, Provider provider)
250 throws NoSuchAlgorithmException {
251 Instance instance = JceSecurity.getInstance
252 ("Mac", MacSpi.class, algorithm, provider);
253 return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
254 }
255
256 // max number of debug warnings to print from chooseFirstProvider()
257 private static int warnCount = 10;
258
259 /**
260 * Choose the Spi from the first provider available. Used if
261 * delayed provider selection is not possible because init()
262 * is not the first method called.
263 */
264 void chooseFirstProvider() {
265 if ((spi != null) || (serviceIterator == null)) {
266 return;
267 }
268 synchronized (lock) {
269 if (spi != null) {
270 return;
271 }
272 if (debug != null) {
273 int w = --warnCount;
274 if (w >= 0) {
275 debug.println("Mac.init() not first method "
276 + "called, disabling delayed provider selection");
277 if (w == 0) {
278 debug.println("Further warnings of this type will "
279 + "be suppressed");
280 }
281 new Exception("Call trace").printStackTrace();
282 }
283 }
284 Exception lastException = null;
285 while ((firstService != null) || serviceIterator.hasNext()) {
286 Service s;
287 if (firstService != null) {
288 s = firstService;
289 firstService = null;
290 } else {
291 s = (Service)serviceIterator.next();
292 }
293 if (JceSecurity.canUseProvider(s.getProvider()) == false) {
294 continue;
295 }
296 try {
297 Object obj = s.newInstance(null);
298 if (obj instanceof MacSpi == false) {
299 continue;
300 }
301 spi = (MacSpi)obj;
302 provider = s.getProvider();
303 // not needed any more
304 firstService = null;
305 serviceIterator = null;
306 return;
307 } catch (NoSuchAlgorithmException e) {
308 lastException = e;
309 }
310 }
311 ProviderException e = new ProviderException
312 ("Could not construct MacSpi instance");
313 if (lastException != null) {
314 e.initCause(lastException);
315 }
316 throw e;
317 }
318 }
319
320 private void chooseProvider(Key key, AlgorithmParameterSpec params)
321 throws InvalidKeyException, InvalidAlgorithmParameterException {
322 synchronized (lock) {
323 if (spi != null) {
324 spi.engineInit(key, params);
325 return;
326 }
327 Exception lastException = null;
328 while ((firstService != null) || serviceIterator.hasNext()) {
329 Service s;
330 if (firstService != null) {
331 s = firstService;
332 firstService = null;
333 } else {
334 s = (Service)serviceIterator.next();
335 }
336 // if provider says it does not support this key, ignore it
337 if (s.supportsParameter(key) == false) {
338 continue;
339 }
340 if (JceSecurity.canUseProvider(s.getProvider()) == false) {
341 continue;
342 }
343 try {
344 MacSpi spi = (MacSpi)s.newInstance(null);
345 spi.engineInit(key, params);
346 provider = s.getProvider();
347 this.spi = spi;
348 firstService = null;
349 serviceIterator = null;
350 return;
351 } catch (Exception e) {
352 // NoSuchAlgorithmException from newInstance()
353 // InvalidKeyException from init()
354 // RuntimeException (ProviderException) from init()
355 if (lastException == null) {
356 lastException = e;
357 }
358 }
359 }
360 // no working provider found, fail
361 if (lastException instanceof InvalidKeyException) {
362 throw (InvalidKeyException)lastException;
363 }
364 if (lastException instanceof InvalidAlgorithmParameterException) {
365 throw (InvalidAlgorithmParameterException)lastException;
366 }
367 if (lastException instanceof RuntimeException) {
368 throw (RuntimeException)lastException;
369 }
370 String kName = (key != null) ? key.getClass().getName() : "(null)";
371 throw new InvalidKeyException
372 ("No installed provider supports this key: "
373 + kName, lastException);
374 }
375 }
376
377 /**
378 * Returns the provider of this <code>Mac</code> object.
379 *
380 * @return the provider of this <code>Mac</code> object.
381 */
382 public final Provider getProvider() {
383 chooseFirstProvider();
384 return this.provider;
385 }
386
387 /**
388 * Returns the length of the MAC in bytes.
389 *
390 * @return the MAC length in bytes.
391 */
392 public final int getMacLength() {
393 chooseFirstProvider();
394 return spi.engineGetMacLength();
395 }
396
397 /**
398 * Initializes this <code>Mac</code> object with the given key.
399 *
400 * @param key the key.
401 *
402 * @exception InvalidKeyException if the given key is inappropriate for
403 * initializing this MAC.
404 */
405 public final void init(Key key) throws InvalidKeyException {
406 try {
407 if (spi != null) {
408 spi.engineInit(key, null);
409 } else {
410 chooseProvider(key, null);
411 }
412 } catch (InvalidAlgorithmParameterException e) {
413 throw new InvalidKeyException("init() failed", e);
414 }
415 initialized = true;
416 }
417
418 /**
419 * Initializes this <code>Mac</code> object with the given key and
420 * algorithm parameters.
421 *
422 * @param key the key.
423 * @param params the algorithm parameters.
424 *
425 * @exception InvalidKeyException if the given key is inappropriate for
426 * initializing this MAC.
427 * @exception InvalidAlgorithmParameterException if the given algorithm
428 * parameters are inappropriate for this MAC.
429 */
430 public final void init(Key key, AlgorithmParameterSpec params)
431 throws InvalidKeyException, InvalidAlgorithmParameterException {
432 if (spi != null) {
433 spi.engineInit(key, params);
434 } else {
435 chooseProvider(key, params);
436 }
437 initialized = true;
438 }
439
440 /**
441 * Processes the given byte.
442 *
443 * @param input the input byte to be processed.
444 *
445 * @exception IllegalStateException if this <code>Mac</code> has not been
446 * initialized.
447 */
448 public final void update(byte input) throws IllegalStateException {
449 chooseFirstProvider();
450 if (initialized == false) {
451 throw new IllegalStateException("MAC not initialized");
452 }
453 spi.engineUpdate(input);
454 }
455
456 /**
457 * Processes the given array of bytes.
458 *
459 * @param input the array of bytes to be processed.
460 *
461 * @exception IllegalStateException if this <code>Mac</code> has not been
462 * initialized.
463 */
464 public final void update(byte[] input) throws IllegalStateException {
465 chooseFirstProvider();
466 if (initialized == false) {
467 throw new IllegalStateException("MAC not initialized");
468 }
469 if (input != null) {
470 spi.engineUpdate(input, 0, input.length);
471 }
472 }
473
474 /**
475 * Processes the first <code>len</code> bytes in <code>input</code>,
476 * starting at <code>offset</code> inclusive.
477 *
478 * @param input the input buffer.
479 * @param offset the offset in <code>input</code> where the input starts.
480 * @param len the number of bytes to process.
481 *
482 * @exception IllegalStateException if this <code>Mac</code> has not been
483 * initialized.
484 */
485 public final void update(byte[] input, int offset, int len)
486 throws IllegalStateException {
487 chooseFirstProvider();
488 if (initialized == false) {
489 throw new IllegalStateException("MAC not initialized");
490 }
491
492 if (input != null) {
493 if ((offset < 0) || (len > (input.length - offset)) || (len < 0))
494 throw new IllegalArgumentException("Bad arguments");
495 spi.engineUpdate(input, offset, len);
496 }
497 }
498
499 /**
500 * Processes <code>input.remaining()</code> bytes in the ByteBuffer
501 * <code>input</code>, starting at <code>input.position()</code>.
502 * Upon return, the buffer's position will be equal to its limit;
503 * its limit will not have changed.
504 *
505 * @param input the ByteBuffer
506 *
507 * @exception IllegalStateException if this <code>Mac</code> has not been
508 * initialized.
509 * @since 1.5
510 */
511 public final void update(ByteBuffer input) {
512 chooseFirstProvider();
513 if (initialized == false) {
514 throw new IllegalStateException("MAC not initialized");
515 }
516 if (input == null) {
517 throw new IllegalArgumentException("Buffer must not be null");
518 }
519 spi.engineUpdate(input);
520 }
521
522 /**
523 * Finishes the MAC operation.
524 *
525 * <p>A call to this method resets this <code>Mac</code> object to the
526 * state it was in when previously initialized via a call to
527 * <code>init(Key)</code> or
528 * <code>init(Key, AlgorithmParameterSpec)</code>.
529 * That is, the object is reset and available to generate another MAC from
530 * the same key, if desired, via new calls to <code>update</code> and
531 * <code>doFinal</code>.
532 * (In order to reuse this <code>Mac</code> object with a different key,
533 * it must be reinitialized via a call to <code>init(Key)</code> or
534 * <code>init(Key, AlgorithmParameterSpec)</code>.
535 *
536 * @return the MAC result.
537 *
538 * @exception IllegalStateException if this <code>Mac</code> has not been
539 * initialized.
540 */
541 public final byte[] doFinal() throws IllegalStateException {
542 chooseFirstProvider();
543 if (initialized == false) {
544 throw new IllegalStateException("MAC not initialized");
545 }
546 byte[] mac = spi.engineDoFinal();
547 spi.engineReset();
548 return mac;
549 }
550
551 /**
552 * Finishes the MAC operation.
553 *
554 * <p>A call to this method resets this <code>Mac</code> object to the
555 * state it was in when previously initialized via a call to
556 * <code>init(Key)</code> or
557 * <code>init(Key, AlgorithmParameterSpec)</code>.
558 * That is, the object is reset and available to generate another MAC from
559 * the same key, if desired, via new calls to <code>update</code> and
560 * <code>doFinal</code>.
561 * (In order to reuse this <code>Mac</code> object with a different key,
562 * it must be reinitialized via a call to <code>init(Key)</code> or
563 * <code>init(Key, AlgorithmParameterSpec)</code>.
564 *
565 * <p>The MAC result is stored in <code>output</code>, starting at
566 * <code>outOffset</code> inclusive.
567 *
568 * @param output the buffer where the MAC result is stored
569 * @param outOffset the offset in <code>output</code> where the MAC is
570 * stored
571 *
572 * @exception ShortBufferException if the given output buffer is too small
573 * to hold the result
574 * @exception IllegalStateException if this <code>Mac</code> has not been
575 * initialized.
576 */
577 public final void doFinal(byte[] output, int outOffset)
578 throws ShortBufferException, IllegalStateException
579 {
580 chooseFirstProvider();
581 if (initialized == false) {
582 throw new IllegalStateException("MAC not initialized");
583 }
584 int macLen = getMacLength();
585 if (output == null || output.length-outOffset < macLen) {
586 throw new ShortBufferException
587 ("Cannot store MAC in output buffer");
588 }
589 byte[] mac = doFinal();
590 System.arraycopy(mac, 0, output, outOffset, macLen);
591 return;
592 }
593
594 /**
595 * Processes the given array of bytes and finishes the MAC operation.
596 *
597 * <p>A call to this method resets this <code>Mac</code> object to the
598 * state it was in when previously initialized via a call to
599 * <code>init(Key)</code> or
600 * <code>init(Key, AlgorithmParameterSpec)</code>.
601 * That is, the object is reset and available to generate another MAC from
602 * the same key, if desired, via new calls to <code>update</code> and
603 * <code>doFinal</code>.
604 * (In order to reuse this <code>Mac</code> object with a different key,
605 * it must be reinitialized via a call to <code>init(Key)</code> or
606 * <code>init(Key, AlgorithmParameterSpec)</code>.
607 *
608 * @param input data in bytes
609 * @return the MAC result.
610 *
611 * @exception IllegalStateException if this <code>Mac</code> has not been
612 * initialized.
613 */
614 public final byte[] doFinal(byte[] input) throws IllegalStateException
615 {
616 chooseFirstProvider();
617 if (initialized == false) {
618 throw new IllegalStateException("MAC not initialized");
619 }
620 update(input);
621 return doFinal();
622 }
623
624 /**
625 * Resets this <code>Mac</code> object.
626 *
627 * <p>A call to this method resets this <code>Mac</code> object to the
628 * state it was in when previously initialized via a call to
629 * <code>init(Key)</code> or
630 * <code>init(Key, AlgorithmParameterSpec)</code>.
631 * That is, the object is reset and available to generate another MAC from
632 * the same key, if desired, via new calls to <code>update</code> and
633 * <code>doFinal</code>.
634 * (In order to reuse this <code>Mac</code> object with a different key,
635 * it must be reinitialized via a call to <code>init(Key)</code> or
636 * <code>init(Key, AlgorithmParameterSpec)</code>.
637 */
638 public final void reset() {
639 chooseFirstProvider();
640 spi.engineReset();
641 }
642
643 /**
644 * Returns a clone if the provider implementation is cloneable.
645 *
646 * @return a clone if the provider implementation is cloneable.
647 *
648 * @exception CloneNotSupportedException if this is called on a
649 * delegate that does not support <code>Cloneable</code>.
650 */
651 public final Object clone() throws CloneNotSupportedException {
652 chooseFirstProvider();
653 Mac that = (Mac)super.clone();
654 that.spi = (MacSpi)this.spi.clone();
655 return that;
656 }
657}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t