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