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