1 /*
   2  * Copyright (c) 2015, 2017, 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             try {
  64                 md = MessageDigest.getInstance(algorithm);
  65 
  66                 for (UpdateDigestMethod updateMethod : UpdateDigestMethod
  67                         .values()) {
  68                     byte[] output = updateMethod.updateDigest(data, md);
  69                     // Get the output and the "correct" one
  70                     byte[] standard = md.digest(data);
  71                     // Compare input and output
  72                     if (!MessageDigest.isEqual(output, standard)) {
  73                         throw new RuntimeException(
  74                                 "Test failed at algorithm/provider/numUpdate:"
  75                                         + algorithm + "/" + md.getProvider()
  76                                         + "/" + updateMethod);
  77                     }
  78                 }
  79             } catch (NoSuchAlgorithmException nae) {
  80                 if (algorithm.startsWith("SHA3") && !isSHA3supported()) {
  81                     continue;
  82                 } else {
  83                     throw nae;
  84                 }
  85             }
  86         }
  87 
  88         out.println("All "
  89                 + algorithmArr.length * UpdateDigestMethod.values().length
  90                 + " tests Passed");
  91     }
  92 
  93     // SHA-3 hash algorithms are only supported by "SUN" provider
  94     // This method checks if system supports SHA-3
  95     private boolean isSHA3supported() {
  96         if (Security.getProvider("SUN") != null) {
  97             return true;
  98         }
  99         return false;
 100     }
 101 
 102     private static enum UpdateDigestMethod {
 103 
 104         /*
 105          * update the data one by one using method update(byte input) then do
 106          * digest (giving the output buffer, offset, and the number of bytes to
 107          * put in the output buffer)
 108          */
 109         UPDATE_DIGEST_BUFFER {
 110             @Override
 111             public byte[] updateDigest(byte[] data, MessageDigest md)
 112                     throws DigestException {
 113                 for (byte element : data) {
 114                     md.update(element);
 115                 }
 116                 byte[] output = new byte[md.getDigestLength()];
 117                 int len = md.digest(output, 0, output.length);
 118                 if (len != output.length) {
 119                     throw new RuntimeException(
 120                             "ERROR" + ": digest length differs!");
 121                 }
 122                 return output;
 123             }
 124         },
 125 
 126         /*
 127          * update the data one by one using method update(byte input) then do
 128          * digest
 129          */
 130         UPDATE_DIGEST {
 131             @Override
 132             public byte[] updateDigest(byte[] data, MessageDigest md) {
 133                 for (byte element : data) {
 134                     md.update(element);
 135                 }
 136                 return md.digest();
 137             }
 138         },
 139 
 140         /*
 141          * update all the data at once as a block, then do digest ( giving the
 142          * output buffer, offset, and the number of bytes to put in the output
 143          * buffer)
 144          */
 145         UPDATE_BLOCK_DIGEST_BUFFER {
 146             @Override
 147             public byte[] updateDigest(byte[] data, MessageDigest md)
 148                     throws DigestException {
 149                 md.update(data);
 150                 byte[] output = new byte[md.getDigestLength()];
 151                 int len = md.digest(output, 0, output.length);
 152                 if (len != output.length) {
 153                     throw new RuntimeException(
 154                             "ERROR" + ": digest length differs!");
 155                 }
 156                 return output;
 157             }
 158         },
 159 
 160         // update all the data at once as a block, then do digest
 161         UPDATE_BLOCK_DIGEST {
 162             @Override
 163             public byte[] updateDigest(byte[] data, MessageDigest md) {
 164                 md.update(data);
 165                 return md.digest();
 166             }
 167         },
 168 
 169         /*
 170          * update the leading bytes (length is "data.length-LASTNBYTES") at once
 171          * as a block, then do digest (do a final update using the left
 172          * LASTNBYTES bytes which is passed as a parameter for the digest
 173          * method, then complete the digest)
 174          */
 175         UPDATE_LEADING_BLOCK_DIGEST_REMAIN {
 176             @Override
 177             public byte[] updateDigest(byte[] data, MessageDigest md) {
 178                 byte[] mainPart = new byte[data.length - LASTNBYTES];
 179                 for (int i = 0; i < mainPart.length; i++) {
 180                     mainPart[i] = data[i];
 181                 }
 182                 for (int j = 0; j < LASTNBYTES; j++) {
 183                     REMAIN[j] = data[data.length - LASTNBYTES + j];
 184                 }
 185                 md.update(mainPart);
 186                 return md.digest(REMAIN);
 187             }
 188         },
 189 
 190         /*
 191          * update the data 2 bytes each time, after finishing updating, do
 192          * digest (giving the output buffer, offset, and the number of bytes to
 193          * put in the output buffer)
 194          */
 195         UPDATE_BYTES_DIGEST_BUFFER {
 196             @Override
 197             public byte[] updateDigest(byte[] data, MessageDigest md)
 198                     throws DigestException {
 199 
 200                 for (int i = 0; i < data.length / 2; i++) {
 201                     md.update(data, i * 2, 2);
 202                 }
 203                 byte[] output = new byte[md.getDigestLength()];
 204                 int len = md.digest(output, 0, output.length);
 205                 if (len != output.length) {
 206                     throw new RuntimeException(
 207                             "ERROR" + ": digest length differs!");
 208                 }
 209                 return output;
 210             }
 211         },
 212 
 213         /*
 214          * update the data 2 bytes each time, after finishing updating, do
 215          * digest
 216          */
 217         UPDATE_BYTES_DIGEST {
 218             @Override
 219             public byte[] updateDigest(byte[] data, MessageDigest md) {
 220                 for (int i = 0; i < data.length / 2; i++) {
 221                     md.update(data, i * 2, 2);
 222                 }
 223                 return md.digest();
 224             }
 225         },
 226 
 227         /*
 228          * update the data one by one using method update(byte[] input, int
 229          * offset, int len) for the leading bytes (length is
 230          * "data.length-LASTNBYTES"), then do digest (do a final update using
 231          * the left LASTNBYTES bytes which is passed as a parameter for digest
 232          * method then complete the digest)
 233          */
 234         UPDATE_BUFFER_LEADING_DIGEST_REMAIN {
 235             @Override
 236             public byte[] updateDigest(byte[] data, MessageDigest md) {
 237                 for (int i = 0; i < data.length - LASTNBYTES; i++) {
 238                     md.update(data, i, 1);
 239                 }
 240                 for (int j = 0; j < LASTNBYTES; j++) {
 241                     REMAIN[j] = data[data.length - LASTNBYTES + j];
 242                 }
 243                 return md.digest(REMAIN);
 244             }
 245         },
 246 
 247         /*
 248          * update the data one by one using method update(byte input) for the
 249          * leading bytes (length is "data.length-LASTNBYTES"), then do digest
 250          * (do a final update using the left LASTNBYTES bytes which is passed as
 251          * a parameter for digest method, then complete the digest)
 252          */
 253         UPDATE_LEADING_DIGEST_REMAIN {
 254             @Override
 255             public byte[] updateDigest(byte[] data, MessageDigest md) {
 256                 for (int i = 0; i < data.length - LASTNBYTES; i++) {
 257                     md.update(data[i]);
 258                 }
 259                 for (int j = 0; j < LASTNBYTES; j++) {
 260                     REMAIN[j] = data[data.length - LASTNBYTES + j];
 261                 }
 262                 return md.digest(REMAIN);
 263             }
 264         },
 265 
 266         /*
 267          * update all the data at once as a ByteBuffer, then do digest (giving
 268          * the output buffer, offset, and the number of bytes to put in the
 269          * output buffer)
 270          */
 271         UPDATE_BYTE_BUFFER_DIGEST_BUFFER {
 272             @Override
 273             public byte[] updateDigest(byte[] data, MessageDigest md)
 274                     throws DigestException {
 275                 md.update(ByteBuffer.wrap(data));
 276                 byte[] output = new byte[md.getDigestLength()];
 277                 int len = md.digest(output, 0, output.length);
 278                 if (len != output.length) {
 279                     throw new RuntimeException(
 280                             "ERROR" + ": digest length differs!");
 281                 }
 282                 return output;
 283             }
 284         },
 285 
 286         // update all the data at once as a ByteBuffer, then do digest
 287         UPDATE_BYTE_BUFFER_DIGEST {
 288             @Override
 289             public byte[] updateDigest(byte[] data, MessageDigest md) {
 290                 md.update(ByteBuffer.wrap(data));
 291                 return md.digest();
 292             }
 293         },
 294 
 295         /*
 296          * update the leading bytes (length is "data.length-LASTNBYTES") at once
 297          * as a ByteBuffer, then do digest (do a final update using the left
 298          * LASTNBYTES bytes which is passed as a parameter for the digest
 299          * method, then complete the digest)
 300          */
 301         UPDATE_BYTE_BUFFER_LEADING_DIGEST_REMAIN {
 302             @Override
 303             public byte[] updateDigest(byte[] data, MessageDigest md) {
 304                 byte[] mainPart = new byte[data.length - LASTNBYTES];
 305                 for (int i = 0; i < mainPart.length; i++) {
 306                     mainPart[i] = data[i];
 307                 }
 308                 for (int j = 0; j < LASTNBYTES; j++) {
 309                     REMAIN[j] = data[data.length - LASTNBYTES + j];
 310                 }
 311                 md.update(ByteBuffer.wrap(mainPart));
 312                 return md.digest(REMAIN);
 313             }
 314         };
 315 
 316         private static final int LASTNBYTES = 5;
 317         private static final byte[] REMAIN = new byte[LASTNBYTES];
 318 
 319         public abstract byte[] updateDigest(byte[] data, MessageDigest md)
 320                 throws DigestException;
 321     }
 322 }