/* * Copyright (c) 1996, 2020, 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 java.security; import java.util.*; import java.lang.*; import java.io.IOException; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.io.InputStream; import java.io.ByteArrayInputStream; import java.nio.ByteBuffer; import sun.security.jca.Providers; import javax.crypto.SecretKey; /** * This MessageDigest class provides applications the functionality of a * message digest algorithm, such as SHA-1 or SHA-256. * Message digests are secure one-way hash functions that take arbitrary-sized * data and output a fixed-length hash value. * *
A MessageDigest object starts out initialized. The data is * processed through it using the {@link #update(byte) update} * methods. At any point {@link #reset() reset} can be called * to reset the digest. Once all the data to be updated has been * updated, one of the {@link #digest() digest} methods should * be called to complete the hash computation. * *
The {@code digest} method can be called once for a given number * of updates. After {@code digest} has been called, the MessageDigest * object is reset to its initialized state. * *
Implementations are free to implement the Cloneable interface. * Client applications can test cloneability by attempting cloning * and catching the CloneNotSupportedException: * *
{@code * MessageDigest md = MessageDigest.getInstance("SHA-256"); * * try { * md.update(toChapter1); * MessageDigest tc1 = md.clone(); * byte[] toChapter1Digest = tc1.digest(); * md.update(toChapter2); * ...etc. * } catch (CloneNotSupportedException cnse) { * throw new DigestException("couldn't make digest of partial content"); * } * }* *
Note that if a given implementation is not cloneable, it is * still possible to compute intermediate digests by instantiating * several instances, if the number of digests is known in advance. * *
Note that this class is abstract and extends from * {@code MessageDigestSpi} for historical reasons. * Application developers should only take notice of the methods defined in * this {@code MessageDigest} class; all the methods in * the superclass are intended for cryptographic service providers who wish to * supply their own implementations of message digest algorithms. * *
Android provides the following MessageDigest
algorithms:
*
Algorithm | *Supported API Levels | *
---|---|
MD5 | *1+ | *
SHA-1 | *1+ | *
SHA-224 | *1-8,22+ | *
SHA-256 | *1+ | *
SHA-384 | *1+ | *
SHA-512 | *1+ | *
This method traverses the list of registered security Providers, * starting with the most preferred Provider. * A new MessageDigest object encapsulating the * MessageDigestSpi implementation from the first * Provider that supports the specified algorithm is returned. * *
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 than the order of providers returned by * {@link Security#getProviders() Security.getProviders()}. * * @param algorithm the name of the algorithm requested. * See the MessageDigest section in the * Java Security Standard Algorithm Names Specification * for information about standard algorithm names. * * @return a {@code MessageDigest} object that implements the * specified algorithm * * @throws NoSuchAlgorithmException if no {@code Provider} supports a * {@code MessageDigestSpi} implementation for the * specified algorithm * * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider */ public static MessageDigest getInstance(String algorithm) throws NoSuchAlgorithmException { Objects.requireNonNull(algorithm, "null algorithm name"); try { MessageDigest md; Object[] objs = Security.getImpl(algorithm, "MessageDigest", (String)null); if (objs[0] instanceof MessageDigest) { md = (MessageDigest)objs[0]; } else { md = new Delegate((MessageDigestSpi)objs[0], algorithm); } md.provider = (Provider)objs[1]; // Android-removed: this debugging mechanism is not used in Android. /* if (!skipDebug && pdebug != null) { pdebug.println("MessageDigest." + algorithm + " algorithm from: " + md.provider.getName()); } */ return md; } catch(NoSuchProviderException e) { throw new NoSuchAlgorithmException(algorithm + " not found"); } } /** * Returns a MessageDigest object that implements the specified digest * algorithm. * *
A new MessageDigest object encapsulating the * MessageDigestSpi implementation from the specified provider * is returned. The specified provider must be registered * in the security provider list. * *
Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * * @param algorithm the name of the algorithm requested. * See the MessageDigest section in the * Java Security Standard Algorithm Names Specification * for information about standard algorithm names. * * @param provider the name of the provider. * * @return a {@code MessageDigest} object that implements the * specified algorithm * * @throws IllegalArgumentException if the provider name is {@code null} * or empty * * @throws NoSuchAlgorithmException if a {@code MessageDigestSpi} * 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 Provider */ public static MessageDigest getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { Objects.requireNonNull(algorithm, "null algorithm name"); if (provider == null || provider.isEmpty()) throw new IllegalArgumentException("missing provider"); // Android-added: Check for Bouncy Castle deprecation Providers.checkBouncyCastleDeprecation(provider, "MessageDigest", algorithm); Object[] objs = Security.getImpl(algorithm, "MessageDigest", provider); if (objs[0] instanceof MessageDigest) { MessageDigest md = (MessageDigest)objs[0]; md.provider = (Provider)objs[1]; return md; } else { MessageDigest delegate = new Delegate((MessageDigestSpi)objs[0], algorithm); delegate.provider = (Provider)objs[1]; return delegate; } } /** * Returns a MessageDigest object that implements the specified digest * algorithm. * *
A new MessageDigest object encapsulating the
* MessageDigestSpi implementation from the specified Provider
* object is returned. Note that the specified Provider object
* does not have to be registered in the provider list.
*
* @param algorithm the name of the algorithm requested.
* See the MessageDigest section in the
* Java Security Standard Algorithm Names Specification
* for information about standard algorithm names.
*
* @param provider the provider.
*
* @return a {@code MessageDigest} object that implements the
* specified algorithm
*
* @throws IllegalArgumentException if the specified provider is
* {@code null}
*
* @throws NoSuchAlgorithmException if a {@code MessageDigestSpi}
* implementation for the specified algorithm is not available
* from the specified {@code Provider} object
*
* @throws NullPointerException if {@code algorithm} is {@code null}
*
* @see Provider
*
* @since 1.4
*/
public static MessageDigest getInstance(String algorithm,
Provider provider)
throws NoSuchAlgorithmException
{
Objects.requireNonNull(algorithm, "null algorithm name");
if (provider == null)
throw new IllegalArgumentException("missing provider");
// Android-added: Check for Bouncy Castle deprecation
Providers.checkBouncyCastleDeprecation(provider, "MessageDigest", algorithm);
Object[] objs = Security.getImpl(algorithm, "MessageDigest", provider);
if (objs[0] instanceof MessageDigest) {
MessageDigest md = (MessageDigest)objs[0];
md.provider = (Provider)objs[1];
return md;
} else {
MessageDigest delegate =
new Delegate((MessageDigestSpi)objs[0], algorithm);
delegate.provider = (Provider)objs[1];
return delegate;
}
}
/**
* Returns the provider of this message digest object.
*
* @return the provider of this message digest object
*/
public final Provider getProvider() {
return this.provider;
}
/**
* Updates the digest using the specified byte.
*
* @param input the byte with which to update the digest.
*/
public void update(byte input) {
engineUpdate(input);
state = IN_PROGRESS;
}
/**
* Updates the digest using the specified array of bytes, starting
* at the specified offset.
*
* @param input the array of bytes.
*
* @param offset the offset to start from in the array of bytes.
*
* @param len the number of bytes to use, starting at
* {@code offset}.
*/
public void update(byte[] input, int offset, int len) {
if (input == null) {
throw new IllegalArgumentException("No input buffer given");
}
if (input.length - offset < len) {
throw new IllegalArgumentException("Input buffer too short");
}
engineUpdate(input, offset, len);
state = IN_PROGRESS;
}
/**
* Updates the digest using the specified array of bytes.
*
* @param input the array of bytes.
*/
public void update(byte[] input) {
engineUpdate(input, 0, input.length);
state = IN_PROGRESS;
}
/**
* Update the digest using the specified ByteBuffer. The digest is
* updated using the {@code input.remaining()} bytes 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
* @since 1.5
*/
public final void update(ByteBuffer input) {
if (input == null) {
throw new NullPointerException();
}
engineUpdate(input);
state = IN_PROGRESS;
}
/**
* Completes the hash computation by performing final operations
* such as padding. The digest is reset after this call is made.
*
* @return the array of bytes for the resulting hash value.
*/
public byte[] digest() {
/* Resetting is the responsibility of implementors. */
byte[] result = engineDigest();
state = INITIAL;
return result;
}
/**
* Completes the hash computation by performing final operations
* such as padding. The digest is reset after this call is made.
*
* @param buf output buffer for the computed digest
*
* @param offset offset into the output buffer to begin storing the digest
*
* @param len number of bytes within buf allotted for the digest
*
* @return the number of bytes placed into {@code buf}
*
* @exception DigestException if an error occurs.
*/
public int digest(byte[] buf, int offset, int len) throws DigestException {
if (buf == null) {
throw new IllegalArgumentException("No output buffer given");
}
if (buf.length - offset < len) {
throw new IllegalArgumentException
("Output buffer too small for specified offset and length");
}
int numBytes = engineDigest(buf, offset, len);
state = INITIAL;
return numBytes;
}
/**
* Performs a final update on the digest using the specified array
* of bytes, then completes the digest computation. That is, this
* method first calls {@link #update(byte[]) update(input)},
* passing the input array to the {@code update} method,
* then calls {@link #digest() digest()}.
*
* @param input the input to be updated before the digest is
* completed.
*
* @return the array of bytes for the resulting hash value.
*/
public byte[] digest(byte[] input) {
update(input);
return digest();
}
private String getProviderName() {
return (provider == null) ? "(no provider)" : provider.getName();
}
/**
* Returns a string representation of this message digest object.
*/
public String toString() {
// BEGIN Android-changed: Use StringBuilder instead of a ByteArrayOutputStream.
StringBuilder builder = new StringBuilder();
builder.append(algorithm);
builder.append(" Message Digest from ");
builder.append(getProviderName());
builder.append(", ");
switch (state) {
case INITIAL:
builder.append("