All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jasypt.digest.StandardStringDigester Maven / Gradle / Ivy

There is a newer version: 6.1.2
Show newest version
/*
 * =============================================================================
 * 
 *   Copyright (c) 2007-2010, The JASYPT team (http://www.jasypt.org)
 * 
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 * 
 * =============================================================================
 */
package org.jasypt.digest;

import java.security.Provider;

import org.jasypt.commons.CommonUtils;
import org.jasypt.contrib.org.apache.commons.codec_1_3.binary.Base64;
import org.jasypt.digest.config.DigesterConfig;
import org.jasypt.digest.config.StringDigesterConfig;
import org.jasypt.exceptions.AlreadyInitializedException;
import org.jasypt.exceptions.EncryptionInitializationException;
import org.jasypt.exceptions.EncryptionOperationNotPossibleException;
import org.jasypt.normalization.Normalizer;
import org.jasypt.salt.SaltGenerator;


/**
 * 

* Standard implementation of the {@link StringDigester} interface. * This class lets the user specify the algorithm (and provider) to be used for * creating digests, the size of the salt to be applied, * the number of times the hash function will be applied (iterations) and * the salt generator to be used. *

*

* This class avoids byte-conversion problems related to the fact of * different platforms having different default charsets, and returns * digests in the form of BASE64-encoded or HEXADECIMAL ASCII Strings. *

*

* This class is thread-safe. *

*

*
Configuration *

*

* The algorithm, provider, salt size, iterations and salt generator can take values * in any of these ways: *

    *
  • Using its default values.
  • *
  • Setting a {@link org.jasypt.digest.config.DigesterConfig} * object which provides new * configuration values.
  • *
  • Calling the corresponding setX(...) methods.
  • *
* And the actual values to be used for initialization will be established * by applying the following priorities: *
    *
  1. First, the default values are considered.
  2. *
  3. Then, if a {@link org.jasypt.digest.config.DigesterConfig} * object has been set with * setConfig, the non-null values returned by its * getX methods override the default values.
  4. *
  5. Finally, if the corresponding setX method has been called * on the digester itself for any of the configuration parameters, the * values set by these calls override all of the above.
  6. *
*

* *

*
Initialization *

*

* Before it is ready to create digests, an object of this class has to be * initialized. Initialization happens: *

    *
  • When initialize is called.
  • *
  • When digest or matches are called for the * first time, if initialize has not been called before.
  • *
* Once a digester has been initialized, trying to * change its configuration * will result in an AlreadyInitializedException being thrown. *

* *

*
Usage *

*

* A digester may be used in two different ways: *

    *
  • For creating digests, by calling the digest method.
  • *
  • For matching digests, this is, checking whether a digest * corresponds adequately to a digest (as in password checking) or not, by * calling the matches method.
  • *
* The steps taken for creating digests are: *
    *
  1. The String message is converted to a byte array.
  2. *
  3. A salt of the specified size is generated (see * {@link org.jasypt.salt.SaltGenerator}).
  4. *
  5. The salt bytes are added to the message.
  6. *
  7. The hash function is applied to the salt and message altogether, * and then to the * results of the function itself, as many times as specified * (iterations).
  8. *
  9. If specified by the salt generator (see * {@link org.jasypt.salt.SaltGenerator#includePlainSaltInEncryptionResults()}), * the undigested salt and the final result of the hash * function are concatenated and returned as a result.
  10. *
  11. The result of the concatenation is encoded in BASE64 or HEXADECIMAL * and returned as an ASCII String.
  12. *
* Put schematically in bytes: *
    *
  • * DIGEST = |S|..(ssb)..|S|X|X|X|...|X| *
      *
    • S: salt bytes (plain, not digested). (OPTIONAL).
    • *
    • ssb: salt size in bytes.
    • *
    • X: bytes resulting from hashing (see below).
    • *
    *
  • *
  • * |X|X|X|...|X| = * H(H(H(..(it)..H(Z|Z|Z|...|Z|)))) *
      *
    • H: Hash function (algorithm).
    • *
    • it: Number of iterations.
    • *
    • Z: Input for hashing (see below).
    • *
    *
  • *
  • * |Z|Z|Z|...|Z| = * |S|..(ssb)..|S|M|M|M...|M| *
      *
    • S: salt bytes (plain, not digested).
    • *
    • ssb: salt size in bytes.
    • *
    • M: message bytes.
    • *
    *
  • *
* If a random salt generator is used, two digests created for the same * message will always be different * (except in the case of random salt coincidence). * Because of this, in this case the result of the digest method * will contain both the undigested salt and the digest of the * (salt + message), so that another digest operation can be performed * with the same salt on a different message to check if both messages * match (all of which will be managed automatically by the * matches method). *

*

* To learn more about the mechanisms involved in digest creation, read * PKCS #5: Password-Based Cryptography Standard. *

* * @since 1.0 * * @author Daniel Fernández * */ public final class StandardStringDigester implements StringDigester { /** *

* Charset to be used to obtain "digestable" byte arrays from input Strings. * Set to UTF-8. *

*

* This charset has to be fixed to some value so that we avoid problems * with different platforms having different "default" charsets. *

*

* It is set to UTF-8 because it covers the whole spectrum of characters * representable in Java (which internally uses UTF-16), and avoids the * size penalty of UTF-16 (which will always use two bytes for representing * each character, even if it is an ASCII one). *

*

* Setting this value to UTF-8 does not mean that Strings that originally * come for, for example, an ISO-8859-1 input, will not be correcly * digested. It simply provides a way of "fixing" the way a String will * be converted into bytes for digesting. *

*/ public static final String MESSAGE_CHARSET = "UTF-8"; /** *

* Charset to be used for encoding the resulting digests. * Set to US-ASCII. *

*

* The result of digesting some bytes can be any other bytes, and so * the result of digesting, for example, some LATIN-1 valid String bytes, * can be bytes that may not conform a "valid" LATIN-1 String. *

*

* Because of this, digests are always encoded in BASE64 or * HEXADECIMAL after * being created, and this ensures that the * digests will make perfectly representable, safe ASCII Strings. Because * of this, the charset used to convert the digest bytes to the returned * String is set to US-ASCII. *

*/ public static final String DIGEST_CHARSET = "US-ASCII"; /** *

* Whether the Unicode normalization step should be ignored because of * legacy-compatibility issues. Defaults to FALSE (the normalization * step WILL be performed). *

*/ public static final boolean DEFAULT_UNICODE_NORMALIZATION_IGNORED = false; /** *

* Default type of String output. Set to BASE64. *

*/ public static final String DEFAULT_STRING_OUTPUT_TYPE = CommonUtils.STRING_OUTPUT_TYPE_BASE64; // The StandardByteDigester that will be internally used. private final StandardByteDigester byteDigester; // If the config object set is a StringDigesterConfig, it must be referenced private StringDigesterConfig stringDigesterConfig = null; // This variable holds whether the unicode normalization step should // be ignored or not (default = DO NOT ignore). private boolean unicodeNormalizationIgnored = DEFAULT_UNICODE_NORMALIZATION_IGNORED; // This variable holds the type of String output which will be done, // and also a boolean variable for faster comparison private String stringOutputType = DEFAULT_STRING_OUTPUT_TYPE; private boolean stringOutputTypeBase64 = true; // Prefix and suffix to be added to encryption results (if any) private String prefix = null; private String suffix = null; /* * Set of booleans which indicate whether the config or default values * have to be overriden because of the setX methods having been * called. */ private boolean unicodeNormalizationIgnoredSet = false; private boolean stringOutputTypeSet = false; private boolean prefixSet = false; private boolean suffixSet = false; // BASE64 encoder which will make sure the returned digests are // valid US-ASCII strings (if the user chooses BASE64 output). // The Bsae64 encoder is THREAD-SAFE private final Base64 base64; /** * Creates a new instance of StandardStringDigester. */ public StandardStringDigester() { super(); this.byteDigester = new StandardByteDigester(); this.base64 = new Base64(); } /* * Creates a new instance of StandardStringDigester using * the specified byte digester (constructor used for cloning) */ private StandardStringDigester(final StandardByteDigester standardByteDigester) { super(); this.byteDigester = standardByteDigester; this.base64 = new Base64(); } /** *

* Sets a {@link org.jasypt.digest.config.DigesterConfig} * or {@link StringDigesterConfig} object * for the digester. If this config * object is set, it will be asked values for: *

* *
    *
  • Algorithm
  • *
  • Security Provider (or provider name)
  • *
  • Salt size
  • *
  • Hashing iterations
  • *
  • Salt generator
  • *
  • Use of Unicode normalization mechanisms * (only StringDigesterConfig)
  • *
  • Output type (base64, hexadecimal) * (only StringDigesterConfig)
  • *
* *

* The non-null values it returns will override the default ones, * and will be overriden by any values specified with a setX * method. *

* * @param config the DigesterConfig object to be used as the * source for configuration parameters. */ public synchronized void setConfig(final DigesterConfig config) { this.byteDigester.setConfig(config); if ((config != null) && (config instanceof StringDigesterConfig)) { this.stringDigesterConfig = (StringDigesterConfig) config; } } /** *

* Sets the algorithm to be used for digesting, like MD5 * or SHA-1. *

*

* This algorithm has to be supported by your security infrastructure, and * it should be allowed as an algorithm for creating * java.security.MessageDigest instances. *

*

* If you are specifying a security provider with {@link #setProvider(Provider)} or * {@link #setProviderName(String)}, this algorithm should be * supported by your specified provider. *

*

* If you are not specifying a provider, you will be able to use those * algorithms provided by the default security provider of your JVM vendor. * For valid names in the Sun JVM, see Java * Cryptography Architecture API Specification & * Reference. *

* * @param algorithm the name of the algorithm to be used. */ public void setAlgorithm(final String algorithm) { this.byteDigester.setAlgorithm(algorithm); } /** *

* Sets the size of the salt to be used to compute the digest. * This mechanism is explained in * PKCS #5: Password-Based Cryptography Standard. *

* *

* If salt size is set to zero, then no salt will be used. *

* * @param saltSizeBytes the size of the salt to be used, in bytes. */ public void setSaltSizeBytes(final int saltSizeBytes) { this.byteDigester.setSaltSizeBytes(saltSizeBytes); } /** *

* Set the number of times the hash function will be applied recursively. *
* The hash function will be applied to its own results as many times as * specified: h(h(...h(x)...)) *

*

* This mechanism is explained in * PKCS #5: Password-Based Cryptography Standard. *

* * @param iterations the number of iterations. */ public void setIterations(final int iterations) { this.byteDigester.setIterations(iterations); } /** *

* Sets the salt generator to be used. If no salt generator is specified, * an instance of {@link org.jasypt.salt.RandomSaltGenerator} will be used. *

* * @param saltGenerator the salt generator to be used. */ public void setSaltGenerator(final SaltGenerator saltGenerator) { this.byteDigester.setSaltGenerator(saltGenerator); } /** *

* Sets the name of the security provider to be asked for the * digest algorithm. This security provider has to be registered beforehand * at the JVM security framework. *

*

* The provider can also be set with the {@link #setProvider(Provider)} * method, in which case it will not be necessary neither registering * the provider beforehand, * nor calling this {@link #setProviderName(String)} method to specify * a provider name. *

*

* Note that a call to {@link #setProvider(Provider)} overrides any value * set by this method. *

*

* If no provider name / provider is explicitly set, the default JVM * provider will be used. *

* * @since 1.3 * * @param providerName the name of the security provider to be asked * for the digest algorithm. */ public void setProviderName(final String providerName) { this.byteDigester.setProviderName(providerName); } /** *

* Sets the security provider to be asked for the digest algorithm. * The provider does not have to be registered at the security * infrastructure beforehand, and its being used here will not result in * its being registered. *

*

* If this method is called, calling {@link #setProviderName(String)} * becomes unnecessary. *

*

* If no provider name / provider is explicitly set, the default JVM * provider will be used. *

* * @since 1.3 * * @param provider the provider to be asked for the chosen algorithm */ public void setProvider(final Provider provider) { this.byteDigester.setProvider(provider); } /** *

* Whether the salt bytes are to be appended after the * message ones before performing the digest operation on the whole. The * default behaviour is to insert those bytes before the message bytes, but * setting this configuration item to true allows compatibility * with some external systems and specifications (e.g. LDAP {SSHA}). *

*

* If this parameter is not explicitly set, the default behaviour * (insertion of salt before message) will be applied. *

* * @since 1.7 * * @param invertPositionOfSaltInMessageBeforeDigesting * whether salt will be appended after the message before applying * the digest operation on the whole, instead of inserted before it * (which is the default). */ public synchronized void setInvertPositionOfSaltInMessageBeforeDigesting( final boolean invertPositionOfSaltInMessageBeforeDigesting) { this.byteDigester.setInvertPositionOfSaltInMessageBeforeDigesting(invertPositionOfSaltInMessageBeforeDigesting); } /** *

* Whether the plain (not hashed) salt bytes are to * be appended after the digest operation result bytes. The default behaviour is * to insert them before the digest result, but setting this configuration * item to true allows compatibility with some external systems * and specifications (e.g. LDAP {SSHA}). *

*

* If this parameter is not explicitly set, the default behaviour * (insertion of plain salt before digest result) will be applied. *

* * @since 1.7 * * @param invertPositionOfPlainSaltInEncryptionResults * whether plain salt will be appended after the digest operation * result instead of inserted before it (which is the * default). */ public synchronized void setInvertPositionOfPlainSaltInEncryptionResults( final boolean invertPositionOfPlainSaltInEncryptionResults) { this.byteDigester.setInvertPositionOfPlainSaltInEncryptionResults(invertPositionOfPlainSaltInEncryptionResults); } /** *

* Whether digest matching operations will allow matching * digests with a salt size different to the one configured in the "saltSizeBytes" * property. This is possible because digest algorithms will produce a fixed-size * result, so the remaining bytes from the hashed input will be considered salt. *

*

* This will allow the digester to match digests produced in environments which do not * establish a fixed salt size as standard (for example, SSHA password encryption * in LDAP systems). *

*

* The value of this property will not affect the creation of digests, * which will always have a salt of the size established by the "saltSizeBytes" * property. It will only affect digest matching. *

*

* Setting this property to true is not compatible with {@link SaltGenerator} * implementations which return false for their * {@link SaltGenerator#includePlainSaltInEncryptionResults()} property. *

*

* Also, be aware that some algorithms or algorithm providers might not support * knowing the size of the digests beforehand, which is also incompatible with * a lenient behaviour. *

*

* If this parameter is not explicitly set, the default behaviour * (NOT lenient) will be applied. *

* * @since 1.7 * * @param useLenientSaltSizeCheck whether the digester will allow matching of * digests with different salt sizes than established or not (default * is false). */ public synchronized void setUseLenientSaltSizeCheck(final boolean useLenientSaltSizeCheck) { this.byteDigester.setUseLenientSaltSizeCheck(useLenientSaltSizeCheck); } /** *

* Sets whether the unicode text normalization step should be ignored. *

*

* The Java Virtual Machine internally handles all Strings as UNICODE. When * digesting or matching digests in jasypt, these Strings are first * normalized to * its NFC form so that digest matching is not affected by the specific * form in which the messages where input. *

*

* It is normally safe (and recommended) to leave this parameter set to * its default FALSE value (and thus DO perform normalization * operations). But in some specific cases in which issues with legacy * software could arise, it might be useful to set this to TRUE. *

*

* For more information on unicode text normalization, see this issue of * Core Java Technologies Tech Tips. *

* * @since 1.3 * * @param unicodeNormalizationIgnored whether the unicode text * normalization step should be ignored or not. */ public synchronized void setUnicodeNormalizationIgnored(final boolean unicodeNormalizationIgnored) { if (isInitialized()) { throw new AlreadyInitializedException(); } this.unicodeNormalizationIgnored = unicodeNormalizationIgnored; this.unicodeNormalizationIgnoredSet = true; } /** *

* Sets the the form in which String output * will be encoded. Available encoding types are: *

*
    *
  • base64 (default)
  • *
  • hexadecimal
  • *
*

* If not set, null will be returned. *

* * @since 1.3 * * @param stringOutputType the string output type. */ public synchronized void setStringOutputType(final String stringOutputType) { CommonUtils.validateNotEmpty(stringOutputType, "String output type cannot be set empty"); if (isInitialized()) { throw new AlreadyInitializedException(); } this.stringOutputType = CommonUtils. getStandardStringOutputType(stringOutputType); this.stringOutputTypeSet = true; } /** *

* Sets the prefix to be added at the beginning of encryption results, and also to * be expected at the beginning of plain messages provided for matching operations * (raising an {@link EncryptionOperationNotPossibleException} if not). *

*

* By default, no prefix will be added to encryption results. *

* * @since 1.7 * * @param prefix the prefix to be set */ public synchronized void setPrefix(final String prefix) { if (isInitialized()) { throw new AlreadyInitializedException(); } this.prefix = prefix; this.prefixSet = true; } /** *

* Sets the suffix to be added at the end of encryption results, and also to * be expected at the end of plain messages provided for matching operations * (raising an {@link EncryptionOperationNotPossibleException} if not). *

*

* By default, no suffix will be added to encryption results. *

* * @since 1.7 * * @param suffix the suffix to be set */ public synchronized void setSuffix(final String suffix) { if (isInitialized()) { throw new AlreadyInitializedException(); } this.suffix = suffix; this.suffixSet = true; } /* * Clone this digester. */ StandardStringDigester cloneDigester() { // Check initialization if (!isInitialized()) { initialize(); } final StandardStringDigester cloned = new StandardStringDigester(this.byteDigester.cloneDigester()); cloned.setPrefix(this.prefix); cloned.setSuffix(this.suffix); if (CommonUtils.isNotEmpty(this.stringOutputType)) { cloned.setStringOutputType(this.stringOutputType); } cloned.setUnicodeNormalizationIgnored(this.unicodeNormalizationIgnored); return cloned; } /** *

* Returns true if the digester has already been initialized, false if * not.
* Initialization happens: *

*
    *
  • When initialize is called.
  • *
  • When digest or matches are called for the * first time, if initialize has not been called before.
  • *
*

* Once a digester has been initialized, trying to * change its configuration will result in an * AlreadyInitializedException * being thrown. *

* * @return true if the digester has already been initialized, false if * not. */ public boolean isInitialized() { return this.byteDigester.isInitialized(); } /** *

* Initialize the digester. *

*

* This operation will consist in determining the actual configuration * values to be used, and then initializing the digester with them. *
* These values are decided by applying the following priorities: *

*
    *
  1. First, the default values are considered.
  2. *
  3. Then, if a * {@link org.jasypt.digest.config.DigesterConfig} object * has been set with * setConfig, the non-null values returned by its * getX methods override the default values.
  4. *
  5. Finally, if the corresponding setX method has been called * on the digester itself for any of the configuration parameters, the * values set by these calls override all of the above.
  6. *
*

* Once a digester has been initialized, trying to * change its configuration will result in an * AlreadyInitializedException * being thrown. *

* * @throws EncryptionInitializationException if initialization could not * be correctly done (for example, if the digest algorithm chosen * cannot be used). * */ public synchronized void initialize() { // Double-check to avoid synchronization issues if (!this.isInitialized()) { /* * If a StringDigesterConfig object has been set, we need to * consider the values it returns (if, for each value, the * corresponding "setX" method has not been called). */ if (this.stringDigesterConfig != null) { final Boolean configUnicodeNormalizationIgnored = this.stringDigesterConfig.isUnicodeNormalizationIgnored(); final String configStringOutputType = this.stringDigesterConfig.getStringOutputType(); final String configPrefix = this.stringDigesterConfig.getPrefix(); final String configSuffix = this.stringDigesterConfig.getSuffix(); this.unicodeNormalizationIgnored = ((this.unicodeNormalizationIgnoredSet) || (configUnicodeNormalizationIgnored == null))? this.unicodeNormalizationIgnored : configUnicodeNormalizationIgnored.booleanValue(); this.stringOutputType = ((this.stringOutputTypeSet) || (configStringOutputType == null))? this.stringOutputType : configStringOutputType; this.prefix = ((this.prefixSet) || (configPrefix == null))? this.prefix : configPrefix; this.suffix = ((this.suffixSet) || (configSuffix == null))? this.suffix : configSuffix; } this.stringOutputTypeBase64 = (CommonUtils.STRING_OUTPUT_TYPE_BASE64. equalsIgnoreCase(this.stringOutputType)); this.byteDigester.initialize(); } } /** *

* Performs a digest operation on a String message. *

*

* The steps taken for creating the digest are: *

    *
  1. The String message is converted to a byte array.
  2. *
  3. A salt of the specified size is generated (see * {@link org.jasypt.salt.SaltGenerator}).
  4. *
  5. The salt bytes are added to the message.
  6. *
  7. The hash function is applied to the salt and message altogether, * and then to the * results of the function itself, as many times as specified * (iterations).
  8. *
  9. If specified by the salt generator (see * {@link org.jasypt.salt.SaltGenerator#includePlainSaltInEncryptionResults()}), * the undigested salt and the final result of the hash * function are concatenated and returned as a result.
  10. *
  11. The result of the concatenation is encoded in BASE64 (default) * or HEXADECIMAL * and returned as an ASCII String.
  12. *
* Put schematically in bytes: *
    *
  • * DIGEST = |S|..(ssb)..|S|X|X|X|...|X| *
      *
    • S: salt bytes (plain, not digested). (OPTIONAL).
    • *
    • ssb: salt size in bytes.
    • *
    • X: bytes resulting from hashing (see below).
    • *
    *
  • *
  • * |X|X|X|...|X| = * H(H(H(..(it)..H(Z|Z|Z|...|Z|)))) *
      *
    • H: Hash function (algorithm).
    • *
    • it: Number of iterations.
    • *
    • Z: Input for hashing (see below).
    • *
    *
  • *
  • * |Z|Z|Z|...|Z| = * |S|..(ssb)..|S|M|M|M...|M| *
      *
    • S: salt bytes (plain, not digested).
    • *
    • ssb: salt size in bytes.
    • *
    • M: message bytes.
    • *
    *
  • *
*

*

* If a random salt generator is used, two digests created for the same * message will always be different * (except in the case of random salt coincidence). * Because of this, in this case the result of the digest method * will contain both the undigested salt and the digest of the * (salt + message), so that another digest operation can be performed * with the same salt on a different message to check if both messages * match (all of which will be managed automatically by the * matches method). *

* * @param message the String to be digested * @return the digest result * @throws EncryptionOperationNotPossibleException if the digest operation * fails, ommitting any further information about the cause for * security reasons. * @throws EncryptionInitializationException if initialization could not * be correctly done (for example, if the digest algorithm chosen * cannot be used). */ public String digest(final String message) { if (message == null) { return null; } // Check initialization if (!isInitialized()) { initialize(); } try { // Normalize Unicode message to NFC form String normalizedMessage = null; if (! this.unicodeNormalizationIgnored) { normalizedMessage = Normalizer.normalizeToNfc(message); } else { normalizedMessage = message; } // The input String is converted into bytes using MESSAGE_CHARSET // as a fixed charset to avoid problems with different platforms // having different default charsets (see MESSAGE_CHARSET doc). final byte[] messageBytes = normalizedMessage.getBytes(MESSAGE_CHARSET); // The StandardByteDigester does its job. byte[] digest = this.byteDigester.digest(messageBytes); // We build the result variable final StringBuffer result = new StringBuffer(); if (this.prefix != null) { // Prefix is added result.append(this.prefix); } // We encode the result in BASE64 or HEXADECIMAL so that we obtain // the safest result String possible. if (this.stringOutputTypeBase64) { digest = this.base64.encode(digest); result.append(new String(digest, DIGEST_CHARSET)); } else { result.append(CommonUtils.toHexadecimal(digest)); } if (this.suffix != null) { // Suffix is added result.append(this.suffix); } return result.toString(); } catch (EncryptionInitializationException e) { throw e; } catch (EncryptionOperationNotPossibleException e) { throw e; } catch (Exception e) { // If digest fails, it is more secure not to return any information // about the cause in nested exceptions. Simply fail. throw new EncryptionOperationNotPossibleException(); } } /** *

* Checks a message against a given digest. *

*

* This method tells whether a message corresponds to a specific digest * or not by getting the salt with which the digest was created and * applying it to a digest operation performed on the message. If * new and existing digest match, the message is said to match the digest. *

*

* This method will be used, for instance, for password checking in * authentication processes. *

*

* A null message will only match a null digest. *

* * @param message the message to be compared to the digest. * @param digest the digest. * @return true if the specified message matches the digest, false * if not. * @throws EncryptionOperationNotPossibleException if the digest matching * operation fails, ommitting any further information about the * cause for security reasons. * @throws EncryptionInitializationException if initialization could not * be correctly done (for example, if the digest algorithm chosen * cannot be used). */ public boolean matches(final String message, final String digest) { String processedDigest = digest; if (processedDigest != null) { if (this.prefix != null) { if (!processedDigest.startsWith(this.prefix)) { throw new EncryptionOperationNotPossibleException( "Digest does not start with required prefix \"" + this.prefix + "\""); } processedDigest = processedDigest.substring(this.prefix.length()); } if (this.suffix != null) { if (!processedDigest.endsWith(this.suffix)) { throw new EncryptionOperationNotPossibleException( "Digest does not end with required suffix \"" + this.suffix + "\""); } processedDigest = processedDigest.substring(0, processedDigest.length() - this.suffix.length()); } } if (message == null) { return (processedDigest == null); } else if (processedDigest == null) { return false; } // Check initialization if (!isInitialized()) { initialize(); } try { // Normalize Unicode message to NFC form String normalizedMessage = null; if (! this.unicodeNormalizationIgnored) { normalizedMessage = Normalizer.normalizeToNfc(message); } else { normalizedMessage = message; } // We get a valid byte array from the message, in the // fixed MESSAGE_CHARSET that the digest operations use. final byte[] messageBytes = normalizedMessage.getBytes(MESSAGE_CHARSET); // The BASE64 or HEXADECIMAL encoding is reversed and the digest // is converted into a byte array. byte[] digestBytes = null; if (this.stringOutputTypeBase64) { // The digest must be a US-ASCII String BASE64-encoded digestBytes = processedDigest.getBytes(DIGEST_CHARSET); digestBytes = this.base64.decode(digestBytes); } else { digestBytes = CommonUtils.fromHexadecimal(processedDigest); } // The StandardByteDigester is asked to match message to digest. return this.byteDigester.matches(messageBytes, digestBytes); } catch (EncryptionInitializationException e) { throw e; } catch (EncryptionOperationNotPossibleException e) { throw e; } catch (Exception e) { // If digest fails, it is more secure not to return any information // about the cause in nested exceptions. Simply fail. throw new EncryptionOperationNotPossibleException(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy