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