1 /*
   2  * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import static java.lang.System.out;
  25 import java.nio.ByteBuffer;
  26 import java.security.DigestException;
  27 import java.security.MessageDigest;
  28 import java.security.NoSuchAlgorithmException;
  29 import java.security.Security;
  30 import jdk.test.lib.RandomFactory;
  31 
  32 /**
  33  * @test
  34  * @bug 8050371 8156059
  35  * @summary Check md.digest(data) value whether same with digest output value
  36  *          with various update/digest methods.
  37  * @author Kevin Liu
  38  * @key randomness
  39  * @library /test/lib
  40  * @build jdk.test.lib.RandomFactory
  41  * @run main TestSameValue
  42  */
  43 
  44 public class TestSameValue {
  45 
  46     public static void main(String[] args) throws Exception {
  47         TestSameValue test1 = new TestSameValue();
  48         test1.run();
  49     }
  50 
  51     private void run() throws Exception {
  52 
  53         byte[] data = new byte[6706];
  54         MessageDigest md = null;
  55         // Initialize input data
  56         RandomFactory.getRandom().nextBytes(data);
  57 
  58         String[] algorithmArr = { "SHA", "Sha", "MD5", "md5", "SHA-224",
  59                 "SHA-256", "SHA-384", "SHA-512", "SHA3-224", "SHA3-256",
  60                 "SHA3-384", "SHA3-512" };
  61 
  62         for (String algorithm : algorithmArr) {
  63             md = MessageDigest.getInstance(algorithm);
  64 
  65             for (UpdateDigestMethod updateMethod : UpdateDigestMethod
  66                      .values()) {
  67                 byte[] output = updateMethod.updateDigest(data, md);
  68                 // Get the output and the "correct" one
  69                 byte[] standard = md.digest(data);
  70                 // Compare input and output
  71                 if (!MessageDigest.isEqual(output, standard)) {
  72                     throw new RuntimeException(
  73                             "Test failed at algorithm/provider/numUpdate:"
  74                                     + algorithm + "/" + md.getProvider()
  75                                     + "/" + updateMethod);
  76                 }
  77             }
  78         }
  79 
  80         out.println("All "
  81                 + algorithmArr.length * UpdateDigestMethod.values().length
  82                 + " tests Passed");
  83     }
  84 
  85     private static enum UpdateDigestMethod {
  86 
  87         /*
  88          * update the data one by one using method update(byte input) then do
  89          * digest (giving the output buffer, offset, and the number of bytes to
  90          * put in the output buffer)
  91          */
  92         UPDATE_DIGEST_BUFFER {
  93             @Override
  94             public byte[] updateDigest(byte[] data, MessageDigest md)
  95                     throws DigestException {
  96                 for (byte element : data) {
  97                     md.update(element);
  98                 }
  99                 byte[] output = new byte[md.getDigestLength()];
 100                 int len = md.digest(output, 0, output.length);
 101                 if (len != output.length) {
 102                     throw new RuntimeException(
 103                             "ERROR" + ": digest length differs!");
 104                 }
 105                 return output;
 106             }
 107         },
 108 
 109         /*
 110          * update the data one by one using method update(byte input) then do
 111          * digest
 112          */
 113         UPDATE_DIGEST {
 114             @Override
 115             public byte[] updateDigest(byte[] data, MessageDigest md) {
 116                 for (byte element : data) {
 117                     md.update(element);
 118                 }
 119                 return md.digest();
 120             }
 121         },
 122 
 123         /*
 124          * update all the data at once as a block, then do digest ( giving the
 125          * output buffer, offset, and the number of bytes to put in the output
 126          * buffer)
 127          */
 128         UPDATE_BLOCK_DIGEST_BUFFER {
 129             @Override
 130             public byte[] updateDigest(byte[] data, MessageDigest md)
 131                     throws DigestException {
 132                 md.update(data);
 133                 byte[] output = new byte[md.getDigestLength()];
 134                 int len = md.digest(output, 0, output.length);
 135                 if (len != output.length) {
 136                     throw new RuntimeException(
 137                             "ERROR" + ": digest length differs!");
 138                 }
 139                 return output;
 140             }
 141         },
 142 
 143         // update all the data at once as a block, then do digest
 144         UPDATE_BLOCK_DIGEST {
 145             @Override
 146             public byte[] updateDigest(byte[] data, MessageDigest md) {
 147                 md.update(data);
 148                 return md.digest();
 149             }
 150         },
 151 
 152         /*
 153          * update the leading bytes (length is "data.length-LASTNBYTES") at once
 154          * as a block, then do digest (do a final update using the left
 155          * LASTNBYTES bytes which is passed as a parameter for the digest
 156          * method, then complete the digest)
 157          */
 158         UPDATE_LEADING_BLOCK_DIGEST_REMAIN {
 159             @Override
 160             public byte[] updateDigest(byte[] data, MessageDigest md) {
 161                 byte[] mainPart = new byte[data.length - LASTNBYTES];
 162                 for (int i = 0; i < mainPart.length; i++) {
 163                     mainPart[i] = data[i];
 164                 }
 165                 for (int j = 0; j < LASTNBYTES; j++) {
 166                     REMAIN[j] = data[data.length - LASTNBYTES + j];
 167                 }
 168                 md.update(mainPart);
 169                 return md.digest(REMAIN);
 170             }
 171         },
 172 
 173         /*
 174          * update the data 2 bytes each time, after finishing updating, do
 175          * digest (giving the output buffer, offset, and the number of bytes to
 176          * put in the output buffer)
 177          */
 178         UPDATE_BYTES_DIGEST_BUFFER {
 179             @Override
 180             public byte[] updateDigest(byte[] data, MessageDigest md)
 181                     throws DigestException {
 182 
 183                 for (int i = 0; i < data.length / 2; i++) {
 184                     md.update(data, i * 2, 2);
 185                 }
 186                 byte[] output = new byte[md.getDigestLength()];
 187                 int len = md.digest(output, 0, output.length);
 188                 if (len != output.length) {
 189                     throw new RuntimeException(
 190                             "ERROR" + ": digest length differs!");
 191                 }
 192                 return output;
 193             }
 194         },
 195 
 196         /*
 197          * update the data 2 bytes each time, after finishing updating, do
 198          * digest
 199          */
 200         UPDATE_BYTES_DIGEST {
 201             @Override
 202             public byte[] updateDigest(byte[] data, MessageDigest md) {
 203                 for (int i = 0; i < data.length / 2; i++) {
 204                     md.update(data, i * 2, 2);
 205                 }
 206                 return md.digest();
 207             }
 208         },
 209 
 210         /*
 211          * update the data one by one using method update(byte[] input, int
 212          * offset, int len) for the leading bytes (length is
 213          * "data.length-LASTNBYTES"), then do digest (do a final update using
 214          * the left LASTNBYTES bytes which is passed as a parameter for digest
 215          * method then complete the digest)
 216          */
 217         UPDATE_BUFFER_LEADING_DIGEST_REMAIN {
 218             @Override
 219             public byte[] updateDigest(byte[] data, MessageDigest md) {
 220                 for (int i = 0; i < data.length - LASTNBYTES; i++) {
 221                     md.update(data, i, 1);
 222                 }
 223                 for (int j = 0; j < LASTNBYTES; j++) {
 224                     REMAIN[j] = data[data.length - LASTNBYTES + j];
 225                 }
 226                 return md.digest(REMAIN);
 227             }
 228         },
 229 
 230         /*
 231          * update the data one by one using method update(byte input) for the
 232          * leading bytes (length is "data.length-LASTNBYTES"), then do digest
 233          * (do a final update using the left LASTNBYTES bytes which is passed as
 234          * a parameter for digest method, then complete the digest)
 235          */
 236         UPDATE_LEADING_DIGEST_REMAIN {
 237             @Override
 238             public byte[] updateDigest(byte[] data, MessageDigest md) {
 239                 for (int i = 0; i < data.length - LASTNBYTES; i++) {
 240                     md.update(data[i]);
 241                 }
 242                 for (int j = 0; j < LASTNBYTES; j++) {
 243                     REMAIN[j] = data[data.length - LASTNBYTES + j];
 244                 }
 245                 return md.digest(REMAIN);
 246             }
 247         },
 248 
 249         /*
 250          * update all the data at once as a ByteBuffer, then do digest (giving
 251          * the output buffer, offset, and the number of bytes to put in the
 252          * output buffer)
 253          */
 254         UPDATE_BYTE_BUFFER_DIGEST_BUFFER {
 255             @Override
 256             public byte[] updateDigest(byte[] data, MessageDigest md)
 257                     throws DigestException {
 258                 md.update(ByteBuffer.wrap(data));
 259                 byte[] output = new byte[md.getDigestLength()];
 260                 int len = md.digest(output, 0, output.length);
 261                 if (len != output.length) {
 262                     throw new RuntimeException(
 263                             "ERROR" + ": digest length differs!");
 264                 }
 265                 return output;
 266             }
 267         },
 268 
 269         // update all the data at once as a ByteBuffer, then do digest
 270         UPDATE_BYTE_BUFFER_DIGEST {
 271             @Override
 272             public byte[] updateDigest(byte[] data, MessageDigest md) {
 273                 md.update(ByteBuffer.wrap(data));
 274                 return md.digest();
 275             }
 276         },
 277 
 278         /*
 279          * update the leading bytes (length is "data.length-LASTNBYTES") at once
 280          * as a ByteBuffer, then do digest (do a final update using the left
 281          * LASTNBYTES bytes which is passed as a parameter for the digest
 282          * method, then complete the digest)
 283          */
 284         UPDATE_BYTE_BUFFER_LEADING_DIGEST_REMAIN {
 285             @Override
 286             public byte[] updateDigest(byte[] data, MessageDigest md) {
 287                 byte[] mainPart = new byte[data.length - LASTNBYTES];
 288                 for (int i = 0; i < mainPart.length; i++) {
 289                     mainPart[i] = data[i];
 290                 }
 291                 for (int j = 0; j < LASTNBYTES; j++) {
 292                     REMAIN[j] = data[data.length - LASTNBYTES + j];
 293                 }
 294                 md.update(ByteBuffer.wrap(mainPart));
 295                 return md.digest(REMAIN);
 296             }
 297         };
 298 
 299         private static final int LASTNBYTES = 5;
 300         private static final byte[] REMAIN = new byte[LASTNBYTES];
 301 
 302         public abstract byte[] updateDigest(byte[] data, MessageDigest md)
 303                 throws DigestException;
 304     }
 305 }