test/jdk/javax/crypto/CipherSpi/CipherByteBufferOverwriteTest.java
changeset 55661 b32b6ffb221b
equal deleted inserted replaced
55660:fe5dcb38a26a 55661:b32b6ffb221b
       
     1 /*
       
     2  * Copyright (c) 2019, 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 /**
       
    25  * @test
       
    26  * @bug 8181386
       
    27  * @summary CipherSpi ByteBuffer to byte array conversion fails for
       
    28  *          certain data overlap conditions
       
    29  * @run main CipherByteBufferOverwriteTest 0 false
       
    30  * @run main CipherByteBufferOverwriteTest 0 true
       
    31  * @run main CipherByteBufferOverwriteTest 4 false
       
    32  * @run main CipherByteBufferOverwriteTest 4 true
       
    33  */
       
    34 
       
    35 import java.security.spec.AlgorithmParameterSpec;
       
    36 import javax.crypto.Cipher;
       
    37 import javax.crypto.SecretKey;
       
    38 import javax.crypto.spec.IvParameterSpec;
       
    39 import javax.crypto.spec.SecretKeySpec;
       
    40 import java.nio.ByteBuffer;
       
    41 import java.util.Arrays;
       
    42 
       
    43 public class CipherByteBufferOverwriteTest {
       
    44 
       
    45     private static final boolean DEBUG = false;
       
    46 
       
    47     private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
       
    48 
       
    49     // must be larger than the temp array size, i.e. 4096, hardcoded in
       
    50     // javax.crypto.CipherSpi class
       
    51     private static final int PLAINTEXT_SIZE = 8192;
       
    52     // leave room for padding
       
    53     private static final int CIPHERTEXT_BUFFER_SIZE = PLAINTEXT_SIZE + 32;
       
    54 
       
    55     private static final SecretKey KEY = new SecretKeySpec(new byte[16], "AES");
       
    56     private static final AlgorithmParameterSpec PARAMS =
       
    57             new IvParameterSpec(new byte[16]);
       
    58 
       
    59     private static ByteBuffer inBuf;
       
    60     private static ByteBuffer outBuf;
       
    61 
       
    62     private enum BufferType {
       
    63         ALLOCATE, DIRECT, WRAP;
       
    64     }
       
    65 
       
    66     public static void main(String[] args) throws Exception {
       
    67 
       
    68         int offset = Integer.parseInt(args[0]);
       
    69         boolean useRO = Boolean.parseBoolean(args[1]);
       
    70 
       
    71         // an all-zeros plaintext is the easiest way to demonstrate the issue,
       
    72         // but it fails with any plaintext, of course
       
    73         byte[] expectedPT = new byte[PLAINTEXT_SIZE];
       
    74         byte[] buf = new byte[offset + CIPHERTEXT_BUFFER_SIZE];
       
    75         System.arraycopy(expectedPT, 0, buf, 0, PLAINTEXT_SIZE);
       
    76 
       
    77         // generate expected cipher text using byte[] methods
       
    78         Cipher c = Cipher.getInstance(TRANSFORMATION);
       
    79         c.init(Cipher.ENCRYPT_MODE, KEY, PARAMS);
       
    80         byte[] expectedCT = c.doFinal(expectedPT);
       
    81 
       
    82         // Test#1: against ByteBuffer generated with allocate(int) call
       
    83         prepareBuffers(BufferType.ALLOCATE, useRO, buf.length,
       
    84                 buf, 0, PLAINTEXT_SIZE, offset);
       
    85 
       
    86         runTest(offset, expectedPT, expectedCT);
       
    87         System.out.println("\tALLOCATE: passed");
       
    88 
       
    89         // Test#2: against direct ByteBuffer
       
    90         prepareBuffers(BufferType.DIRECT, useRO, buf.length,
       
    91                 buf, 0, PLAINTEXT_SIZE, offset);
       
    92         System.out.println("\tDIRECT: passed");
       
    93 
       
    94         runTest(offset, expectedPT, expectedCT);
       
    95 
       
    96         // Test#3: against ByteBuffer wrapping existing array
       
    97         prepareBuffers(BufferType.WRAP, useRO, buf.length,
       
    98                 buf, 0, PLAINTEXT_SIZE, offset);
       
    99 
       
   100         runTest(offset, expectedPT, expectedCT);
       
   101         System.out.println("\tWRAP: passed");
       
   102 
       
   103         System.out.println("All Tests Passed");
       
   104     }
       
   105 
       
   106     private static void prepareBuffers(BufferType type,
       
   107             boolean useRO, int bufSz, byte[] in, int inOfs, int inLen,
       
   108             int outOfs) {
       
   109         switch (type) {
       
   110             case ALLOCATE:
       
   111                 outBuf = ByteBuffer.allocate(bufSz);
       
   112                 inBuf = outBuf.slice();
       
   113                 inBuf.put(in, inOfs, inLen);
       
   114                 inBuf.rewind();
       
   115                 inBuf.limit(inLen);
       
   116                 outBuf.position(outOfs);
       
   117                 break;
       
   118             case DIRECT:
       
   119                 outBuf = ByteBuffer.allocateDirect(bufSz);
       
   120                 inBuf = outBuf.slice();
       
   121                 inBuf.put(in, inOfs, inLen);
       
   122                 inBuf.rewind();
       
   123                 inBuf.limit(inLen);
       
   124                 outBuf.position(outOfs);
       
   125                 break;
       
   126             case WRAP:
       
   127                 if (in.length < bufSz) {
       
   128                     throw new RuntimeException("ERROR: Input buffer too small");
       
   129                 }
       
   130                 outBuf = ByteBuffer.wrap(in);
       
   131                 inBuf = ByteBuffer.wrap(in, inOfs, inLen);
       
   132                 outBuf.position(outOfs);
       
   133                 break;
       
   134         }
       
   135         if (useRO) {
       
   136             inBuf = inBuf.asReadOnlyBuffer();
       
   137         }
       
   138         if (DEBUG) {
       
   139             System.out.println("inBuf, pos = " + inBuf.position() +
       
   140                 ", capacity = " + inBuf.capacity() +
       
   141                 ", limit = " + inBuf.limit() +
       
   142                 ", remaining = " + inBuf.remaining());
       
   143             System.out.println("outBuf, pos = " + outBuf.position() +
       
   144                 ", capacity = " + outBuf.capacity() +
       
   145                 ", limit = " + outBuf.limit() +
       
   146                 ", remaining = " + outBuf.remaining());
       
   147         }
       
   148     }
       
   149 
       
   150     private static void runTest(int ofs, byte[] expectedPT, byte[] expectedCT)
       
   151             throws Exception {
       
   152 
       
   153         Cipher c = Cipher.getInstance(TRANSFORMATION);
       
   154         c.init(Cipher.ENCRYPT_MODE, KEY, PARAMS);
       
   155         int ciphertextSize = c.doFinal(inBuf, outBuf);
       
   156 
       
   157         // read out the encrypted result
       
   158         outBuf.position(ofs);
       
   159         byte[] finalCT = new byte[ciphertextSize];
       
   160         if (DEBUG) {
       
   161             System.out.println("runTest, ciphertextSize = " + ciphertextSize);
       
   162             System.out.println("runTest, ofs = " + ofs +
       
   163                 ", remaining = " + finalCT.length +
       
   164                 ", limit = " + outBuf.limit());
       
   165         }
       
   166         outBuf.get(finalCT);
       
   167 
       
   168         if (!Arrays.equals(finalCT, expectedCT)) {
       
   169             throw new Exception("ERROR: Ciphertext does not match");
       
   170         }
       
   171 
       
   172         // now do decryption
       
   173         outBuf.position(ofs);
       
   174         outBuf.limit(ofs + ciphertextSize);
       
   175 
       
   176         c.init(Cipher.DECRYPT_MODE, KEY, PARAMS);
       
   177         ByteBuffer finalPTBuf = ByteBuffer.allocate(
       
   178                 c.getOutputSize(outBuf.remaining()));
       
   179         c.doFinal(outBuf, finalPTBuf);
       
   180 
       
   181         // read out the decrypted result
       
   182         finalPTBuf.flip();
       
   183         byte[] finalPT = new byte[finalPTBuf.remaining()];
       
   184         finalPTBuf.get(finalPT);
       
   185 
       
   186         if (!Arrays.equals(finalPT, expectedPT)) {
       
   187             throw new Exception("ERROR: Plaintext does not match");
       
   188         }
       
   189     }
       
   190 }
       
   191