/* * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
/** * This class provides the functionality of a "Message Authentication Code" * (MAC) algorithm. * * <p> A MAC provides a way to check * the integrity of information transmitted over or stored in an unreliable * medium, based on a secret key. Typically, message * authentication codes are used between two parties that share a secret * key in order to validate information transmitted between these * parties. * * <p> A MAC mechanism that is based on cryptographic hash functions is * referred to as HMAC. HMAC can be used with any cryptographic hash function, * e.g., SHA256 or SHA384, in combination with a secret shared key. HMAC is * specified in RFC 2104. * * <p> Every implementation of the Java platform is required to support * the following standard {@code Mac} algorithms: * <ul> * <li>{@code HmacSHA1}</li> * <li>{@code HmacSHA256}</li> * </ul> * These algorithms are described in the * <a href="{@docRoot}/../specs/security/standard-names.html#mac-algorithms"> * Mac section</a> of the * Java Security Standard Algorithm Names Specification. * Consult the release documentation for your implementation to see if any * other algorithms are supported. * * @author Jan Luehe * * @since 1.4
*/
/** * Returns the algorithm name of this {@code Mac} object. * * <p>This is the same name that was specified in one of the * {@code getInstance} calls that created this * {@code Mac} object. * * @return the algorithm name of this {@code Mac} object.
*/ publicfinal String getAlgorithm() { returnthis.algorithm;
}
/** * Returns a {@code Mac} object that implements the * specified MAC algorithm. * * <p> This method traverses the list of registered security providers, * starting with the most preferred provider. * A new {@code Mac} object encapsulating the * {@code MacSpi} implementation from the first * provider that supports the specified algorithm is returned. * * <p> Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote * The JDK Reference Implementation additionally uses the * {@code jdk.security.provider.preferred} * {@link Security#getProperty(String) Security} property to determine * the preferred provider order for the specified algorithm. This * may be different from the order of providers returned by * {@link Security#getProviders() Security.getProviders()}. * * @param algorithm the standard name of the requested MAC algorithm. * See the Mac section in the <a href= * "{@docRoot}/../specs/security/standard-names.html#mac-algorithms"> * Java Security Standard Algorithm Names Specification</a> * for information about standard algorithm names. * * @return the new {@code Mac} object * * @throws NoSuchAlgorithmException if no {@code Provider} supports a * {@code MacSpi} implementation for the specified algorithm * * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider
*/ publicstaticfinal Mac getInstance(String algorithm) throws NoSuchAlgorithmException {
Objects.requireNonNull(algorithm, "null algorithm name");
List<Service> services = GetInstance.getServices("Mac", algorithm); // make sure there is at least one service from a signed provider
Iterator<Service> t = services.iterator(); while (t.hasNext()) {
Service s = t.next(); if (!JceSecurity.canUseProvider(s.getProvider())) { continue;
} returnnew Mac(s, t, algorithm);
} thrownew NoSuchAlgorithmException
("Algorithm " + algorithm + " not available");
}
/** * Returns a {@code Mac} object that implements the * specified MAC algorithm. * * <p> A new {@code Mac} object encapsulating the * {@code MacSpi} implementation from the specified provider * is returned. The specified provider must be registered * in the security provider list. * * <p> Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * * @param algorithm the standard name of the requested MAC algorithm. * See the Mac section in the <a href= * "{@docRoot}/../specs/security/standard-names.html#mac-algorithms"> * Java Security Standard Algorithm Names Specification</a> * for information about standard algorithm names. * * @param provider the name of the provider. * * @return the new {@code Mac} object * * @throws IllegalArgumentException if the {@code provider} * is {@code null} or empty * * @throws NoSuchAlgorithmException if a {@code MacSpi} * implementation for the specified algorithm is not * available from the specified provider * * @throws NoSuchProviderException if the specified provider is not * registered in the security provider list * * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider
*/ publicstaticfinal Mac getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException {
Objects.requireNonNull(algorithm, "null algorithm name");
Instance instance = JceSecurity.getInstance
("Mac", MacSpi.class, algorithm, provider); returnnew Mac((MacSpi)instance.impl, instance.provider, algorithm);
}
/** * Returns a {@code Mac} object that implements the * specified MAC algorithm. * * <p> A new {@code Mac} object encapsulating the * {@code MacSpi} implementation from the specified provider * is returned. Note that the specified provider * does not have to be registered in the provider list. * * @param algorithm the standard name of the requested MAC algorithm. * See the Mac section in the <a href= * "{@docRoot}/../specs/security/standard-names.html#mac-algorithms"> * Java Security Standard Algorithm Names Specification</a> * for information about standard algorithm names. * * @param provider the provider. * * @return the new {@code Mac} object * * @throws IllegalArgumentException if the {@code provider} is * {@code null} * * @throws NoSuchAlgorithmException if a {@code MacSpi} * implementation for the specified algorithm is not available * from the specified {@code Provider} object * * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider
*/ publicstaticfinal Mac getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException {
Objects.requireNonNull(algorithm, "null algorithm name");
Instance instance = JceSecurity.getInstance
("Mac", MacSpi.class, algorithm, provider); returnnew Mac((MacSpi)instance.impl, instance.provider, algorithm);
}
// max number of debug warnings to print from chooseFirstProvider() privatestaticint warnCount = 10;
/** * Choose the Spi from the first provider available. Used if * delayed provider selection is not possible because init() * is not the first method called.
*/ void chooseFirstProvider() { if ((spi != null) || (serviceIterator == null)) { return;
} synchronized (lock) { if (spi != null) { return;
} if (debug != null) { int w = --warnCount; if (w >= 0) {
debug.println("Mac.init() not first method "
+ "called, disabling delayed provider selection"); if (w == 0) {
debug.println("Further warnings of this type will "
+ "be suppressed");
} new Exception("Call trace").printStackTrace();
}
}
Exception lastException = null; while ((firstService != null) || serviceIterator.hasNext()) {
Service s; if (firstService != null) {
s = firstService;
firstService = null;
} else {
s = serviceIterator.next();
} if (!JceSecurity.canUseProvider(s.getProvider())) { continue;
} try {
Object obj = s.newInstance(null); if (!(obj instanceof MacSpi)) { continue;
}
spi = (MacSpi)obj;
provider = s.getProvider(); // not needed any more
firstService = null;
serviceIterator = null; return;
} catch (NoSuchAlgorithmException e) {
lastException = e;
}
}
ProviderException e = new ProviderException
("Could not construct MacSpi instance"); if (lastException != null) {
e.initCause(lastException);
} throw e;
}
}
privatevoid chooseProvider(Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException { synchronized (lock) { if (spi != null) {
spi.engineInit(key, params); return;
}
Exception lastException = null; while ((firstService != null) || serviceIterator.hasNext()) {
Service s; if (firstService != null) {
s = firstService;
firstService = null;
} else {
s = serviceIterator.next();
} // if provider says it does not support this key, ignore it if (!s.supportsParameter(key)) { continue;
} if (!JceSecurity.canUseProvider(s.getProvider())) { continue;
} try {
MacSpi spi = (MacSpi)s.newInstance(null);
spi.engineInit(key, params);
provider = s.getProvider(); this.spi = spi;
firstService = null;
serviceIterator = null; return;
} catch (Exception e) { // NoSuchAlgorithmException from newInstance() // InvalidKeyException from init() // RuntimeException (ProviderException) from init() if (lastException == null) {
lastException = e;
}
}
} // no working provider found, fail if (lastException instanceof InvalidKeyException) { throw (InvalidKeyException)lastException;
} if (lastException instanceof InvalidAlgorithmParameterException) { throw (InvalidAlgorithmParameterException)lastException;
} if (lastException instanceof RuntimeException) { throw (RuntimeException)lastException;
}
String kName = (key != null) ? key.getClass().getName() : "(null)"; thrownew InvalidKeyException
("No installed provider supports this key: "
+ kName, lastException);
}
}
/** * Returns the provider of this {@code Mac} object. * * @return the provider of this {@code Mac} object.
*/ publicfinal Provider getProvider() {
chooseFirstProvider(); returnthis.provider;
}
/** * Returns the length of the MAC in bytes. * * @return the MAC length in bytes.
*/ publicfinalint getMacLength() {
chooseFirstProvider(); return spi.engineGetMacLength();
}
/** * Initializes this {@code Mac} object with the given key and * algorithm parameters. * * @param key the key. * @param params the algorithm parameters. * * @throws InvalidKeyException if the given key is inappropriate for * initializing this MAC. * @throws InvalidAlgorithmParameterException if the given algorithm * parameters are inappropriate for this MAC.
*/ publicfinalvoid init(Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException { if (spi != null) {
spi.engineInit(key, params);
} else {
chooseProvider(key, params);
}
initialized = true;
/** * Processes the given byte. * * @param input the input byte to be processed. * * @throws IllegalStateException if this {@code Mac} has not been * initialized.
*/ publicfinalvoid update(byte input) throws IllegalStateException {
chooseFirstProvider(); if (!initialized) { thrownew IllegalStateException("MAC not initialized");
}
spi.engineUpdate(input);
}
/** * Processes the given array of bytes. * * @param input the array of bytes to be processed. * * @throws IllegalStateException if this {@code Mac} has not been * initialized.
*/ publicfinalvoid update(byte[] input) throws IllegalStateException {
chooseFirstProvider(); if (!initialized) { thrownew IllegalStateException("MAC not initialized");
} if (input != null) {
spi.engineUpdate(input, 0, input.length);
}
}
/** * Processes the first {@code len} bytes in {@code input}, * starting at {@code offset} inclusive. * * @param input the input buffer. * @param offset the offset in {@code input} where the input starts. * @param len the number of bytes to process. * * @throws IllegalStateException if this {@code Mac} has not been * initialized.
*/ publicfinalvoid update(byte[] input, int offset, int len) throws IllegalStateException {
chooseFirstProvider(); if (!initialized) { thrownew IllegalStateException("MAC not initialized");
}
/** * Processes {@code input.remaining()} bytes in the ByteBuffer * {@code input}, starting at {@code input.position()}. * Upon return, the buffer's position will be equal to its limit; * its limit will not have changed. * * @param input the ByteBuffer * * @throws IllegalStateException if this {@code Mac} has not been * initialized. * @throws IllegalArgumentException if {@code input} is null * @since 1.5
*/ publicfinalvoid update(ByteBuffer input) {
chooseFirstProvider(); if (!initialized) { thrownew IllegalStateException("MAC not initialized");
} if (input == null) { thrownew IllegalArgumentException("Buffer must not be null");
}
spi.engineUpdate(input);
}
/** * Finishes the MAC operation. * * <p>A call to this method resets this {@code Mac} object to the * state it was in when previously initialized via a call to * {@code init(Key)} or * {@code init(Key, AlgorithmParameterSpec)}. * That is, the object is reset and available to generate another MAC from * the same key, if desired, via new calls to {@code update} and * {@code doFinal}. * (In order to reuse this {@code Mac} object with a different key, * it must be reinitialized via a call to {@code init(Key)} or * {@code init(Key, AlgorithmParameterSpec)}. * * @return the MAC result. * * @throws IllegalStateException if this {@code Mac} has not been * initialized.
*/ publicfinalbyte[] doFinal() throws IllegalStateException {
chooseFirstProvider(); if (!initialized) { thrownew IllegalStateException("MAC not initialized");
} byte[] mac = spi.engineDoFinal();
spi.engineReset(); return mac;
}
/** * Finishes the MAC operation. * * <p>A call to this method resets this {@code Mac} object to the * state it was in when previously initialized via a call to * {@code init(Key)} or * {@code init(Key, AlgorithmParameterSpec)}. * That is, the object is reset and available to generate another MAC from * the same key, if desired, via new calls to {@code update} and * {@code doFinal}. * (In order to reuse this {@code Mac} object with a different key, * it must be reinitialized via a call to {@code init(Key)} or * {@code init(Key, AlgorithmParameterSpec)}. * * <p>The MAC result is stored in {@code output}, starting at * {@code outOffset} inclusive. * * @param output the buffer where the MAC result is stored * @param outOffset the offset in {@code output} where the MAC is * stored * * @throws ShortBufferException if the given output buffer is too small * to hold the result * @throws IllegalStateException if this {@code Mac} has not been * initialized.
*/ publicfinalvoid doFinal(byte[] output, int outOffset) throws ShortBufferException, IllegalStateException
{
chooseFirstProvider(); if (!initialized) { thrownew IllegalStateException("MAC not initialized");
} int macLen = getMacLength(); if (output == null || output.length-outOffset < macLen) { thrownew ShortBufferException
("Cannot store MAC in output buffer");
} byte[] mac = doFinal();
System.arraycopy(mac, 0, output, outOffset, macLen);
}
/** * Processes the given array of bytes and finishes the MAC operation. * * <p>A call to this method resets this {@code Mac} object to the * state it was in when previously initialized via a call to * {@code init(Key)} or * {@code init(Key, AlgorithmParameterSpec)}. * That is, the object is reset and available to generate another MAC from * the same key, if desired, via new calls to {@code update} and * {@code doFinal}. * (In order to reuse this {@code Mac} object with a different key, * it must be reinitialized via a call to {@code init(Key)} or * {@code init(Key, AlgorithmParameterSpec)}. * * @param input data in bytes * @return the MAC result. * * @throws IllegalStateException if this {@code Mac} has not been * initialized.
*/ publicfinalbyte[] doFinal(byte[] input) throws IllegalStateException
{
chooseFirstProvider(); if (!initialized) { thrownew IllegalStateException("MAC not initialized");
}
update(input); return doFinal();
}
/** * Resets this {@code Mac} object. * * <p>A call to this method resets this {@code Mac} object to the * state it was in when previously initialized via a call to * {@code init(Key)} or * {@code init(Key, AlgorithmParameterSpec)}. * That is, the object is reset and available to generate another MAC from * the same key, if desired, via new calls to {@code update} and * {@code doFinal}. * (In order to reuse this {@code Mac} object with a different key, * it must be reinitialized via a call to {@code init(Key)} or * {@code init(Key, AlgorithmParameterSpec)}.
*/ publicfinalvoid reset() {
chooseFirstProvider();
spi.engineReset();
}
/** * Returns a clone if the provider implementation is cloneable. * * @return a clone if the provider implementation is cloneable. * * @throws CloneNotSupportedException if this is called on a * delegate that does not support {@code Cloneable}.
*/ publicfinal Object clone() throws CloneNotSupportedException {
chooseFirstProvider();
Mac that = (Mac)super.clone();
that.spi = (MacSpi)this.spi.clone(); return that;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.