Skip to content

Commit

Permalink
Add digest convenience methods
Browse files Browse the repository at this point in the history
Updated the CryptoHelper class to add convenience methods for
generating cryptographic message digests from byte arrays, strings,
and files.  Specific methods are provided for the SHA-256, SHA-384,
and SHA-512 digest algorithms, as well as more general methods in
which you must specify the desired algorithm.
  • Loading branch information
dirmgr committed Jan 5, 2024
1 parent 14f6731 commit 5c30c87
Show file tree
Hide file tree
Showing 3 changed files with 370 additions and 0 deletions.
8 changes: 8 additions & 0 deletions docs/release-notes.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ <h3>Version 7.0.0</h3>
related requests to the same backend server.
<br><br>
</li>

<li>
Updated the CryptoHelper class to add convenience methods for generating
cryptographic message digests from byte arrays, strings, and files. Specific
methods are provided for the SHA-256, SHA-384, and SHA-512 digest algorithms, as
well as more general methods in which you must specify the desired algorithm.
<br><br>
</li>
</ul>

<p></p>
Expand Down
284 changes: 284 additions & 0 deletions src/com/unboundid/util/CryptoHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -2676,4 +2676,288 @@ else if (providerName.equals(BouncyCastleFIPSHelper.JSSE_PROVIDER_NAME))
return provider;
}
}



/**
* Generates a digest of the provided bytes using the specified algorithm.
*
* @param digestAlgorithm The name of the algorithm to use to generate the
* digest. It must not be {@code null}.
* @param dataToDigest The bytes for which to generate the digest. It
* must not be {@code null} but may be empty.
*
* @return The bytes that comprise the digest of the provided bytes.
*
* @throws NoSuchAlgorithmException If the JVM does not support the
* requested digest algorithm.
*/
@NotNull()
public static byte[] digest(@NotNull final String digestAlgorithm,
@NotNull final byte[] dataToDigest)
throws NoSuchAlgorithmException
{
final MessageDigest digest = getMessageDigest(digestAlgorithm);
return digest.digest(dataToDigest);
}



/**
* Generates a digest of the UTF-8 representation of the provided string
* using the specified algorithm.
*
* @param digestAlgorithm The name of the algorithm to use to generate the
* digest. It must not be {@code null}.
* @param dataToDigest The string for which to generate the digest. It
* must not be {@code null} but may be empty.
*
* @return The bytes that comprise the digest of the provided string.
*
* @throws NoSuchAlgorithmException If the JVM does not support the
* requested digest algorithm.
*/
@NotNull()
public static byte[] digest(@NotNull final String digestAlgorithm,
@NotNull final String dataToDigest)
throws NoSuchAlgorithmException
{
final MessageDigest digest = getMessageDigest(digestAlgorithm);
return digest.digest(StaticUtils.getBytes(dataToDigest));
}



/**
* Generates a digest of the contents of the provided file using the specified
* algorithm.
*
* @param digestAlgorithm The name of the algorithm to use to generate the
* digest. It must not be {@code null}.
* @param fileToDigest The file for which to generate the digest. It
* must not be {@code null}, and the file must exist.
*
* @return The bytes that comprise the digest of the provided file.
*
* @throws NoSuchAlgorithmException If the JVM does not support the
* requested digest algorithm.
*
* @throws java.io.IOException If a problem occurs while trying to read from
* the file.
*/
@NotNull()
public static byte[] digest(@NotNull final String digestAlgorithm,
@NotNull final File fileToDigest)
throws NoSuchAlgorithmException, java.io.IOException
{
try (FileInputStream inputStream = new FileInputStream(fileToDigest))
{
final MessageDigest digest = getMessageDigest(digestAlgorithm);
final byte[] buffer = new byte[1048576];
while (true)
{
final int bytesRead = inputStream.read(buffer);
if (bytesRead < 0)
{
return digest.digest();
}
else
{
digest.update(buffer, 0, bytesRead);
}
}
}
}



/**
* Generates a SHA-256 digest of the provided bytes.
*
* @param dataToDigest The bytes for which to generate the digest. It must
* not be {@code null} but may be empty.
*
* @return The bytes that comprise the SHA-256 digest of the provided bytes.
*
* @throws NoSuchAlgorithmException If the JVM does not support the SHA-256
* digest algorithm.
*/
@NotNull()
public static byte[] sha256(@NotNull final byte[] dataToDigest)
throws NoSuchAlgorithmException
{
return CryptoHelper.digest("SHA-256", dataToDigest);
}



/**
* Generates a SHA-256 digest of the UTF-8 representation of the provided
* string.
*
* @param dataToDigest The string for which to generate the digest. It must
* not be {@code null} but may be empty.
*
* @return The bytes that comprise the SHA-256 digest of the provided string.
*
* @throws NoSuchAlgorithmException If the JVM does not support the SHA-256
* digest algorithm.
*/
@NotNull()
public static byte[] sha256(@NotNull final String dataToDigest)
throws NoSuchAlgorithmException
{
return CryptoHelper.digest("SHA-256", dataToDigest);
}



/**
* Generates a SHA-256 digest of the contents of the provided file.
*
* @param fileToDigest The file for which to generate the digest. It must
* not be {@code null}, and the file must exist.
*
* @return The bytes that comprise the SHA-256 digest of the provided file.
*
* @throws NoSuchAlgorithmException If the JVM does not support the SHA-256
* digest algorithm.
*
* @throws java.io.IOException If a problem occurs while trying to read from
* the file.
*/
@NotNull()
public static byte[] sha256(@NotNull final File fileToDigest)
throws NoSuchAlgorithmException, java.io.IOException
{
return CryptoHelper.digest("SHA-256", fileToDigest);
}



/**
* Generates a SHA-384 digest of the provided bytes.
*
* @param dataToDigest The bytes for which to generate the digest. It must
* not be {@code null} but may be empty.
*
* @return The bytes that comprise the SHA-384 digest of the provided bytes.
*
* @throws NoSuchAlgorithmException If the JVM does not support the SHA-384
* digest algorithm.
*/
@NotNull()
public static byte[] sha384(@NotNull final byte[] dataToDigest)
throws NoSuchAlgorithmException
{
return CryptoHelper.digest("SHA-384", dataToDigest);
}



/**
* Generates a SHA-384 digest of the UTF-8 representation of the provided
* string.
*
* @param dataToDigest The string for which to generate the digest. It must
* not be {@code null} but may be empty.
*
* @return The bytes that comprise the SHA-384 digest of the provided string.
*
* @throws NoSuchAlgorithmException If the JVM does not support the SHA-384
* digest algorithm.
*/
@NotNull()
public static byte[] sha384(@NotNull final String dataToDigest)
throws NoSuchAlgorithmException
{
return CryptoHelper.digest("SHA-384", dataToDigest);
}



/**
* Generates a SHA-384 digest of the contents of the provided file.
*
* @param fileToDigest The file for which to generate the digest. It must
* not be {@code null}, and the file must exist.
*
* @return The bytes that comprise the SHA-384 digest of the provided file.
*
* @throws NoSuchAlgorithmException If the JVM does not support the SHA-384
* digest algorithm.
*
* @throws java.io.IOException If a problem occurs while trying to read from
* the file.
*/
@NotNull()
public static byte[] sha384(@NotNull final File fileToDigest)
throws NoSuchAlgorithmException, java.io.IOException
{
return CryptoHelper.digest("SHA-384", fileToDigest);
}



/**
* Generates a SHA-512 digest of the provided bytes.
*
* @param dataToDigest The bytes for which to generate the digest. It must
* not be {@code null} but may be empty.
*
* @return The bytes that comprise the SHA-512 digest of the provided bytes.
*
* @throws NoSuchAlgorithmException If the JVM does not support the SHA-512
* digest algorithm.
*/
@NotNull()
public static byte[] sha512(@NotNull final byte[] dataToDigest)
throws NoSuchAlgorithmException
{
return CryptoHelper.digest("SHA-512", dataToDigest);
}



/**
* Generates a SHA-512 digest of the UTF-8 representation of the provided
* string.
*
* @param dataToDigest The string for which to generate the digest. It must
* not be {@code null} but may be empty.
*
* @return The bytes that comprise the SHA-512 digest of the provided string.
*
* @throws NoSuchAlgorithmException If the JVM does not support the SHA-512
* digest algorithm.
*/
@NotNull()
public static byte[] sha512(@NotNull final String dataToDigest)
throws NoSuchAlgorithmException
{
return CryptoHelper.digest("SHA-512", dataToDigest);
}



/**
* Generates a SHA-512 digest of the contents of the provided file.
*
* @param fileToDigest The file for which to generate the digest. It must
* not be {@code null}, and the file must exist.
*
* @return The bytes that comprise the SHA-512 digest of the provided file.
*
* @throws NoSuchAlgorithmException If the JVM does not support the SHA-512
* digest algorithm.
*
* @throws java.io.IOException If a problem occurs while trying to read from
* the file.
*/
@NotNull()
public static byte[] sha512(@NotNull final File fileToDigest)
throws NoSuchAlgorithmException, java.io.IOException
{
return CryptoHelper.digest("SHA-512", fileToDigest);
}
}
78 changes: 78 additions & 0 deletions tests/unit/src/com/unboundid/util/CryptoHelperTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import com.unboundid.asn1.ASN1Boolean;
Expand Down Expand Up @@ -1931,4 +1932,81 @@ public void testInferKeyStoreTypeNotValidSequence()
// This was expected.
}
}



/**
* Provides test coverage for the convenience methods that can be used to
* generate message digests.
*
* @param stringToDigest The string to digest.
* @param expectedSHA256 The expected SHA-256 digest for the given string.
* @param expectedSHA384 The expected SHA-384 digest for the given string.
* @param expectedSHA512 The expected SHA-512 digest for the given string.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test(dataProvider = "digestConvenienceMethodsTestData")
public void testDigestConvenienceMethods(final String stringToDigest,
final byte[] expectedSHA256,
final byte[] expectedSHA384,
final byte[] expectedSHA512)
throws Exception
{
assertEquals(CryptoHelper.sha256(stringToDigest), expectedSHA256);
assertEquals(CryptoHelper.sha384(stringToDigest), expectedSHA384);
assertEquals(CryptoHelper.sha512(stringToDigest), expectedSHA512);

final byte[] b = StaticUtils.getBytes(stringToDigest);
assertEquals(CryptoHelper.sha256(b), expectedSHA256);
assertEquals(CryptoHelper.sha384(b), expectedSHA384);
assertEquals(CryptoHelper.sha512(b), expectedSHA512);

final File f = createTempFile();
StaticUtils.writeFile(f, b);
assertEquals(CryptoHelper.sha256(f), expectedSHA256);
assertEquals(CryptoHelper.sha384(f), expectedSHA384);
assertEquals(CryptoHelper.sha512(f), expectedSHA512);
}



/**
* Retrieves a set of data to use when testing digest convenience methods.
*
* @return A set of data to use when testing digest convenience methods.
*
* @throws Exception If an unexpected problem occurs.
*/
@DataProvider(name="digestConvenienceMethodsTestData")
public Object[][] getDigestConvenienceMethodsTestData()
throws Exception
{
return new Object[][]
{
new Object[]
{
"",
StaticUtils.fromHex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934c" +
"a495991b7852b855"),
StaticUtils.fromHex("38b060a751ac96384cd9327eb1b1e36a21fdb71114be0743" +
"4c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"),
StaticUtils.fromHex("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc" +
"83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a8" +
"1a538327af927da3e")
},

new Object[]
{
"abc",
StaticUtils.fromHex("ba7816bf8f01cfea414140de5dae2223b00361a396177a9c" +
"b410ff61f20015ad"),
StaticUtils.fromHex("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded163" +
"1a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"),
StaticUtils.fromHex("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea2" +
"0a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80" +
"e2a9ac94fa54ca49f")
},
};
}
}

0 comments on commit 5c30c87

Please sign in to comment.