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 }