| /* |
| * Copyright (c) 2015, 2017, 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 static java.lang.System.out; |
| import java.nio.ByteBuffer; |
| import java.security.DigestException; |
| import java.security.MessageDigest; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.Security; |
| import jdk.test.lib.RandomFactory; |
| |
| /** |
| * @test |
| * @bug 8050371 8156059 |
| * @summary Check md.digest(data) value whether same with digest output value |
| * with various update/digest methods. |
| * @author Kevin Liu |
| * @key randomness |
| * @library /test/lib |
| * @build jdk.test.lib.RandomFactory |
| * @run main TestSameValue |
| */ |
| |
| public class TestSameValue { |
| |
| public static void main(String[] args) throws Exception { |
| TestSameValue test1 = new TestSameValue(); |
| test1.run(); |
| } |
| |
| private void run() throws Exception { |
| |
| byte[] data = new byte[6706]; |
| MessageDigest md = null; |
| // Initialize input data |
| RandomFactory.getRandom().nextBytes(data); |
| |
| String[] algorithmArr = { "SHA", "Sha", "MD5", "md5", "SHA-224", |
| "SHA-256", "SHA-384", "SHA-512", "SHA3-224", "SHA3-256", |
| "SHA3-384", "SHA3-512" }; |
| |
| for (String algorithm : algorithmArr) { |
| try { |
| md = MessageDigest.getInstance(algorithm); |
| |
| for (UpdateDigestMethod updateMethod : UpdateDigestMethod |
| .values()) { |
| byte[] output = updateMethod.updateDigest(data, md); |
| // Get the output and the "correct" one |
| byte[] standard = md.digest(data); |
| // Compare input and output |
| if (!MessageDigest.isEqual(output, standard)) { |
| throw new RuntimeException( |
| "Test failed at algorithm/provider/numUpdate:" |
| + algorithm + "/" + md.getProvider() |
| + "/" + updateMethod); |
| } |
| } |
| } catch (NoSuchAlgorithmException nae) { |
| if (algorithm.startsWith("SHA3") && !isSHA3supported()) { |
| continue; |
| } else { |
| throw nae; |
| } |
| } |
| } |
| |
| out.println("All " |
| + algorithmArr.length * UpdateDigestMethod.values().length |
| + " tests Passed"); |
| } |
| |
| // SHA-3 hash algorithms are only supported by "SUN" provider |
| // and "OracleUcrypto" provider on Solaris 12.0 or later |
| // This method checks if system supports SHA-3 |
| private boolean isSHA3supported() { |
| if (Security.getProvider("SUN") != null) { |
| return true; |
| } |
| if (Security.getProvider("OracleUcrypto") != null |
| && "SunOS".equals(System.getProperty("os.name")) |
| && System.getProperty("os.version").compareTo("5.12") >= 0) { |
| return true; |
| } |
| return false; |
| } |
| |
| private static enum UpdateDigestMethod { |
| |
| /* |
| * update the data one by one using method update(byte input) then do |
| * digest (giving the output buffer, offset, and the number of bytes to |
| * put in the output buffer) |
| */ |
| UPDATE_DIGEST_BUFFER { |
| @Override |
| public byte[] updateDigest(byte[] data, MessageDigest md) |
| throws DigestException { |
| for (byte element : data) { |
| md.update(element); |
| } |
| byte[] output = new byte[md.getDigestLength()]; |
| int len = md.digest(output, 0, output.length); |
| if (len != output.length) { |
| throw new RuntimeException( |
| "ERROR" + ": digest length differs!"); |
| } |
| return output; |
| } |
| }, |
| |
| /* |
| * update the data one by one using method update(byte input) then do |
| * digest |
| */ |
| UPDATE_DIGEST { |
| @Override |
| public byte[] updateDigest(byte[] data, MessageDigest md) { |
| for (byte element : data) { |
| md.update(element); |
| } |
| return md.digest(); |
| } |
| }, |
| |
| /* |
| * update all the data at once as a block, then do digest ( giving the |
| * output buffer, offset, and the number of bytes to put in the output |
| * buffer) |
| */ |
| UPDATE_BLOCK_DIGEST_BUFFER { |
| @Override |
| public byte[] updateDigest(byte[] data, MessageDigest md) |
| throws DigestException { |
| md.update(data); |
| byte[] output = new byte[md.getDigestLength()]; |
| int len = md.digest(output, 0, output.length); |
| if (len != output.length) { |
| throw new RuntimeException( |
| "ERROR" + ": digest length differs!"); |
| } |
| return output; |
| } |
| }, |
| |
| // update all the data at once as a block, then do digest |
| UPDATE_BLOCK_DIGEST { |
| @Override |
| public byte[] updateDigest(byte[] data, MessageDigest md) { |
| md.update(data); |
| return md.digest(); |
| } |
| }, |
| |
| /* |
| * update the leading bytes (length is "data.length-LASTNBYTES") at once |
| * as a block, then do digest (do a final update using the left |
| * LASTNBYTES bytes which is passed as a parameter for the digest |
| * method, then complete the digest) |
| */ |
| UPDATE_LEADING_BLOCK_DIGEST_REMAIN { |
| @Override |
| public byte[] updateDigest(byte[] data, MessageDigest md) { |
| byte[] mainPart = new byte[data.length - LASTNBYTES]; |
| for (int i = 0; i < mainPart.length; i++) { |
| mainPart[i] = data[i]; |
| } |
| for (int j = 0; j < LASTNBYTES; j++) { |
| REMAIN[j] = data[data.length - LASTNBYTES + j]; |
| } |
| md.update(mainPart); |
| return md.digest(REMAIN); |
| } |
| }, |
| |
| /* |
| * update the data 2 bytes each time, after finishing updating, do |
| * digest (giving the output buffer, offset, and the number of bytes to |
| * put in the output buffer) |
| */ |
| UPDATE_BYTES_DIGEST_BUFFER { |
| @Override |
| public byte[] updateDigest(byte[] data, MessageDigest md) |
| throws DigestException { |
| |
| for (int i = 0; i < data.length / 2; i++) { |
| md.update(data, i * 2, 2); |
| } |
| byte[] output = new byte[md.getDigestLength()]; |
| int len = md.digest(output, 0, output.length); |
| if (len != output.length) { |
| throw new RuntimeException( |
| "ERROR" + ": digest length differs!"); |
| } |
| return output; |
| } |
| }, |
| |
| /* |
| * update the data 2 bytes each time, after finishing updating, do |
| * digest |
| */ |
| UPDATE_BYTES_DIGEST { |
| @Override |
| public byte[] updateDigest(byte[] data, MessageDigest md) { |
| for (int i = 0; i < data.length / 2; i++) { |
| md.update(data, i * 2, 2); |
| } |
| return md.digest(); |
| } |
| }, |
| |
| /* |
| * update the data one by one using method update(byte[] input, int |
| * offset, int len) for the leading bytes (length is |
| * "data.length-LASTNBYTES"), then do digest (do a final update using |
| * the left LASTNBYTES bytes which is passed as a parameter for digest |
| * method then complete the digest) |
| */ |
| UPDATE_BUFFER_LEADING_DIGEST_REMAIN { |
| @Override |
| public byte[] updateDigest(byte[] data, MessageDigest md) { |
| for (int i = 0; i < data.length - LASTNBYTES; i++) { |
| md.update(data, i, 1); |
| } |
| for (int j = 0; j < LASTNBYTES; j++) { |
| REMAIN[j] = data[data.length - LASTNBYTES + j]; |
| } |
| return md.digest(REMAIN); |
| } |
| }, |
| |
| /* |
| * update the data one by one using method update(byte input) for the |
| * leading bytes (length is "data.length-LASTNBYTES"), then do digest |
| * (do a final update using the left LASTNBYTES bytes which is passed as |
| * a parameter for digest method, then complete the digest) |
| */ |
| UPDATE_LEADING_DIGEST_REMAIN { |
| @Override |
| public byte[] updateDigest(byte[] data, MessageDigest md) { |
| for (int i = 0; i < data.length - LASTNBYTES; i++) { |
| md.update(data[i]); |
| } |
| for (int j = 0; j < LASTNBYTES; j++) { |
| REMAIN[j] = data[data.length - LASTNBYTES + j]; |
| } |
| return md.digest(REMAIN); |
| } |
| }, |
| |
| /* |
| * update all the data at once as a ByteBuffer, then do digest (giving |
| * the output buffer, offset, and the number of bytes to put in the |
| * output buffer) |
| */ |
| UPDATE_BYTE_BUFFER_DIGEST_BUFFER { |
| @Override |
| public byte[] updateDigest(byte[] data, MessageDigest md) |
| throws DigestException { |
| md.update(ByteBuffer.wrap(data)); |
| byte[] output = new byte[md.getDigestLength()]; |
| int len = md.digest(output, 0, output.length); |
| if (len != output.length) { |
| throw new RuntimeException( |
| "ERROR" + ": digest length differs!"); |
| } |
| return output; |
| } |
| }, |
| |
| // update all the data at once as a ByteBuffer, then do digest |
| UPDATE_BYTE_BUFFER_DIGEST { |
| @Override |
| public byte[] updateDigest(byte[] data, MessageDigest md) { |
| md.update(ByteBuffer.wrap(data)); |
| return md.digest(); |
| } |
| }, |
| |
| /* |
| * update the leading bytes (length is "data.length-LASTNBYTES") at once |
| * as a ByteBuffer, then do digest (do a final update using the left |
| * LASTNBYTES bytes which is passed as a parameter for the digest |
| * method, then complete the digest) |
| */ |
| UPDATE_BYTE_BUFFER_LEADING_DIGEST_REMAIN { |
| @Override |
| public byte[] updateDigest(byte[] data, MessageDigest md) { |
| byte[] mainPart = new byte[data.length - LASTNBYTES]; |
| for (int i = 0; i < mainPart.length; i++) { |
| mainPart[i] = data[i]; |
| } |
| for (int j = 0; j < LASTNBYTES; j++) { |
| REMAIN[j] = data[data.length - LASTNBYTES + j]; |
| } |
| md.update(ByteBuffer.wrap(mainPart)); |
| return md.digest(REMAIN); |
| } |
| }; |
| |
| private static final int LASTNBYTES = 5; |
| private static final byte[] REMAIN = new byte[LASTNBYTES]; |
| |
| public abstract byte[] updateDigest(byte[] data, MessageDigest md) |
| throws DigestException; |
| } |
| } |