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