1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package javax.crypto; 28 29 import java.util.*; 30 31 import java.security.*; 32 import java.security.Provider.Service; 33 import java.security.spec.AlgorithmParameterSpec; 34 35 import java.nio.ByteBuffer; 36 37 import sun.security.jca.*; 38 import 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> Android provides the following <code>Mac</code> algorithms: 57 * <table> 58 * <thead> 59 * <tr> 60 * <th>Algorithm</th> 61 * <th>Supported API Levels</th> 62 * </tr> 63 * </thead> 64 * <tbody> 65 * <tr class="deprecated"> 66 * <td>DESMAC</td> 67 * <td>1-8</td> 68 * </tr> 69 * <tr class="deprecated"> 70 * <td>DESMAC/CFB8</td> 71 * <td>1-8</td> 72 * </tr> 73 * <tr class="deprecated"> 74 * <td>DESedeMAC</td> 75 * <td>1-8</td> 76 * </tr> 77 * <tr class="deprecated"> 78 * <td>DESedeMAC/CFB8</td> 79 * <td>1-8</td> 80 * </tr> 81 * <tr class="deprecated"> 82 * <td>DESedeMAC64</td> 83 * <td>1-8</td> 84 * </tr> 85 * <tr class="deprecated"> 86 * <td>DESwithISO9797</td> 87 * <td>1-8</td> 88 * </tr> 89 * <tr> 90 * <td>HmacMD5</td> 91 * <td>1+</td> 92 * </tr> 93 * <tr> 94 * <td>HmacSHA1</td> 95 * <td>1+</td> 96 * </tr> 97 * <tr> 98 * <td>HmacSHA224</td> 99 * <td>1-8,22+</td> 100 * </tr> 101 * <tr> 102 * <td>HmacSHA256</td> 103 * <td>1+</td> 104 * </tr> 105 * <tr> 106 * <td>HmacSHA384</td> 107 * <td>1+</td> 108 * </tr> 109 * <tr> 110 * <td>HmacSHA512</td> 111 * <td>1+</td> 112 * </tr> 113 * <tr class="deprecated"> 114 * <td>ISO9797ALG3MAC</td> 115 * <td>1-8</td> 116 * </tr> 117 * <tr> 118 * <td>PBEwithHmacSHA</td> 119 * <td>1+</td> 120 * </tr> 121 * <tr> 122 * <td>PBEwithHmacSHA1</td> 123 * <td>1+</td> 124 * </tr> 125 * <tr> 126 * <td>PBEwithHmacSHA224</td> 127 * <td>26+</td> 128 * </tr> 129 * <tr> 130 * <td>PBEwithHmacSHA256</td> 131 * <td>26+</td> 132 * </tr> 133 * <tr> 134 * <td>PBEwithHmacSHA384</td> 135 * <td>26+</td> 136 * </tr> 137 * <tr> 138 * <td>PBEwithHmacSHA512</td> 139 * <td>26+</td> 140 * </tr> 141 * </tbody> 142 * </table> 143 * 144 * These algorithms are described in the 145 * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#Mac"> 146 * Mac section</a> of the 147 * Java Cryptography Architecture Standard Algorithm Name Documentation. 148 * 149 * @author Jan Luehe 150 * 151 * @since 1.4 152 */ 153 154 public class Mac implements Cloneable { 155 156 // Android-removed: this debugging mechanism is not used in Android. 157 /* 158 private static final Debug debug = 159 Debug.getInstance("jca", "Mac"); 160 161 private static final Debug pdebug = 162 Debug.getInstance("provider", "Provider"); 163 private static final boolean skipDebug = 164 Debug.isOn("engine=") && !Debug.isOn("mac"); 165 */ 166 167 // The provider 168 private Provider provider; 169 170 // The provider implementation (delegate) 171 private MacSpi spi; 172 173 // The name of the MAC algorithm. 174 private final String algorithm; 175 176 // Has this object been initialized? 177 private boolean initialized = false; 178 179 // BEGIN Android-removed: Redo the provider selection logic to allow reselecting provider. 180 // When only the algorithm is specified, we want to allow the Mac provider for that 181 // algorithm to change if multiple providers exist and they support different subsets of 182 // keys. To that end, we don't hold an iterator and exhaust it when we need to choose 183 // a provider like the upstream implementation, we reestablish the list of providers 184 // each time. 185 /* 186 // next service to try in provider selection 187 // null once provider is selected 188 private Service firstService; 189 190 // remaining services to try in provider selection 191 // null once provider is selected 192 private Iterator<Service> serviceIterator; 193 */ 194 // END Android-removed: Redo the provider selection logic to allow reselecting provider. 195 196 private final Object lock; 197 198 /** 199 * Creates a MAC object. 200 * 201 * @param macSpi the delegate 202 * @param provider the provider 203 * @param algorithm the algorithm 204 */ 205 protected Mac(MacSpi macSpi, Provider provider, String algorithm) { 206 this.spi = macSpi; 207 this.provider = provider; 208 this.algorithm = algorithm; 209 lock = null; 210 } 211 212 // Android-changed: Remove Service and Iterator from constructor args. 213 private Mac(String algorithm) { 214 this.algorithm = algorithm; 215 lock = new Object(); 216 } 217 218 /** 219 * Returns the algorithm name of this <code>Mac</code> object. 220 * 221 * <p>This is the same name that was specified in one of the 222 * <code>getInstance</code> calls that created this 223 * <code>Mac</code> object. 224 * 225 * @return the algorithm name of this <code>Mac</code> object. 226 */ 227 public final String getAlgorithm() { 228 return this.algorithm; 229 } 230 231 /** 232 * Returns a <code>Mac</code> object that implements the 233 * specified MAC algorithm. 234 * 235 * <p> This method traverses the list of registered security Providers, 236 * starting with the most preferred Provider. 237 * A new Mac object encapsulating the 238 * MacSpi implementation from the first 239 * Provider that supports the specified algorithm is returned. 240 * 241 * <p> Note that the list of registered providers may be retrieved via 242 * the {@link Security#getProviders() Security.getProviders()} method. 243 * 244 * @param algorithm the standard name of the requested MAC algorithm. 245 * See the Mac section in the <a href= 246 * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#Mac"> 247 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 248 * for information about standard algorithm names. 249 * 250 * @return the new <code>Mac</code> object. 251 * 252 * @exception NoSuchAlgorithmException if no Provider supports a 253 * MacSpi implementation for the 254 * specified algorithm. 255 * 256 * @see java.security.Provider 257 */ 258 public static final Mac getInstance(String algorithm) 259 throws NoSuchAlgorithmException { 260 List<Service> services = GetInstance.getServices("Mac", algorithm); 261 // make sure there is at least one service from a signed provider 262 Iterator<Service> t = services.iterator(); 263 while (t.hasNext()) { 264 Service s = t.next(); 265 if (JceSecurity.canUseProvider(s.getProvider()) == false) { 266 continue; 267 } 268 // Android-changed: Remove Service and Iterator from constructor args. 269 // return new Mac(s, t, algorithm); 270 return new Mac(algorithm); 271 } 272 throw new NoSuchAlgorithmException 273 ("Algorithm " + algorithm + " not available"); 274 } 275 276 /** 277 * Returns a <code>Mac</code> object that implements the 278 * specified MAC algorithm. 279 * 280 * <p> A new Mac object encapsulating the 281 * MacSpi implementation from the specified provider 282 * is returned. The specified provider must be registered 283 * in the security provider list. 284 * 285 * <p> Note that the list of registered providers may be retrieved via 286 * the {@link Security#getProviders() Security.getProviders()} method. 287 * 288 * @param algorithm the standard name of the requested MAC algorithm. 289 * See the Mac section in the <a href= 290 * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#Mac"> 291 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 292 * for information about standard algorithm names. 293 * 294 * @param provider the name of the provider. 295 * 296 * @return the new <code>Mac</code> object. 297 * 298 * @exception NoSuchAlgorithmException if a MacSpi 299 * implementation for the specified algorithm is not 300 * available from the specified provider. 301 * 302 * @exception NoSuchProviderException if the specified provider is not 303 * registered in the security provider list. 304 * 305 * @exception IllegalArgumentException if the <code>provider</code> 306 * is null or empty. 307 * 308 * @see java.security.Provider 309 */ 310 public static final Mac getInstance(String algorithm, String provider) 311 throws NoSuchAlgorithmException, NoSuchProviderException { 312 Instance instance = JceSecurity.getInstance 313 ("Mac", MacSpi.class, algorithm, provider); 314 return new Mac((MacSpi)instance.impl, instance.provider, algorithm); 315 } 316 317 /** 318 * Returns a <code>Mac</code> object that implements the 319 * specified MAC algorithm. 320 * 321 * <p> A new Mac object encapsulating the 322 * MacSpi implementation from the specified Provider 323 * object is returned. Note that the specified Provider object 324 * does not have to be registered in the provider list. 325 * 326 * @param algorithm the standard name of the requested MAC algorithm. 327 * See the Mac section in the <a href= 328 * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#Mac"> 329 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 330 * for information about standard algorithm names. 331 * 332 * @param provider the provider. 333 * 334 * @return the new <code>Mac</code> object. 335 * 336 * @exception NoSuchAlgorithmException if a MacSpi 337 * implementation for the specified algorithm is not available 338 * from the specified Provider object. 339 * 340 * @exception IllegalArgumentException if the <code>provider</code> 341 * is null. 342 * 343 * @see java.security.Provider 344 */ 345 public static final Mac getInstance(String algorithm, Provider provider) 346 throws NoSuchAlgorithmException { 347 Instance instance = JceSecurity.getInstance 348 ("Mac", MacSpi.class, algorithm, provider); 349 return new Mac((MacSpi)instance.impl, instance.provider, algorithm); 350 } 351 352 // max number of debug warnings to print from chooseFirstProvider() 353 private static int warnCount = 10; 354 355 /** 356 * Choose the Spi from the first provider available. Used if 357 * delayed provider selection is not possible because init() 358 * is not the first method called. 359 */ 360 void chooseFirstProvider() { 361 // Android-changed: Check if lock is null rather than removed serviceIterator field. 362 // if ((spi != null) || (serviceIterator == null)) { 363 if (spi != null || lock == null) { 364 return; 365 } 366 synchronized (lock) { 367 if (spi != null) { 368 return; 369 } 370 // Android-removed: this debugging mechanism is not used in Android. 371 /* 372 if (debug != null) { 373 int w = --warnCount; 374 if (w >= 0) { 375 debug.println("Mac.init() not first method " 376 + "called, disabling delayed provider selection"); 377 if (w == 0) { 378 debug.println("Further warnings of this type will " 379 + "be suppressed"); 380 } 381 new Exception("Call trace").printStackTrace(); 382 } 383 } 384 */ 385 Exception lastException = null; 386 // Android-changed: Provider selection; loop over a new list each time. 387 for (Service s : GetInstance.getServices("Mac", algorithm)) { 388 if (JceSecurity.canUseProvider(s.getProvider()) == false) { 389 continue; 390 } 391 try { 392 Object obj = s.newInstance(null); 393 if (obj instanceof MacSpi == false) { 394 continue; 395 } 396 spi = (MacSpi)obj; 397 provider = s.getProvider(); 398 // Android-removed: Provider selection; loop over a new list each time. 399 /* 400 // not needed any more 401 firstService = null; 402 serviceIterator = null; 403 */ 404 return; 405 } catch (NoSuchAlgorithmException e) { 406 lastException = e; 407 } 408 } 409 ProviderException e = new ProviderException 410 ("Could not construct MacSpi instance"); 411 if (lastException != null) { 412 e.initCause(lastException); 413 } 414 throw e; 415 } 416 } 417 418 private void chooseProvider(Key key, AlgorithmParameterSpec params) 419 throws InvalidKeyException, InvalidAlgorithmParameterException { 420 synchronized (lock) { 421 // Android-changed: Use the currently-selected provider only if no key was provided. 422 // if (spi != null) { 423 if (spi != null && (key == null || lock == null)) { 424 spi.engineInit(key, params); 425 return; 426 } 427 Exception lastException = null; 428 // Android-changed: Provider selection; loop over a new list each time. 429 for (Service s : GetInstance.getServices("Mac", algorithm)) { 430 // if provider says it does not support this key, ignore it 431 if (s.supportsParameter(key) == false) { 432 continue; 433 } 434 if (JceSecurity.canUseProvider(s.getProvider()) == false) { 435 continue; 436 } 437 try { 438 MacSpi spi = (MacSpi)s.newInstance(null); 439 spi.engineInit(key, params); 440 provider = s.getProvider(); 441 this.spi = spi; 442 // Android-removed: Provider selection; loop over a new list each time. 443 /* 444 firstService = null; 445 serviceIterator = null; 446 */ 447 return; 448 } catch (Exception e) { 449 // NoSuchAlgorithmException from newInstance() 450 // InvalidKeyException from init() 451 // RuntimeException (ProviderException) from init() 452 if (lastException == null) { 453 lastException = e; 454 } 455 } 456 } 457 // no working provider found, fail 458 if (lastException instanceof InvalidKeyException) { 459 throw (InvalidKeyException)lastException; 460 } 461 if (lastException instanceof InvalidAlgorithmParameterException) { 462 throw (InvalidAlgorithmParameterException)lastException; 463 } 464 if (lastException instanceof RuntimeException) { 465 throw (RuntimeException)lastException; 466 } 467 String kName = (key != null) ? key.getClass().getName() : "(null)"; 468 throw new InvalidKeyException 469 ("No installed provider supports this key: " 470 + kName, lastException); 471 } 472 } 473 474 /** 475 * Returns the provider of this <code>Mac</code> object. 476 * 477 * @return the provider of this <code>Mac</code> object. 478 */ 479 public final Provider getProvider() { 480 chooseFirstProvider(); 481 return this.provider; 482 } 483 484 /** 485 * Returns the length of the MAC in bytes. 486 * 487 * @return the MAC length in bytes. 488 */ 489 public final int getMacLength() { 490 chooseFirstProvider(); 491 return spi.engineGetMacLength(); 492 } 493 494 /** 495 * Initializes this <code>Mac</code> object with the given key. 496 * 497 * @param key the key. 498 * 499 * @exception InvalidKeyException if the given key is inappropriate for 500 * initializing this MAC. 501 */ 502 public final void init(Key key) throws InvalidKeyException { 503 try { 504 // Android-changed: Use the currently-selected provider only if no key was provided. 505 // if (spi != null) { 506 if (spi != null && (key == null || lock == null)) { 507 spi.engineInit(key, null); 508 } else { 509 chooseProvider(key, null); 510 } 511 } catch (InvalidAlgorithmParameterException e) { 512 throw new InvalidKeyException("init() failed", e); 513 } 514 initialized = true; 515 516 // Android-removed: this debugging mechanism is not used in Android. 517 /* 518 if (!skipDebug && pdebug != null) { 519 pdebug.println("Mac." + algorithm + " algorithm from: " + 520 this.provider.getName()); 521 } 522 */ 523 } 524 525 /** 526 * Initializes this <code>Mac</code> object with the given key and 527 * algorithm parameters. 528 * 529 * @param key the key. 530 * @param params the algorithm parameters. 531 * 532 * @exception InvalidKeyException if the given key is inappropriate for 533 * initializing this MAC. 534 * @exception InvalidAlgorithmParameterException if the given algorithm 535 * parameters are inappropriate for this MAC. 536 */ 537 public final void init(Key key, AlgorithmParameterSpec params) 538 throws InvalidKeyException, InvalidAlgorithmParameterException { 539 // Android-changed: Use the currently-selected provider only if no key was provided. 540 // if (spi != null) { 541 if (spi != null && (key == null || lock == null)) { 542 spi.engineInit(key, params); 543 } else { 544 chooseProvider(key, params); 545 } 546 initialized = true; 547 548 // Android-removed: this debugging mechanism is not used in Android. 549 /* 550 if (!skipDebug && pdebug != null) { 551 pdebug.println("Mac." + algorithm + " algorithm from: " + 552 this.provider.getName()); 553 } 554 */ 555 } 556 557 /** 558 * Processes the given byte. 559 * 560 * @param input the input byte to be processed. 561 * 562 * @exception IllegalStateException if this <code>Mac</code> has not been 563 * initialized. 564 */ 565 public final void update(byte input) throws IllegalStateException { 566 chooseFirstProvider(); 567 if (initialized == false) { 568 throw new IllegalStateException("MAC not initialized"); 569 } 570 spi.engineUpdate(input); 571 } 572 573 /** 574 * Processes the given array of bytes. 575 * 576 * @param input the array of bytes to be processed. 577 * 578 * @exception IllegalStateException if this <code>Mac</code> has not been 579 * initialized. 580 */ 581 public final void update(byte[] input) throws IllegalStateException { 582 chooseFirstProvider(); 583 if (initialized == false) { 584 throw new IllegalStateException("MAC not initialized"); 585 } 586 if (input != null) { 587 spi.engineUpdate(input, 0, input.length); 588 } 589 } 590 591 /** 592 * Processes the first <code>len</code> bytes in <code>input</code>, 593 * starting at <code>offset</code> inclusive. 594 * 595 * @param input the input buffer. 596 * @param offset the offset in <code>input</code> where the input starts. 597 * @param len the number of bytes to process. 598 * 599 * @exception IllegalStateException if this <code>Mac</code> has not been 600 * initialized. 601 */ 602 public final void update(byte[] input, int offset, int len) 603 throws IllegalStateException { 604 chooseFirstProvider(); 605 if (initialized == false) { 606 throw new IllegalStateException("MAC not initialized"); 607 } 608 609 if (input != null) { 610 if ((offset < 0) || (len > (input.length - offset)) || (len < 0)) 611 throw new IllegalArgumentException("Bad arguments"); 612 spi.engineUpdate(input, offset, len); 613 } 614 } 615 616 /** 617 * Processes <code>input.remaining()</code> bytes in the ByteBuffer 618 * <code>input</code>, starting at <code>input.position()</code>. 619 * Upon return, the buffer's position will be equal to its limit; 620 * its limit will not have changed. 621 * 622 * @param input the ByteBuffer 623 * 624 * @exception IllegalStateException if this <code>Mac</code> has not been 625 * initialized. 626 * @since 1.5 627 */ 628 public final void update(ByteBuffer input) { 629 chooseFirstProvider(); 630 if (initialized == false) { 631 throw new IllegalStateException("MAC not initialized"); 632 } 633 if (input == null) { 634 throw new IllegalArgumentException("Buffer must not be null"); 635 } 636 spi.engineUpdate(input); 637 } 638 639 /** 640 * Finishes the MAC operation. 641 * 642 * <p>A call to this method resets this <code>Mac</code> object to the 643 * state it was in when previously initialized via a call to 644 * <code>init(Key)</code> or 645 * <code>init(Key, AlgorithmParameterSpec)</code>. 646 * That is, the object is reset and available to generate another MAC from 647 * the same key, if desired, via new calls to <code>update</code> and 648 * <code>doFinal</code>. 649 * (In order to reuse this <code>Mac</code> object with a different key, 650 * it must be reinitialized via a call to <code>init(Key)</code> or 651 * <code>init(Key, AlgorithmParameterSpec)</code>. 652 * 653 * @return the MAC result. 654 * 655 * @exception IllegalStateException if this <code>Mac</code> has not been 656 * initialized. 657 */ 658 public final byte[] doFinal() throws IllegalStateException { 659 chooseFirstProvider(); 660 if (initialized == false) { 661 throw new IllegalStateException("MAC not initialized"); 662 } 663 byte[] mac = spi.engineDoFinal(); 664 spi.engineReset(); 665 return mac; 666 } 667 668 /** 669 * Finishes the MAC operation. 670 * 671 * <p>A call to this method resets this <code>Mac</code> object to the 672 * state it was in when previously initialized via a call to 673 * <code>init(Key)</code> or 674 * <code>init(Key, AlgorithmParameterSpec)</code>. 675 * That is, the object is reset and available to generate another MAC from 676 * the same key, if desired, via new calls to <code>update</code> and 677 * <code>doFinal</code>. 678 * (In order to reuse this <code>Mac</code> object with a different key, 679 * it must be reinitialized via a call to <code>init(Key)</code> or 680 * <code>init(Key, AlgorithmParameterSpec)</code>. 681 * 682 * <p>The MAC result is stored in <code>output</code>, starting at 683 * <code>outOffset</code> inclusive. 684 * 685 * @param output the buffer where the MAC result is stored 686 * @param outOffset the offset in <code>output</code> where the MAC is 687 * stored 688 * 689 * @exception ShortBufferException if the given output buffer is too small 690 * to hold the result 691 * @exception IllegalStateException if this <code>Mac</code> has not been 692 * initialized. 693 */ 694 public final void doFinal(byte[] output, int outOffset) 695 throws ShortBufferException, IllegalStateException 696 { 697 chooseFirstProvider(); 698 if (initialized == false) { 699 throw new IllegalStateException("MAC not initialized"); 700 } 701 int macLen = getMacLength(); 702 if (output == null || output.length-outOffset < macLen) { 703 throw new ShortBufferException 704 ("Cannot store MAC in output buffer"); 705 } 706 byte[] mac = doFinal(); 707 System.arraycopy(mac, 0, output, outOffset, macLen); 708 return; 709 } 710 711 /** 712 * Processes the given array of bytes and finishes the MAC operation. 713 * 714 * <p>A call to this method resets this <code>Mac</code> object to the 715 * state it was in when previously initialized via a call to 716 * <code>init(Key)</code> or 717 * <code>init(Key, AlgorithmParameterSpec)</code>. 718 * That is, the object is reset and available to generate another MAC from 719 * the same key, if desired, via new calls to <code>update</code> and 720 * <code>doFinal</code>. 721 * (In order to reuse this <code>Mac</code> object with a different key, 722 * it must be reinitialized via a call to <code>init(Key)</code> or 723 * <code>init(Key, AlgorithmParameterSpec)</code>. 724 * 725 * @param input data in bytes 726 * @return the MAC result. 727 * 728 * @exception IllegalStateException if this <code>Mac</code> has not been 729 * initialized. 730 */ 731 public final byte[] doFinal(byte[] input) throws IllegalStateException 732 { 733 chooseFirstProvider(); 734 if (initialized == false) { 735 throw new IllegalStateException("MAC not initialized"); 736 } 737 update(input); 738 return doFinal(); 739 } 740 741 /** 742 * Resets this <code>Mac</code> object. 743 * 744 * <p>A call to this method resets this <code>Mac</code> object to the 745 * state it was in when previously initialized via a call to 746 * <code>init(Key)</code> or 747 * <code>init(Key, AlgorithmParameterSpec)</code>. 748 * That is, the object is reset and available to generate another MAC from 749 * the same key, if desired, via new calls to <code>update</code> and 750 * <code>doFinal</code>. 751 * (In order to reuse this <code>Mac</code> object with a different key, 752 * it must be reinitialized via a call to <code>init(Key)</code> or 753 * <code>init(Key, AlgorithmParameterSpec)</code>. 754 */ 755 public final void reset() { 756 chooseFirstProvider(); 757 spi.engineReset(); 758 } 759 760 /** 761 * Returns a clone if the provider implementation is cloneable. 762 * 763 * @return a clone if the provider implementation is cloneable. 764 * 765 * @exception CloneNotSupportedException if this is called on a 766 * delegate that does not support <code>Cloneable</code>. 767 */ 768 public final Object clone() throws CloneNotSupportedException { 769 chooseFirstProvider(); 770 Mac that = (Mac)super.clone(); 771 that.spi = (MacSpi)this.spi.clone(); 772 return that; 773 } 774 775 // BEGIN Android-added: Allow access to the current SPI for testing purposes. 776 /** 777 * Returns the {@code MacSpi} backing this {@code Mac} or {@code null} if no {@code MacSpi} is 778 * backing this {@code Mac}. 779 * 780 * @hide 781 */ 782 public MacSpi getCurrentSpi() { 783 return spi; 784 } 785 // END Android-added: Allow access to the current SPI for testing purposes. 786 } 787