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