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 }