Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/crypto/Mac.java
38829 views
/*1* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.crypto;2627import java.util.*;2829import java.security.*;30import java.security.Provider.Service;31import java.security.spec.AlgorithmParameterSpec;3233import java.nio.ByteBuffer;3435import sun.security.util.Debug;36import sun.security.jca.*;37import sun.security.jca.GetInstance.Instance;3839/**40* This class provides the functionality of a "Message Authentication Code"41* (MAC) algorithm.42*43* <p> A MAC provides a way to check44* the integrity of information transmitted over or stored in an unreliable45* medium, based on a secret key. Typically, message46* authentication codes are used between two parties that share a secret47* key in order to validate information transmitted between these48* parties.49*50* <p> A MAC mechanism that is based on cryptographic hash functions is51* referred to as HMAC. HMAC can be used with any cryptographic hash function,52* e.g., SHA256 or SHA384, in combination with a secret shared key. HMAC is53* specified in RFC 2104.54*55* <p> Every implementation of the Java platform is required to support56* the following standard {@code Mac} algorithms:57* <ul>58* <li>{@code HmacMD5}</li>59* <li>{@code HmacSHA1}</li>60* <li>{@code HmacSHA256}</li>61* </ul>62* These algorithms are described in the63* <a href="{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">64* Mac section</a> of the65* Java Cryptography Architecture Standard Algorithm Name Documentation.66* Consult the release documentation for your implementation to see if any67* other algorithms are supported.68*69* @author Jan Luehe70*71* @since 1.472*/7374public class Mac implements Cloneable {7576private static final Debug debug =77Debug.getInstance("jca", "Mac");7879private static final Debug pdebug =80Debug.getInstance("provider", "Provider");81private static final boolean skipDebug =82Debug.isOn("engine=") && !Debug.isOn("mac");8384// The provider85private Provider provider;8687// The provider implementation (delegate)88private MacSpi spi;8990// The name of the MAC algorithm.91private final String algorithm;9293// Has this object been initialized?94private boolean initialized = false;9596// next service to try in provider selection97// null once provider is selected98private Service firstService;99100// remaining services to try in provider selection101// null once provider is selected102private Iterator<Service> serviceIterator;103104private final Object lock;105106/**107* Creates a MAC object.108*109* @param macSpi the delegate110* @param provider the provider111* @param algorithm the algorithm112*/113protected Mac(MacSpi macSpi, Provider provider, String algorithm) {114this.spi = macSpi;115this.provider = provider;116this.algorithm = algorithm;117serviceIterator = null;118lock = null;119}120121private Mac(Service s, Iterator<Service> t, String algorithm) {122firstService = s;123serviceIterator = t;124this.algorithm = algorithm;125lock = new Object();126}127128/**129* Returns the algorithm name of this {@code Mac} object.130*131* <p>This is the same name that was specified in one of the132* {@code getInstance} calls that created this133* {@code Mac} object.134*135* @return the algorithm name of this {@code Mac} object.136*/137public final String getAlgorithm() {138return this.algorithm;139}140141/**142* Returns a {@code Mac} object that implements the143* specified MAC algorithm.144*145* <p> This method traverses the list of registered security Providers,146* starting with the most preferred Provider.147* A new Mac object encapsulating the148* MacSpi implementation from the first149* Provider that supports the specified algorithm is returned.150*151* <p> Note that the list of registered providers may be retrieved via152* the {@link Security#getProviders() Security.getProviders()} method.153*154* @param algorithm the standard name of the requested MAC algorithm.155* See the Mac section in the <a href=156* "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">157* Java Cryptography Architecture Standard Algorithm Name Documentation</a>158* for information about standard algorithm names.159*160* @return the new {@code Mac} object.161*162* @exception NoSuchAlgorithmException if no Provider supports a163* MacSpi implementation for the164* specified algorithm.165*166* @see java.security.Provider167*/168public static final Mac getInstance(String algorithm)169throws NoSuchAlgorithmException {170List<Service> services = GetInstance.getServices("Mac", algorithm);171// make sure there is at least one service from a signed provider172Iterator<Service> t = services.iterator();173while (t.hasNext()) {174Service s = t.next();175if (JceSecurity.canUseProvider(s.getProvider()) == false) {176continue;177}178return new Mac(s, t, algorithm);179}180throw new NoSuchAlgorithmException181("Algorithm " + algorithm + " not available");182}183184/**185* Returns a {@code Mac} object that implements the186* specified MAC algorithm.187*188* <p> A new Mac object encapsulating the189* MacSpi implementation from the specified provider190* is returned. The specified provider must be registered191* in the security provider list.192*193* <p> Note that the list of registered providers may be retrieved via194* the {@link Security#getProviders() Security.getProviders()} method.195*196* @param algorithm the standard name of the requested MAC algorithm.197* See the Mac section in the <a href=198* "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">199* Java Cryptography Architecture Standard Algorithm Name Documentation</a>200* for information about standard algorithm names.201*202* @param provider the name of the provider.203*204* @return the new {@code Mac} object.205*206* @exception NoSuchAlgorithmException if a MacSpi207* implementation for the specified algorithm is not208* available from the specified provider.209*210* @exception NoSuchProviderException if the specified provider is not211* registered in the security provider list.212*213* @exception IllegalArgumentException if the {@code provider}214* is null or empty.215*216* @see java.security.Provider217*/218public static final Mac getInstance(String algorithm, String provider)219throws NoSuchAlgorithmException, NoSuchProviderException {220Instance instance = JceSecurity.getInstance221("Mac", MacSpi.class, algorithm, provider);222return new Mac((MacSpi)instance.impl, instance.provider, algorithm);223}224225/**226* Returns a {@code Mac} object that implements the227* specified MAC algorithm.228*229* <p> A new Mac object encapsulating the230* MacSpi implementation from the specified Provider231* object is returned. Note that the specified Provider object232* does not have to be registered in the provider list.233*234* @param algorithm the standard name of the requested MAC algorithm.235* See the Mac section in the <a href=236* "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">237* Java Cryptography Architecture Standard Algorithm Name Documentation</a>238* for information about standard algorithm names.239*240* @param provider the provider.241*242* @return the new {@code Mac} object.243*244* @exception NoSuchAlgorithmException if a MacSpi245* implementation for the specified algorithm is not available246* from the specified Provider object.247*248* @exception IllegalArgumentException if the {@code provider}249* is null.250*251* @see java.security.Provider252*/253public static final Mac getInstance(String algorithm, Provider provider)254throws NoSuchAlgorithmException {255Instance instance = JceSecurity.getInstance256("Mac", MacSpi.class, algorithm, provider);257return new Mac((MacSpi)instance.impl, instance.provider, algorithm);258}259260// max number of debug warnings to print from chooseFirstProvider()261private static int warnCount = 10;262263/**264* Choose the Spi from the first provider available. Used if265* delayed provider selection is not possible because init()266* is not the first method called.267*/268void chooseFirstProvider() {269if ((spi != null) || (serviceIterator == null)) {270return;271}272synchronized (lock) {273if (spi != null) {274return;275}276if (debug != null) {277int w = --warnCount;278if (w >= 0) {279debug.println("Mac.init() not first method "280+ "called, disabling delayed provider selection");281if (w == 0) {282debug.println("Further warnings of this type will "283+ "be suppressed");284}285new Exception("Call trace").printStackTrace();286}287}288Exception lastException = null;289while ((firstService != null) || serviceIterator.hasNext()) {290Service s;291if (firstService != null) {292s = firstService;293firstService = null;294} else {295s = serviceIterator.next();296}297if (JceSecurity.canUseProvider(s.getProvider()) == false) {298continue;299}300try {301Object obj = s.newInstance(null);302if (obj instanceof MacSpi == false) {303continue;304}305spi = (MacSpi)obj;306provider = s.getProvider();307// not needed any more308firstService = null;309serviceIterator = null;310return;311} catch (NoSuchAlgorithmException e) {312lastException = e;313}314}315ProviderException e = new ProviderException316("Could not construct MacSpi instance");317if (lastException != null) {318e.initCause(lastException);319}320throw e;321}322}323324private void chooseProvider(Key key, AlgorithmParameterSpec params)325throws InvalidKeyException, InvalidAlgorithmParameterException {326synchronized (lock) {327if (spi != null) {328spi.engineInit(key, params);329return;330}331Exception lastException = null;332while ((firstService != null) || serviceIterator.hasNext()) {333Service s;334if (firstService != null) {335s = firstService;336firstService = null;337} else {338s = serviceIterator.next();339}340// if provider says it does not support this key, ignore it341if (s.supportsParameter(key) == false) {342continue;343}344if (JceSecurity.canUseProvider(s.getProvider()) == false) {345continue;346}347try {348MacSpi spi = (MacSpi)s.newInstance(null);349spi.engineInit(key, params);350provider = s.getProvider();351this.spi = spi;352firstService = null;353serviceIterator = null;354return;355} catch (Exception e) {356// NoSuchAlgorithmException from newInstance()357// InvalidKeyException from init()358// RuntimeException (ProviderException) from init()359if (lastException == null) {360lastException = e;361}362}363}364// no working provider found, fail365if (lastException instanceof InvalidKeyException) {366throw (InvalidKeyException)lastException;367}368if (lastException instanceof InvalidAlgorithmParameterException) {369throw (InvalidAlgorithmParameterException)lastException;370}371if (lastException instanceof RuntimeException) {372throw (RuntimeException)lastException;373}374String kName = (key != null) ? key.getClass().getName() : "(null)";375throw new InvalidKeyException376("No installed provider supports this key: "377+ kName, lastException);378}379}380381/**382* Returns the provider of this {@code Mac} object.383*384* @return the provider of this {@code Mac} object.385*/386public final Provider getProvider() {387chooseFirstProvider();388return this.provider;389}390391/**392* Returns the length of the MAC in bytes.393*394* @return the MAC length in bytes.395*/396public final int getMacLength() {397chooseFirstProvider();398return spi.engineGetMacLength();399}400401/**402* Initializes this {@code Mac} object with the given key.403*404* @param key the key.405*406* @exception InvalidKeyException if the given key is inappropriate for407* initializing this MAC.408*/409public final void init(Key key) throws InvalidKeyException {410try {411if (spi != null) {412spi.engineInit(key, null);413} else {414chooseProvider(key, null);415}416} catch (InvalidAlgorithmParameterException e) {417throw new InvalidKeyException("init() failed", e);418}419initialized = true;420421if (!skipDebug && pdebug != null) {422pdebug.println("Mac." + algorithm + " algorithm from: " +423this.provider.getName());424}425}426427/**428* Initializes this {@code Mac} object with the given key and429* algorithm parameters.430*431* @param key the key.432* @param params the algorithm parameters.433*434* @exception InvalidKeyException if the given key is inappropriate for435* initializing this MAC.436* @exception InvalidAlgorithmParameterException if the given algorithm437* parameters are inappropriate for this MAC.438*/439public final void init(Key key, AlgorithmParameterSpec params)440throws InvalidKeyException, InvalidAlgorithmParameterException {441if (spi != null) {442spi.engineInit(key, params);443} else {444chooseProvider(key, params);445}446initialized = true;447448if (!skipDebug && pdebug != null) {449pdebug.println("Mac." + algorithm + " algorithm from: " +450this.provider.getName());451}452}453454/**455* Processes the given byte.456*457* @param input the input byte to be processed.458*459* @exception IllegalStateException if this {@code Mac} has not been460* initialized.461*/462public final void update(byte input) throws IllegalStateException {463chooseFirstProvider();464if (initialized == false) {465throw new IllegalStateException("MAC not initialized");466}467spi.engineUpdate(input);468}469470/**471* Processes the given array of bytes.472*473* @param input the array of bytes to be processed.474*475* @exception IllegalStateException if this {@code Mac} has not been476* initialized.477*/478public final void update(byte[] input) throws IllegalStateException {479chooseFirstProvider();480if (initialized == false) {481throw new IllegalStateException("MAC not initialized");482}483if (input != null) {484spi.engineUpdate(input, 0, input.length);485}486}487488/**489* Processes the first {@code len} bytes in {@code input},490* starting at {@code offset} inclusive.491*492* @param input the input buffer.493* @param offset the offset in {@code input} where the input starts.494* @param len the number of bytes to process.495*496* @exception IllegalStateException if this {@code Mac} has not been497* initialized.498*/499public final void update(byte[] input, int offset, int len)500throws IllegalStateException {501chooseFirstProvider();502if (initialized == false) {503throw new IllegalStateException("MAC not initialized");504}505506if (input != null) {507if ((offset < 0) || (len > (input.length - offset)) || (len < 0))508throw new IllegalArgumentException("Bad arguments");509spi.engineUpdate(input, offset, len);510}511}512513/**514* Processes {@code input.remaining()} bytes in the ByteBuffer515* {@code input}, starting at {@code input.position()}.516* Upon return, the buffer's position will be equal to its limit;517* its limit will not have changed.518*519* @param input the ByteBuffer520*521* @exception IllegalStateException if this {@code Mac} has not been522* initialized.523* @since 1.5524*/525public final void update(ByteBuffer input) {526chooseFirstProvider();527if (initialized == false) {528throw new IllegalStateException("MAC not initialized");529}530if (input == null) {531throw new IllegalArgumentException("Buffer must not be null");532}533spi.engineUpdate(input);534}535536/**537* Finishes the MAC operation.538*539* <p>A call to this method resets this {@code Mac} object to the540* state it was in when previously initialized via a call to541* {@code init(Key)} or542* {@code init(Key, AlgorithmParameterSpec)}.543* That is, the object is reset and available to generate another MAC from544* the same key, if desired, via new calls to {@code update} and545* {@code doFinal}.546* (In order to reuse this {@code Mac} object with a different key,547* it must be reinitialized via a call to {@code init(Key)} or548* {@code init(Key, AlgorithmParameterSpec)}.549*550* @return the MAC result.551*552* @exception IllegalStateException if this {@code Mac} has not been553* initialized.554*/555public final byte[] doFinal() throws IllegalStateException {556chooseFirstProvider();557if (initialized == false) {558throw new IllegalStateException("MAC not initialized");559}560byte[] mac = spi.engineDoFinal();561spi.engineReset();562return mac;563}564565/**566* Finishes the MAC operation.567*568* <p>A call to this method resets this {@code Mac} object to the569* state it was in when previously initialized via a call to570* {@code init(Key)} or571* {@code init(Key, AlgorithmParameterSpec)}.572* That is, the object is reset and available to generate another MAC from573* the same key, if desired, via new calls to {@code update} and574* {@code doFinal}.575* (In order to reuse this {@code Mac} object with a different key,576* it must be reinitialized via a call to {@code init(Key)} or577* {@code init(Key, AlgorithmParameterSpec)}.578*579* <p>The MAC result is stored in {@code output}, starting at580* {@code outOffset} inclusive.581*582* @param output the buffer where the MAC result is stored583* @param outOffset the offset in {@code output} where the MAC is584* stored585*586* @exception ShortBufferException if the given output buffer is too small587* to hold the result588* @exception IllegalStateException if this {@code Mac} has not been589* initialized.590*/591public final void doFinal(byte[] output, int outOffset)592throws ShortBufferException, IllegalStateException593{594chooseFirstProvider();595if (initialized == false) {596throw new IllegalStateException("MAC not initialized");597}598int macLen = getMacLength();599if (output == null || output.length-outOffset < macLen) {600throw new ShortBufferException601("Cannot store MAC in output buffer");602}603byte[] mac = doFinal();604System.arraycopy(mac, 0, output, outOffset, macLen);605return;606}607608/**609* Processes the given array of bytes and finishes the MAC operation.610*611* <p>A call to this method resets this {@code Mac} object to the612* state it was in when previously initialized via a call to613* {@code init(Key)} or614* {@code init(Key, AlgorithmParameterSpec)}.615* That is, the object is reset and available to generate another MAC from616* the same key, if desired, via new calls to {@code update} and617* {@code doFinal}.618* (In order to reuse this {@code Mac} object with a different key,619* it must be reinitialized via a call to {@code init(Key)} or620* {@code init(Key, AlgorithmParameterSpec)}.621*622* @param input data in bytes623* @return the MAC result.624*625* @exception IllegalStateException if this {@code Mac} has not been626* initialized.627*/628public final byte[] doFinal(byte[] input) throws IllegalStateException629{630chooseFirstProvider();631if (initialized == false) {632throw new IllegalStateException("MAC not initialized");633}634update(input);635return doFinal();636}637638/**639* Resets this {@code Mac} object.640*641* <p>A call to this method resets this {@code Mac} object to the642* state it was in when previously initialized via a call to643* {@code init(Key)} or644* {@code init(Key, AlgorithmParameterSpec)}.645* That is, the object is reset and available to generate another MAC from646* the same key, if desired, via new calls to {@code update} and647* {@code doFinal}.648* (In order to reuse this {@code Mac} object with a different key,649* it must be reinitialized via a call to {@code init(Key)} or650* {@code init(Key, AlgorithmParameterSpec)}.651*/652public final void reset() {653chooseFirstProvider();654spi.engineReset();655}656657/**658* Returns a clone if the provider implementation is cloneable.659*660* @return a clone if the provider implementation is cloneable.661*662* @exception CloneNotSupportedException if this is called on a663* delegate that does not support {@code Cloneable}.664*/665public final Object clone() throws CloneNotSupportedException {666chooseFirstProvider();667Mac that = (Mac)super.clone();668that.spi = (MacSpi)this.spi.clone();669return that;670}671}672673674