blob: 46028e85af840ab4067b2e51067638798435f735 [file] [log] [blame]
/*
* Copyright (c) 2003, 2014, 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.util.Arrays;
import java.util.Random;
import static java.lang.System.out;
/**
* @test
* @bug 8050370
* @summary MessageDigest tests with DigestIOStream
* @author Kevin Liu
*/
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"
};
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 = new Random();
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;
}
}
}