071bd521bc
Reviewed-by: alanb, bchristi, dcubed, dfuchs, eosterlund, erikj, glaubitz, ihse, iignatyev, jjiang, kbarrett, ksrini, kvn, naoto, prr, rriggs, serb, sspitsyn, stefank, tschatzl, valeriep, weijun, weijun
345 lines
13 KiB
Java
345 lines
13 KiB
Java
/*
|
|
* Copyright (c) 2003, 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.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.PrintStream;
|
|
import java.security.DigestInputStream;
|
|
import java.security.DigestOutputStream;
|
|
import java.security.MessageDigest;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.security.Security;
|
|
import java.util.Arrays;
|
|
import java.util.Random;
|
|
import jdk.test.lib.RandomFactory;
|
|
import static java.lang.System.out;
|
|
|
|
/**
|
|
* @test
|
|
* @bug 8050370 8156059
|
|
* @summary MessageDigest tests with DigestIOStream
|
|
* @author Kevin Liu
|
|
* @key randomness
|
|
* @library /test/lib
|
|
* @build jdk.test.lib.RandomFactory
|
|
* @run main/timeout=180 TestDigestIOStream
|
|
*/
|
|
|
|
enum ReadModel {
|
|
READ, BUFFER_READ, MIX_READ
|
|
}
|
|
|
|
public class TestDigestIOStream {
|
|
|
|
private static final int[] DATA_LEN_ARRAY = { 1, 50, 2500, 125000,
|
|
6250000 };
|
|
private static final String[] ALGORITHM_ARRAY = { "MD2", "MD5", "SHA1",
|
|
"SHA-224", "SHA-256", "SHA-384", "SHA-512", "SHA3-224", "SHA3-256",
|
|
"SHA3-384", "SHA3-512" };
|
|
|
|
private static byte[] data;
|
|
|
|
private static MessageDigest md = null;
|
|
|
|
public static void main(String argv[]) throws Exception {
|
|
TestDigestIOStream test = new TestDigestIOStream();
|
|
test.run();
|
|
}
|
|
|
|
public void run() throws Exception {
|
|
for (String algorithm : ALGORITHM_ARRAY) {
|
|
md = MessageDigest.getInstance(algorithm);
|
|
for (int length : DATA_LEN_ARRAY) {
|
|
|
|
Random rdm = RandomFactory.getRandom();
|
|
data = new byte[length];
|
|
rdm.nextBytes(data);
|
|
|
|
if (!testMDChange(algorithm, length)) {
|
|
throw new RuntimeException("testMDChange failed at:"
|
|
+ algorithm + "/" + length);
|
|
}
|
|
if (!testMDShare(algorithm, length)) {
|
|
throw new RuntimeException("testMDShare failed at:"
|
|
+ algorithm + "/" + length);
|
|
}
|
|
for (ReadModel readModel : ReadModel.values()) {
|
|
// test Digest function when digest switch on
|
|
if (!testDigestOnOff(algorithm, readModel, true,
|
|
length)) {
|
|
throw new RuntimeException(
|
|
"testDigestOn failed at:" + algorithm + "/"
|
|
+ length + "/" + readModel);
|
|
}
|
|
// test Digest function when digest switch off
|
|
if (!testDigestOnOff(algorithm, readModel, false,
|
|
length)) {
|
|
throw new RuntimeException(
|
|
"testDigestOff failed at:" + algorithm + "/"
|
|
+ length + "/" + readModel);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
int testNumber = ALGORITHM_ARRAY.length * ReadModel.values().length
|
|
* DATA_LEN_ARRAY.length * 2
|
|
+ ALGORITHM_ARRAY.length * DATA_LEN_ARRAY.length * 2;
|
|
out.println("All " + testNumber + " Tests Passed");
|
|
}
|
|
|
|
/**
|
|
* Test DigestInputStream and DigestOutputStream digest function when digest
|
|
* set on and off
|
|
*
|
|
* @param algo
|
|
* Message Digest algorithm
|
|
* @param readModel
|
|
* which read method used(READ, BUFFER_READ, MIX_READ)
|
|
* @param on
|
|
* digest switch(on and off)
|
|
* @param dataLength
|
|
* plain test data length.
|
|
* @exception Exception
|
|
* throw unexpected exception
|
|
*/
|
|
public boolean testDigestOnOff(String algo, ReadModel readModel, boolean on,
|
|
int dataLength) throws Exception {
|
|
|
|
// Generate the DigestInputStream/DigestOutputStream object
|
|
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
|
DigestInputStream dis = new DigestInputStream(bais,
|
|
MessageDigest.getInstance(algo));
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
DigestOutputStream dos = new DigestOutputStream(baos,
|
|
MessageDigest.getInstance(algo));
|
|
ByteArrayOutputStream baOut = new ByteArrayOutputStream();) {
|
|
|
|
// Perform the update using all available/possible update methods
|
|
int k = 0;
|
|
byte[] buffer = new byte[5];
|
|
boolean enDigest = true;
|
|
// Make sure the digest function is on (default)
|
|
dis.on(enDigest);
|
|
dos.on(enDigest);
|
|
|
|
switch (readModel) {
|
|
case READ: // use only read()
|
|
while ((k = dis.read()) != -1) {
|
|
if (on) {
|
|
dos.write(k);
|
|
} else {
|
|
dos.write(k);
|
|
if (enDigest) {
|
|
baOut.write(k);
|
|
}
|
|
enDigest = !enDigest;
|
|
dos.on(enDigest);
|
|
dis.on(enDigest);
|
|
}
|
|
}
|
|
break;
|
|
case BUFFER_READ: // use only read(byte[], int, int)
|
|
while ((k = dis.read(buffer, 0, buffer.length)) != -1) {
|
|
if (on) {
|
|
dos.write(buffer, 0, k);
|
|
} else {
|
|
dos.write(buffer, 0, k);
|
|
if (enDigest) {
|
|
baOut.write(buffer, 0, k);
|
|
}
|
|
enDigest = !enDigest;
|
|
dis.on(enDigest);
|
|
dos.on(enDigest);
|
|
}
|
|
}
|
|
break;
|
|
case MIX_READ: // use both read() and read(byte[], int, int)
|
|
while ((k = dis.read()) != -1) {
|
|
if (on) {
|
|
dos.write(k);
|
|
if ((k = dis.read(buffer, 0, buffer.length)) != -1) {
|
|
dos.write(buffer, 0, k);
|
|
}
|
|
} else {
|
|
dos.write(k);
|
|
if (enDigest) {
|
|
baOut.write(k);
|
|
}
|
|
enDigest = !enDigest;
|
|
dis.on(enDigest);
|
|
dos.on(enDigest);
|
|
if ((k = dis.read(buffer, 0, buffer.length)) != -1) {
|
|
dos.write(buffer, 0, k);
|
|
if (enDigest) {
|
|
baOut.write(buffer, 0, k);
|
|
}
|
|
enDigest = !enDigest;
|
|
dis.on(enDigest);
|
|
dos.on(enDigest);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
out.println("ERROR: Invalid read/write combination choice!");
|
|
return false;
|
|
}
|
|
|
|
// Get the output and the "correct" digest values
|
|
byte[] output1 = dis.getMessageDigest().digest();
|
|
byte[] output2 = dos.getMessageDigest().digest();
|
|
byte[] standard;
|
|
if (on) {
|
|
standard = md.digest(data);
|
|
} else {
|
|
byte[] dataDigested = baOut.toByteArray();
|
|
standard = md.digest(dataDigested);
|
|
}
|
|
|
|
// Compare the output byte array value to the input data
|
|
if (!MessageDigest.isEqual(data, baos.toByteArray())) {
|
|
out.println("ERROR of " + readModel
|
|
+ ": output and input data unexpectedly changed");
|
|
return false;
|
|
}
|
|
// Compare generated digest values
|
|
if (!MessageDigest.isEqual(output1, standard)
|
|
|| !MessageDigest.isEqual(output2, standard)) {
|
|
out.println("ERROR" + readModel
|
|
+ ": generated digest data unexpectedly changed");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
} catch (Exception ex) {
|
|
out.println("testDigestOnOff failed at:" + algo + "/" + readModel
|
|
+ "/" + dataLength + " with unexpected exception");
|
|
throw ex;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test DigestInputStream and DigestOutputStream digest function when Swap
|
|
* the message digest engines between DigestIn/OutputStream
|
|
*
|
|
* @param algo
|
|
* Message Digest algorithm
|
|
* @param dataLength
|
|
* plain test data length.
|
|
* @exception Exception
|
|
* throw unexpected exception
|
|
*/
|
|
public boolean testMDChange(String algo, int dataLength) throws Exception {
|
|
// Generate the DigestInputStream/DigestOutputStream object
|
|
MessageDigest mdIn = MessageDigest.getInstance(algo);
|
|
MessageDigest mdOut = MessageDigest.getInstance(algo);
|
|
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
|
DigestInputStream dis = new DigestInputStream(bais, mdIn);
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
DigestOutputStream dos = new DigestOutputStream(baos, mdOut);) {
|
|
|
|
// Perform the update using all available/possible update methods
|
|
int k = 0;
|
|
byte[] buffer = new byte[10];
|
|
|
|
// use both read() and read(byte[], int, int)
|
|
while ((k = dis.read()) != -1) {
|
|
dos.write(k);
|
|
if ((k = dis.read(buffer, 0, buffer.length)) != -1) {
|
|
dos.write(buffer, 0, k);
|
|
}
|
|
|
|
// Swap the message digest engines between
|
|
// DigestIn/OutputStream objects
|
|
dis.setMessageDigest(mdOut);
|
|
dos.setMessageDigest(mdIn);
|
|
mdIn = dis.getMessageDigest();
|
|
mdOut = dos.getMessageDigest();
|
|
}
|
|
|
|
// Get the output and the "correct" digest values
|
|
byte[] output1 = mdIn.digest();
|
|
byte[] output2 = mdOut.digest();
|
|
byte[] standard = md.digest(data);
|
|
|
|
// Compare generated digest values
|
|
return MessageDigest.isEqual(output1, standard)
|
|
&& MessageDigest.isEqual(output2, standard);
|
|
} catch (Exception ex) {
|
|
out.println("testMDChange failed at:" + algo + "/" + dataLength
|
|
+ " with unexpected exception");
|
|
throw ex;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test DigestInputStream and DigestOutputStream digest function when use
|
|
* same message digest object.
|
|
*
|
|
* @param algo
|
|
* Message Digest algorithm
|
|
* @param dataLength
|
|
* plain test data length.
|
|
* @exception Exception
|
|
* throw unexpected exception
|
|
*/
|
|
public boolean testMDShare(String algo, int dataLength) throws Exception {
|
|
MessageDigest mdCommon = MessageDigest.getInstance(algo);
|
|
// Generate the DigestInputStream/DigestOutputStream object
|
|
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
|
DigestInputStream dis = new DigestInputStream(bais, mdCommon);
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
DigestOutputStream dos = new DigestOutputStream(baos,
|
|
mdCommon);) {
|
|
|
|
// Perform the update using all available/possible update methods
|
|
int k = 0;
|
|
byte[] buffer = new byte[10];
|
|
|
|
// use both read() and read(byte[], int, int)
|
|
while (k < data.length) {
|
|
int len = dis.read(buffer, 0, buffer.length);
|
|
if (len != -1) {
|
|
k += len;
|
|
if (k < data.length) {
|
|
dos.write(data[k]);
|
|
k++;
|
|
dis.skip(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the output and the "correct" digest values
|
|
byte[] output = mdCommon.digest();
|
|
byte[] standard = md.digest(data);
|
|
|
|
// Compare generated digest values
|
|
return MessageDigest.isEqual(output, standard);
|
|
} catch (Exception ex) {
|
|
out.println("TestMDShare failed at:" + algo + "/" + dataLength
|
|
+ " with unexpected exception");
|
|
throw ex;
|
|
}
|
|
}
|
|
}
|