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="https://docs.oracle.com/javase/8/docs/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 */ Mac(MacSpi macSpi, Provider provider, String algorithm)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. Mac(String algorithm)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 */ getAlgorithm()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 * "https://docs.oracle.com/javase/8/docs/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 */ getInstance(String algorithm)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 * "https://docs.oracle.com/javase/8/docs/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 */ getInstance(String algorithm, String provider)310 public static final Mac getInstance(String algorithm, String provider) 311 throws NoSuchAlgorithmException, NoSuchProviderException { 312 // Android-added: Check for Bouncy Castle deprecation 313 Providers.checkBouncyCastleDeprecation(provider, "Mac", algorithm); 314 Instance instance = JceSecurity.getInstance 315 ("Mac", MacSpi.class, algorithm, provider); 316 return new Mac((MacSpi)instance.impl, instance.provider, algorithm); 317 } 318 319 /** 320 * Returns a <code>Mac</code> object that implements the 321 * specified MAC algorithm. 322 * 323 * <p> A new Mac object encapsulating the 324 * MacSpi implementation from the specified Provider 325 * object is returned. Note that the specified Provider object 326 * does not have to be registered in the provider list. 327 * 328 * @param algorithm the standard name of the requested MAC algorithm. 329 * See the Mac section in the <a href= 330 * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Mac"> 331 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 332 * for information about standard algorithm names. 333 * 334 * @param provider the provider. 335 * 336 * @return the new <code>Mac</code> object. 337 * 338 * @exception NoSuchAlgorithmException if a MacSpi 339 * implementation for the specified algorithm is not available 340 * from the specified Provider object. 341 * 342 * @exception IllegalArgumentException if the <code>provider</code> 343 * is null. 344 * 345 * @see java.security.Provider 346 */ getInstance(String algorithm, Provider provider)347 public static final Mac getInstance(String algorithm, Provider provider) 348 throws NoSuchAlgorithmException { 349 // Android-added: Check for Bouncy Castle deprecation 350 Providers.checkBouncyCastleDeprecation(provider, "Mac", algorithm); 351 Instance instance = JceSecurity.getInstance 352 ("Mac", MacSpi.class, algorithm, provider); 353 return new Mac((MacSpi)instance.impl, instance.provider, algorithm); 354 } 355 356 // max number of debug warnings to print from chooseFirstProvider() 357 private static int warnCount = 10; 358 359 /** 360 * Choose the Spi from the first provider available. Used if 361 * delayed provider selection is not possible because init() 362 * is not the first method called. 363 */ chooseFirstProvider()364 void chooseFirstProvider() { 365 // Android-changed: Check if lock is null rather than removed serviceIterator field. 366 // if ((spi != null) || (serviceIterator == null)) { 367 if (spi != null || lock == null) { 368 return; 369 } 370 synchronized (lock) { 371 if (spi != null) { 372 return; 373 } 374 // Android-removed: this debugging mechanism is not used in Android. 375 /* 376 if (debug != null) { 377 int w = --warnCount; 378 if (w >= 0) { 379 debug.println("Mac.init() not first method " 380 + "called, disabling delayed provider selection"); 381 if (w == 0) { 382 debug.println("Further warnings of this type will " 383 + "be suppressed"); 384 } 385 new Exception("Call trace").printStackTrace(); 386 } 387 } 388 */ 389 Exception lastException = null; 390 // Android-changed: Provider selection; loop over a new list each time. 391 for (Service s : GetInstance.getServices("Mac", algorithm)) { 392 if (JceSecurity.canUseProvider(s.getProvider()) == false) { 393 continue; 394 } 395 try { 396 Object obj = s.newInstance(null); 397 if (obj instanceof MacSpi == false) { 398 continue; 399 } 400 spi = (MacSpi)obj; 401 provider = s.getProvider(); 402 // Android-removed: Provider selection; loop over a new list each time. 403 /* 404 // not needed any more 405 firstService = null; 406 serviceIterator = null; 407 */ 408 return; 409 } catch (NoSuchAlgorithmException e) { 410 lastException = e; 411 } 412 } 413 ProviderException e = new ProviderException 414 ("Could not construct MacSpi instance"); 415 if (lastException != null) { 416 e.initCause(lastException); 417 } 418 throw e; 419 } 420 } 421 chooseProvider(Key key, AlgorithmParameterSpec params)422 private void chooseProvider(Key key, AlgorithmParameterSpec params) 423 throws InvalidKeyException, InvalidAlgorithmParameterException { 424 synchronized (lock) { 425 // Android-changed: Use the currently-selected provider only if no key was provided. 426 // if (spi != null) { 427 if (spi != null && (key == null || lock == null)) { 428 spi.engineInit(key, params); 429 return; 430 } 431 Exception lastException = null; 432 // Android-changed: Provider selection; loop over a new list each time. 433 for (Service s : GetInstance.getServices("Mac", algorithm)) { 434 // if provider says it does not support this key, ignore it 435 if (s.supportsParameter(key) == false) { 436 continue; 437 } 438 if (JceSecurity.canUseProvider(s.getProvider()) == false) { 439 continue; 440 } 441 try { 442 MacSpi spi = (MacSpi)s.newInstance(null); 443 spi.engineInit(key, params); 444 provider = s.getProvider(); 445 this.spi = spi; 446 // Android-removed: Provider selection; loop over a new list each time. 447 /* 448 firstService = null; 449 serviceIterator = null; 450 */ 451 return; 452 } catch (Exception e) { 453 // NoSuchAlgorithmException from newInstance() 454 // InvalidKeyException from init() 455 // RuntimeException (ProviderException) from init() 456 if (lastException == null) { 457 lastException = e; 458 } 459 } 460 } 461 // no working provider found, fail 462 if (lastException instanceof InvalidKeyException) { 463 throw (InvalidKeyException)lastException; 464 } 465 if (lastException instanceof InvalidAlgorithmParameterException) { 466 throw (InvalidAlgorithmParameterException)lastException; 467 } 468 if (lastException instanceof RuntimeException) { 469 throw (RuntimeException)lastException; 470 } 471 String kName = (key != null) ? key.getClass().getName() : "(null)"; 472 throw new InvalidKeyException 473 ("No installed provider supports this key: " 474 + kName, lastException); 475 } 476 } 477 478 /** 479 * Returns the provider of this <code>Mac</code> object. 480 * 481 * @return the provider of this <code>Mac</code> object. 482 */ getProvider()483 public final Provider getProvider() { 484 chooseFirstProvider(); 485 return this.provider; 486 } 487 488 /** 489 * Returns the length of the MAC in bytes. 490 * 491 * @return the MAC length in bytes. 492 */ getMacLength()493 public final int getMacLength() { 494 chooseFirstProvider(); 495 return spi.engineGetMacLength(); 496 } 497 498 /** 499 * Initializes this <code>Mac</code> object with the given key. 500 * 501 * @param key the key. 502 * 503 * @exception InvalidKeyException if the given key is inappropriate for 504 * initializing this MAC. 505 */ init(Key key)506 public final void init(Key key) throws InvalidKeyException { 507 try { 508 // Android-changed: Use the currently-selected provider only if no key was provided. 509 // if (spi != null) { 510 if (spi != null && (key == null || lock == null)) { 511 spi.engineInit(key, null); 512 } else { 513 chooseProvider(key, null); 514 } 515 } catch (InvalidAlgorithmParameterException e) { 516 throw new InvalidKeyException("init() failed", e); 517 } 518 initialized = true; 519 520 // Android-removed: this debugging mechanism is not used in Android. 521 /* 522 if (!skipDebug && pdebug != null) { 523 pdebug.println("Mac." + algorithm + " algorithm from: " + 524 this.provider.getName()); 525 } 526 */ 527 } 528 529 /** 530 * Initializes this <code>Mac</code> object with the given key and 531 * algorithm parameters. 532 * 533 * @param key the key. 534 * @param params the algorithm parameters. 535 * 536 * @exception InvalidKeyException if the given key is inappropriate for 537 * initializing this MAC. 538 * @exception InvalidAlgorithmParameterException if the given algorithm 539 * parameters are inappropriate for this MAC. 540 */ init(Key key, AlgorithmParameterSpec params)541 public final void init(Key key, AlgorithmParameterSpec params) 542 throws InvalidKeyException, InvalidAlgorithmParameterException { 543 // Android-changed: Use the currently-selected provider only if no key was provided. 544 // if (spi != null) { 545 if (spi != null && (key == null || lock == null)) { 546 spi.engineInit(key, params); 547 } else { 548 chooseProvider(key, params); 549 } 550 initialized = true; 551 552 // Android-removed: this debugging mechanism is not used in Android. 553 /* 554 if (!skipDebug && pdebug != null) { 555 pdebug.println("Mac." + algorithm + " algorithm from: " + 556 this.provider.getName()); 557 } 558 */ 559 } 560 561 /** 562 * Processes the given byte. 563 * 564 * @param input the input byte to be processed. 565 * 566 * @exception IllegalStateException if this <code>Mac</code> has not been 567 * initialized. 568 */ update(byte input)569 public final void update(byte input) throws IllegalStateException { 570 chooseFirstProvider(); 571 if (initialized == false) { 572 throw new IllegalStateException("MAC not initialized"); 573 } 574 spi.engineUpdate(input); 575 } 576 577 /** 578 * Processes the given array of bytes. 579 * 580 * @param input the array of bytes to be processed. 581 * 582 * @exception IllegalStateException if this <code>Mac</code> has not been 583 * initialized. 584 */ update(byte[] input)585 public final void update(byte[] input) throws IllegalStateException { 586 chooseFirstProvider(); 587 if (initialized == false) { 588 throw new IllegalStateException("MAC not initialized"); 589 } 590 if (input != null) { 591 spi.engineUpdate(input, 0, input.length); 592 } 593 } 594 595 /** 596 * Processes the first <code>len</code> bytes in <code>input</code>, 597 * starting at <code>offset</code> inclusive. 598 * 599 * @param input the input buffer. 600 * @param offset the offset in <code>input</code> where the input starts. 601 * @param len the number of bytes to process. 602 * 603 * @exception IllegalStateException if this <code>Mac</code> has not been 604 * initialized. 605 */ update(byte[] input, int offset, int len)606 public final void update(byte[] input, int offset, int len) 607 throws IllegalStateException { 608 chooseFirstProvider(); 609 if (initialized == false) { 610 throw new IllegalStateException("MAC not initialized"); 611 } 612 613 if (input != null) { 614 if ((offset < 0) || (len > (input.length - offset)) || (len < 0)) 615 throw new IllegalArgumentException("Bad arguments"); 616 spi.engineUpdate(input, offset, len); 617 } 618 } 619 620 /** 621 * Processes <code>input.remaining()</code> bytes in the ByteBuffer 622 * <code>input</code>, starting at <code>input.position()</code>. 623 * Upon return, the buffer's position will be equal to its limit; 624 * its limit will not have changed. 625 * 626 * @param input the ByteBuffer 627 * 628 * @exception IllegalStateException if this <code>Mac</code> has not been 629 * initialized. 630 * @since 1.5 631 */ update(ByteBuffer input)632 public final void update(ByteBuffer input) { 633 chooseFirstProvider(); 634 if (initialized == false) { 635 throw new IllegalStateException("MAC not initialized"); 636 } 637 if (input == null) { 638 throw new IllegalArgumentException("Buffer must not be null"); 639 } 640 spi.engineUpdate(input); 641 } 642 643 /** 644 * Finishes the MAC operation. 645 * 646 * <p>A call to this method resets this <code>Mac</code> object to the 647 * state it was in when previously initialized via a call to 648 * <code>init(Key)</code> or 649 * <code>init(Key, AlgorithmParameterSpec)</code>. 650 * That is, the object is reset and available to generate another MAC from 651 * the same key, if desired, via new calls to <code>update</code> and 652 * <code>doFinal</code>. 653 * (In order to reuse this <code>Mac</code> object with a different key, 654 * it must be reinitialized via a call to <code>init(Key)</code> or 655 * <code>init(Key, AlgorithmParameterSpec)</code>. 656 * 657 * @return the MAC result. 658 * 659 * @exception IllegalStateException if this <code>Mac</code> has not been 660 * initialized. 661 */ doFinal()662 public final byte[] doFinal() throws IllegalStateException { 663 chooseFirstProvider(); 664 if (initialized == false) { 665 throw new IllegalStateException("MAC not initialized"); 666 } 667 byte[] mac = spi.engineDoFinal(); 668 spi.engineReset(); 669 return mac; 670 } 671 672 /** 673 * Finishes the MAC operation. 674 * 675 * <p>A call to this method resets this <code>Mac</code> object to the 676 * state it was in when previously initialized via a call to 677 * <code>init(Key)</code> or 678 * <code>init(Key, AlgorithmParameterSpec)</code>. 679 * That is, the object is reset and available to generate another MAC from 680 * the same key, if desired, via new calls to <code>update</code> and 681 * <code>doFinal</code>. 682 * (In order to reuse this <code>Mac</code> object with a different key, 683 * it must be reinitialized via a call to <code>init(Key)</code> or 684 * <code>init(Key, AlgorithmParameterSpec)</code>. 685 * 686 * <p>The MAC result is stored in <code>output</code>, starting at 687 * <code>outOffset</code> inclusive. 688 * 689 * @param output the buffer where the MAC result is stored 690 * @param outOffset the offset in <code>output</code> where the MAC is 691 * stored 692 * 693 * @exception ShortBufferException if the given output buffer is too small 694 * to hold the result 695 * @exception IllegalStateException if this <code>Mac</code> has not been 696 * initialized. 697 */ doFinal(byte[] output, int outOffset)698 public final void doFinal(byte[] output, int outOffset) 699 throws ShortBufferException, IllegalStateException 700 { 701 chooseFirstProvider(); 702 if (initialized == false) { 703 throw new IllegalStateException("MAC not initialized"); 704 } 705 int macLen = getMacLength(); 706 if (output == null || output.length-outOffset < macLen) { 707 throw new ShortBufferException 708 ("Cannot store MAC in output buffer"); 709 } 710 byte[] mac = doFinal(); 711 System.arraycopy(mac, 0, output, outOffset, macLen); 712 return; 713 } 714 715 /** 716 * Processes the given array of bytes and finishes the MAC operation. 717 * 718 * <p>A call to this method resets this <code>Mac</code> object to the 719 * state it was in when previously initialized via a call to 720 * <code>init(Key)</code> or 721 * <code>init(Key, AlgorithmParameterSpec)</code>. 722 * That is, the object is reset and available to generate another MAC from 723 * the same key, if desired, via new calls to <code>update</code> and 724 * <code>doFinal</code>. 725 * (In order to reuse this <code>Mac</code> object with a different key, 726 * it must be reinitialized via a call to <code>init(Key)</code> or 727 * <code>init(Key, AlgorithmParameterSpec)</code>. 728 * 729 * @param input data in bytes 730 * @return the MAC result. 731 * 732 * @exception IllegalStateException if this <code>Mac</code> has not been 733 * initialized. 734 */ doFinal(byte[] input)735 public final byte[] doFinal(byte[] input) throws IllegalStateException 736 { 737 chooseFirstProvider(); 738 if (initialized == false) { 739 throw new IllegalStateException("MAC not initialized"); 740 } 741 update(input); 742 return doFinal(); 743 } 744 745 /** 746 * Resets this <code>Mac</code> object. 747 * 748 * <p>A call to this method resets this <code>Mac</code> object to the 749 * state it was in when previously initialized via a call to 750 * <code>init(Key)</code> or 751 * <code>init(Key, AlgorithmParameterSpec)</code>. 752 * That is, the object is reset and available to generate another MAC from 753 * the same key, if desired, via new calls to <code>update</code> and 754 * <code>doFinal</code>. 755 * (In order to reuse this <code>Mac</code> object with a different key, 756 * it must be reinitialized via a call to <code>init(Key)</code> or 757 * <code>init(Key, AlgorithmParameterSpec)</code>. 758 */ reset()759 public final void reset() { 760 chooseFirstProvider(); 761 spi.engineReset(); 762 } 763 764 /** 765 * Returns a clone if the provider implementation is cloneable. 766 * 767 * @return a clone if the provider implementation is cloneable. 768 * 769 * @exception CloneNotSupportedException if this is called on a 770 * delegate that does not support <code>Cloneable</code>. 771 */ clone()772 public final Object clone() throws CloneNotSupportedException { 773 chooseFirstProvider(); 774 Mac that = (Mac)super.clone(); 775 that.spi = (MacSpi)this.spi.clone(); 776 return that; 777 } 778 779 // BEGIN Android-added: Allow access to the current SPI for testing purposes. 780 /** 781 * Returns the {@code MacSpi} backing this {@code Mac} or {@code null} if no {@code MacSpi} is 782 * backing this {@code Mac}. 783 * 784 * @hide 785 */ getCurrentSpi()786 public MacSpi getCurrentSpi() { 787 return spi; 788 } 789 // END Android-added: Allow access to the current SPI for testing purposes. 790 } 791