Quelle Mac.java
Sprache: JAVA
/*
* 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 .
*/
package javax.crypto;
import java.util.*;
import java.security.*;
import java.security.Provider.Service;
import java.security.spec.AlgorithmParameterSpec;
import java.nio.ByteBuffer;
import sun.security.util.Debug;
import sun.security.jca.*;
import sun.security.jca.GetInstance.Instance;
/**
* 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
*/
public class Mac implements Cloneable {
private static final Debug debug =
Debug.getInstance("jca" , "Mac" );
private static final Debug pdebug =
Debug.getInstance("provider" , "Provider" );
private static final boolean skipDebug =
Debug.isOn("engine=" ) && !Debug.isOn("mac" );
// The provider
private Provider provider;
// The provider implementation (delegate)
private MacSpi spi;
// The name of the MAC algorithm.
private final String algorithm;
// Has this object been initialized?
private boolean initialized = false ;
// next service to try in provider selection
// null once provider is selected
private Service firstService;
// remaining services to try in provider selection
// null once provider is selected
private Iterator<Service> serviceIterator;
private final Object lock;
/**
* Creates a MAC object .
*
* @ param macSpi the delegate
* @ param provider the provider
* @ param algorithm the algorithm
*/
protected Mac(MacSpi macSpi, Provider provider, String algorithm) {
this .spi = macSpi;
this .provider = provider;
this .algorithm = algorithm;
serviceIterator = null ;
lock = null ;
}
private Mac(Service s, Iterator<Service> t, String algorithm) {
firstService = s;
serviceIterator = t;
this .algorithm = algorithm;
lock = new Object();
}
/**
* 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 .
*/
public final String getAlgorithm() {
return this .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
*/
public static final 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 ;
}
return new Mac(s, t, algorithm);
}
throw new 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
*/
public static final Mac getInstance(String algorithm, String provider)
throws NoSuchAlgorithmException, NoSuchProviderException {
Objects.requireNonNull(algorithm, "null algorithm name" );
Instance instance = JceSecurity.getInstance
("Mac" , MacSpi.class , algorithm, provider);
return new 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
*/
public static final Mac getInstance(String algorithm, Provider provider)
throws NoSuchAlgorithmException {
Objects.requireNonNull(algorithm, "null algorithm name" );
Instance instance = JceSecurity.getInstance
("Mac" , MacSpi.class , algorithm, provider);
return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
}
// max number of debug warnings to print from chooseFirstProvider()
private static int 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;
}
}
private void 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)" ;
throw new 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 .
*/
public final Provider getProvider() {
chooseFirstProvider();
return this .provider;
}
/**
* Returns the length of the MAC in bytes .
*
* @ return the MAC length in bytes .
*/
public final int getMacLength() {
chooseFirstProvider();
return spi.engineGetMacLength();
}
private String getProviderName() {
return (provider == null ) ? "(no provider)" : provider.getName();
}
/**
* Initializes this { @ code Mac } object with the given key .
*
* @ param key the key .
*
* @ throws InvalidKeyException if the given key is inappropriate for
* initializing this MAC .
*/
public final void init(Key key) throws InvalidKeyException {
try {
if (spi != null ) {
spi.engineInit(key, null );
} else {
chooseProvider(key, null );
}
} catch (InvalidAlgorithmParameterException e) {
throw new InvalidKeyException("init() failed" , e);
}
initialized = true ;
if (!skipDebug && pdebug != null ) {
pdebug.println("Mac." + algorithm + " algorithm from: " +
getProviderName());
}
}
/**
* 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 .
*/
public final void init(Key key, AlgorithmParameterSpec params)
throws InvalidKeyException, InvalidAlgorithmParameterException {
if (spi != null ) {
spi.engineInit(key, params);
} else {
chooseProvider(key, params);
}
initialized = true ;
if (!skipDebug && pdebug != null ) {
pdebug.println("Mac." + algorithm + " algorithm from: " +
getProviderName());
}
}
/**
* Processes the given byte .
*
* @ param input the input byte to be processed .
*
* @ throws IllegalStateException if this { @ code Mac } has not been
* initialized .
*/
public final void update(byte input) throws IllegalStateException {
chooseFirstProvider();
if (!initialized) {
throw new 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 .
*/
public final void update(byte [] input) throws IllegalStateException {
chooseFirstProvider();
if (!initialized) {
throw new 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 .
*/
public final void update(byte [] input, int offset, int len)
throws IllegalStateException {
chooseFirstProvider();
if (!initialized) {
throw new IllegalStateException("MAC not initialized" );
}
if (input != null ) {
if ((offset < 0 ) || (len > (input.length - offset)) || (len < 0 ))
throw new IllegalArgumentException("Bad arguments" );
spi.engineUpdate(input, offset, len);
}
}
/**
* 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
*/
public final void update(ByteBuffer input) {
chooseFirstProvider();
if (!initialized) {
throw new IllegalStateException("MAC not initialized" );
}
if (input == null ) {
throw new 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 .
*/
public final byte [] doFinal() throws IllegalStateException {
chooseFirstProvider();
if (!initialized) {
throw new 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 .
*/
public final void doFinal(byte [] output, int outOffset)
throws ShortBufferException, IllegalStateException
{
chooseFirstProvider();
if (!initialized) {
throw new IllegalStateException("MAC not initialized" );
}
int macLen = getMacLength();
if (output == null || output.length-outOffset < macLen) {
throw new 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 .
*/
public final byte [] doFinal(byte [] input) throws IllegalStateException
{
chooseFirstProvider();
if (!initialized) {
throw new 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 ) } .
*/
public final void 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 } .
*/
public final Object clone() throws CloneNotSupportedException {
chooseFirstProvider();
Mac that = (Mac)super .clone();
that.spi = (MacSpi)this .spi.clone();
return that;
}
}
Messung V0.5 in Prozent C=95 H=89 G=91
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet am 2026-06-11)
¤
*© Formatika GbR, Deutschland
2026-07-09