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 }