1 /* 2 * Copyright (c) 2003, 2014, 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 java.io.ByteArrayInputStream; 25 import java.io.ByteArrayOutputStream; 26 import java.io.PrintStream; 27 import java.security.DigestInputStream; 28 import java.security.DigestOutputStream; 29 import java.security.MessageDigest; 30 import java.util.Arrays; 31 import java.util.Random; 32 import static java.lang.System.out; 33 34 /** 35 * @test 36 * @bug 8050370 37 * @summary MessageDigest tests with DigestIOStream 38 * @author Kevin Liu 39 */ 40 41 enum ReadModel { 42 READ, BUFFER_READ, MIX_READ 43 } 44 45 public class TestDigestIOStream { 46 47 private static final int[] DATA_LEN_ARRAY = { 48 1, 50, 2500, 125000, 6250000 49 }; 50 private static final String[] ALGORITHM_ARRAY = { 51 "MD2", "MD5", "SHA1", "SHA-224", "SHA-256", "SHA-384", "SHA-512" 52 }; 53 54 private static byte[] data; 55 56 private static MessageDigest md = null; 57 58 public static void main(String argv[]) throws Exception { 59 TestDigestIOStream test = new TestDigestIOStream(); 60 test.run(); 61 } 62 63 public void run() throws Exception { 64 for (String algorithm: ALGORITHM_ARRAY) { 65 66 md = MessageDigest.getInstance(algorithm); 67 68 for (int length: DATA_LEN_ARRAY) { 69 70 Random rdm = new Random(); 71 data = new byte[length]; 72 rdm.nextBytes(data); 73 74 if (!testMDChange(algorithm, length)) { 75 throw new RuntimeException("testMDChange failed at:" 76 + algorithm + "/" + length); 77 } 78 if (!testMDShare(algorithm, length)) { 79 throw new RuntimeException("testMDShare failed at:" 80 + algorithm + "/" + length); 81 } 82 for (ReadModel readModel: ReadModel.values()) { 83 // test Digest function when digest switch on 84 if (!testDigestOnOff(algorithm, readModel, true, length)) { 85 throw new RuntimeException("testDigestOn failed at:" 86 + algorithm + "/" + length + "/" + readModel); 87 } 88 // test Digest function when digest switch off 89 if (!testDigestOnOff(algorithm, readModel, false, length)) { 90 throw new RuntimeException("testDigestOff failed at:" 91 + algorithm + "/" + length + "/" + readModel); 92 } 93 } 94 } 95 } 96 int testNumber = ALGORITHM_ARRAY.length * ReadModel.values().length 97 * DATA_LEN_ARRAY.length * 2 + ALGORITHM_ARRAY.length 98 * DATA_LEN_ARRAY.length * 2; 99 out.println("All " + testNumber + " Tests Passed"); 100 } 101 102 /** 103 * Test DigestInputStream and DigestOutputStream digest function when digest 104 * set on and off 105 * 106 * @param algo 107 * Message Digest algorithm 108 * @param readModel 109 * which read method used(READ, BUFFER_READ, MIX_READ) 110 * @param on 111 * digest switch(on and off) 112 * @param dataLength 113 * plain test data length. 114 * @exception Exception 115 * throw unexpected exception 116 */ 117 public boolean testDigestOnOff(String algo, ReadModel readModel, 118 boolean on, int dataLength) throws Exception { 119 120 // Generate the DigestInputStream/DigestOutputStream object 121 try (ByteArrayInputStream bais = new ByteArrayInputStream(data); 122 DigestInputStream dis = new DigestInputStream(bais, 123 MessageDigest.getInstance(algo)); 124 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 125 DigestOutputStream dos = new DigestOutputStream(baos, 126 MessageDigest.getInstance(algo)); 127 ByteArrayOutputStream baOut = new ByteArrayOutputStream();) { 128 129 // Perform the update using all available/possible update methods 130 int k = 0; 131 byte[] buffer = new byte[5]; 132 boolean enDigest = true; 133 // Make sure the digest function is on (default) 134 dis.on(enDigest); 135 dos.on(enDigest); 136 137 switch (readModel) { 138 case READ: // use only read() 139 while ((k = dis.read()) != -1) { 140 if (on) { 141 dos.write(k); 142 } else { 143 dos.write(k); 144 if (enDigest) { 145 baOut.write(k); 146 } 147 enDigest = !enDigest; 148 dos.on(enDigest); 149 dis.on(enDigest); 150 } 151 } 152 break; 153 case BUFFER_READ: // use only read(byte[], int, int) 154 while ((k = dis.read(buffer, 0, buffer.length)) != -1) { 155 if (on) { 156 dos.write(buffer, 0, k); 157 } else { 158 dos.write(buffer, 0, k); 159 if (enDigest) { 160 baOut.write(buffer, 0, k); 161 } 162 enDigest = !enDigest; 163 dis.on(enDigest); 164 dos.on(enDigest); 165 } 166 } 167 break; 168 case MIX_READ: // use both read() and read(byte[], int, int) 169 while ((k = dis.read()) != -1) { 170 if (on) { 171 dos.write(k); 172 if ((k = dis.read(buffer, 0, buffer.length)) != -1) { 173 dos.write(buffer, 0, k); 174 } 175 } else { 176 dos.write(k); 177 if (enDigest) { 178 baOut.write(k); 179 } 180 enDigest = !enDigest; 181 dis.on(enDigest); 182 dos.on(enDigest); 183 if ((k = dis.read(buffer, 0, buffer.length)) != -1) { 184 dos.write(buffer, 0, k); 185 if (enDigest) { 186 baOut.write(buffer, 0, k); 187 } 188 enDigest = !enDigest; 189 dis.on(enDigest); 190 dos.on(enDigest); 191 } 192 } 193 } 194 break; 195 default: 196 out.println("ERROR: Invalid read/write combination choice!"); 197 return false; 198 } 199 200 // Get the output and the "correct" digest values 201 byte[] output1 = dis.getMessageDigest().digest(); 202 byte[] output2 = dos.getMessageDigest().digest(); 203 byte[] standard; 204 if (on) { 205 standard = md.digest(data); 206 } else { 207 byte[] dataDigested = baOut.toByteArray(); 208 standard = md.digest(dataDigested); 209 } 210 211 // Compare the output byte array value to the input data 212 if (!MessageDigest.isEqual(data, baos.toByteArray())) { 213 out.println("ERROR of " + readModel 214 + ": output and input data unexpectedly changed"); 215 return false; 216 } 217 // Compare generated digest values 218 if (!MessageDigest.isEqual(output1, standard) 219 || !MessageDigest.isEqual(output2, standard)) { 220 out.println("ERROR" + readModel 221 + ": generated digest data unexpectedly changed"); 222 return false; 223 } 224 225 return true; 226 } catch (Exception ex) { 227 out.println("testDigestOnOff failed at:" + algo + "/" + readModel 228 + "/" + dataLength + " with unexpected exception"); 229 throw ex; 230 } 231 } 232 233 /** 234 * Test DigestInputStream and DigestOutputStream digest function when Swap 235 * the message digest engines between DigestIn/OutputStream 236 * 237 * @param algo 238 * Message Digest algorithm 239 * @param dataLength 240 * plain test data length. 241 * @exception Exception 242 * throw unexpected exception 243 */ 244 public boolean testMDChange(String algo, int dataLength) throws Exception { 245 // Generate the DigestInputStream/DigestOutputStream object 246 MessageDigest mdIn = MessageDigest.getInstance(algo); 247 MessageDigest mdOut = MessageDigest.getInstance(algo); 248 try (ByteArrayInputStream bais = new ByteArrayInputStream(data); 249 DigestInputStream dis = new DigestInputStream(bais, mdIn); 250 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 251 DigestOutputStream dos = new DigestOutputStream(baos, mdOut);) { 252 253 // Perform the update using all available/possible update methods 254 int k = 0; 255 byte[] buffer = new byte[10]; 256 257 // use both read() and read(byte[], int, int) 258 while ((k = dis.read()) != -1) { 259 dos.write(k); 260 if ((k = dis.read(buffer, 0, buffer.length)) != -1) { 261 dos.write(buffer, 0, k); 262 } 263 264 // Swap the message digest engines between 265 // DigestIn/OutputStream objects 266 dis.setMessageDigest(mdOut); 267 dos.setMessageDigest(mdIn); 268 mdIn = dis.getMessageDigest(); 269 mdOut = dos.getMessageDigest(); 270 } 271 272 // Get the output and the "correct" digest values 273 byte[] output1 = mdIn.digest(); 274 byte[] output2 = mdOut.digest(); 275 byte[] standard = md.digest(data); 276 277 // Compare generated digest values 278 return MessageDigest.isEqual(output1, standard) 279 && MessageDigest.isEqual(output2, standard); 280 } catch (Exception ex) { 281 out.println("testMDChange failed at:" + algo + "/" + dataLength 282 + " with unexpected exception"); 283 throw ex; 284 } 285 } 286 287 /** 288 * Test DigestInputStream and DigestOutputStream digest function when use 289 * same message digest object. 290 * 291 * @param algo 292 * Message Digest algorithm 293 * @param dataLength 294 * plain test data length. 295 * @exception Exception 296 * throw unexpected exception 297 */ 298 public boolean testMDShare(String algo, int dataLength) throws Exception { 299 MessageDigest mdCommon = MessageDigest.getInstance(algo); 300 // Generate the DigestInputStream/DigestOutputStream object 301 try (ByteArrayInputStream bais = new ByteArrayInputStream(data); 302 DigestInputStream dis = new DigestInputStream(bais, mdCommon); 303 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 304 DigestOutputStream dos = new DigestOutputStream(baos, mdCommon);) { 305 306 // Perform the update using all available/possible update methods 307 int k = 0; 308 byte[] buffer = new byte[10]; 309 310 // use both read() and read(byte[], int, int) 311 while (k < data.length) { 312 int len = dis.read(buffer, 0, buffer.length); 313 if (len != -1) { 314 k += len; 315 if (k < data.length) { 316 dos.write(data[k]); 317 k++; 318 dis.skip(1); 319 } 320 } 321 } 322 323 // Get the output and the "correct" digest values 324 byte[] output = mdCommon.digest(); 325 byte[] standard = md.digest(data); 326 327 // Compare generated digest values 328 return MessageDigest.isEqual(output, standard); 329 } catch (Exception ex) { 330 out.println("TestMDShare failed at:" + algo + "/" + dataLength 331 + " with unexpected exception"); 332 throw ex; 333 } 334 } 335 }