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