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