test/jdk/com/sun/crypto/provider/Cipher/ChaCha20/OutputSizeTest.java
changeset 57791 34bbd91b1522
equal deleted inserted replaced
57787:094ef5a91b68 57791:34bbd91b1522
       
     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 8224997
       
    27  * @summary ChaCha20-Poly1305 TLS cipher suite decryption throws ShortBufferException
       
    28  * @library /test/lib
       
    29  * @build jdk.test.lib.Convert
       
    30  * @run main OutputSizeTest
       
    31  */
       
    32 
       
    33 import java.nio.ByteBuffer;
       
    34 import java.security.GeneralSecurityException;
       
    35 import java.security.Key;
       
    36 import java.security.SecureRandom;
       
    37 import javax.crypto.Cipher;
       
    38 import javax.crypto.KeyGenerator;
       
    39 import javax.crypto.spec.ChaCha20ParameterSpec;
       
    40 import javax.crypto.spec.IvParameterSpec;
       
    41 
       
    42 public class OutputSizeTest {
       
    43 
       
    44     private static final SecureRandom SR = new SecureRandom();
       
    45 
       
    46     public static void main(String args[]) throws Exception {
       
    47         testCC20GetOutSize();
       
    48         testCC20P1305GetOutSize();
       
    49         testMultiPartAEADDec();
       
    50     }
       
    51 
       
    52     private static void testCC20GetOutSize()
       
    53             throws GeneralSecurityException {
       
    54         boolean result = true;
       
    55         KeyGenerator kg = KeyGenerator.getInstance("ChaCha20", "SunJCE");
       
    56         kg.init(256);
       
    57 
       
    58         // ChaCha20 encrypt
       
    59         Cipher cc20 = Cipher.getInstance("ChaCha20", "SunJCE");
       
    60         cc20.init(Cipher.ENCRYPT_MODE, kg.generateKey(),
       
    61                 new ChaCha20ParameterSpec(getRandBuf(12), 10));
       
    62 
       
    63         testOutLen(cc20, 0, 0);
       
    64         testOutLen(cc20, 5, 5);
       
    65         testOutLen(cc20, 5120, 5120);
       
    66         // perform an update, then test with a final block
       
    67         byte[] input = new byte[5120];
       
    68         SR.nextBytes(input);
       
    69         cc20.update(input);
       
    70         testOutLen(cc20, 1024, 1024);
       
    71 
       
    72         // Decryption lengths should be calculated the same way as encryption
       
    73         cc20.init(Cipher.DECRYPT_MODE, kg.generateKey(),
       
    74                 new ChaCha20ParameterSpec(getRandBuf(12), 10));
       
    75         testOutLen(cc20, 0, 0);
       
    76         testOutLen(cc20, 5, 5);
       
    77         testOutLen(cc20, 5120, 5120);
       
    78         // perform an update, then test with a final block
       
    79         cc20.update(input);
       
    80         testOutLen(cc20, 1024, 1024);
       
    81     }
       
    82 
       
    83     private static void testCC20P1305GetOutSize()
       
    84             throws GeneralSecurityException {
       
    85         KeyGenerator kg = KeyGenerator.getInstance("ChaCha20", "SunJCE");
       
    86         kg.init(256);
       
    87 
       
    88         // ChaCha20 encrypt
       
    89         Cipher cc20 = Cipher.getInstance("ChaCha20-Poly1305", "SunJCE");
       
    90         cc20.init(Cipher.ENCRYPT_MODE, kg.generateKey(),
       
    91                 new IvParameterSpec(getRandBuf(12)));
       
    92 
       
    93         // Encryption lengths are calculated as the input length plus the tag
       
    94         // length (16).
       
    95         testOutLen(cc20, 0, 16);
       
    96         testOutLen(cc20, 5, 21);
       
    97         testOutLen(cc20, 5120, 5136);
       
    98         // perform an update, then test with a final block
       
    99         byte[] input = new byte[5120];
       
   100         SR.nextBytes(input);
       
   101         cc20.update(input);
       
   102         testOutLen(cc20, 1024, 1040);
       
   103 
       
   104         // Decryption lengths are handled differently for AEAD mode.  The length
       
   105         // should be zero for anything up to and including the first 16 bytes
       
   106         // (since that's the tag).  Anything above that should be the input
       
   107         // length plus any unprocessed input (via update calls), minus the
       
   108         // 16 byte tag.
       
   109         cc20.init(Cipher.DECRYPT_MODE, kg.generateKey(),
       
   110                 new IvParameterSpec(getRandBuf(12)));
       
   111         testOutLen(cc20, 0, 0);
       
   112         testOutLen(cc20, 5, 0);
       
   113         testOutLen(cc20, 16, 0);
       
   114         testOutLen(cc20, 5120, 5104);
       
   115         // Perform an update, then test with a the length of a final chunk
       
   116         // of data.
       
   117         cc20.update(input);
       
   118         testOutLen(cc20, 1024, 6128);
       
   119     }
       
   120 
       
   121     private static void testMultiPartAEADDec() throws GeneralSecurityException {
       
   122         KeyGenerator kg = KeyGenerator.getInstance("ChaCha20", "SunJCE");
       
   123         kg.init(256);
       
   124         Key key = kg.generateKey();
       
   125         IvParameterSpec ivps = new IvParameterSpec(getRandBuf(12));
       
   126 
       
   127         // Encrypt some data so we can test decryption.
       
   128         byte[] pText = getRandBuf(2048);
       
   129         ByteBuffer pTextBase = ByteBuffer.wrap(pText);
       
   130 
       
   131         Cipher enc = Cipher.getInstance("ChaCha20-Poly1305", "SunJCE");
       
   132         enc.init(Cipher.ENCRYPT_MODE, key, ivps);
       
   133         ByteBuffer ctBuf = ByteBuffer.allocateDirect(
       
   134                 enc.getOutputSize(pText.length));
       
   135         enc.doFinal(pTextBase, ctBuf);
       
   136 
       
   137         // Create a new direct plain text ByteBuffer which will catch the
       
   138         // decrypted data.
       
   139         ByteBuffer ptBuf = ByteBuffer.allocateDirect(pText.length);
       
   140 
       
   141         // Set the cipher text buffer limit to roughly half the data so we can
       
   142         // do an update/final sequence.
       
   143         ctBuf.position(0).limit(1024);
       
   144 
       
   145         Cipher dec = Cipher.getInstance("ChaCha20-Poly1305", "SunJCE");
       
   146         dec.init(Cipher.DECRYPT_MODE, key, ivps);
       
   147         dec.update(ctBuf, ptBuf);
       
   148         System.out.println("CTBuf: " + ctBuf);
       
   149         System.out.println("PTBuf: " + ptBuf);
       
   150         ctBuf.limit(ctBuf.capacity());
       
   151         dec.doFinal(ctBuf, ptBuf);
       
   152 
       
   153         ptBuf.flip();
       
   154         pTextBase.flip();
       
   155         System.out.println("PT Base:" + pTextBase);
       
   156         System.out.println("PT Actual:" + ptBuf);
       
   157 
       
   158         if (pTextBase.compareTo(ptBuf) != 0) {
       
   159             StringBuilder sb = new StringBuilder();
       
   160             sb.append("Plaintext mismatch: Original: ").
       
   161                     append(pTextBase.toString()).append("\nActual :").
       
   162                     append(ptBuf);
       
   163             throw new RuntimeException(sb.toString());
       
   164         }
       
   165     }
       
   166 
       
   167     private static void testOutLen(Cipher c, int inLen, int expOut) {
       
   168         int actualOut = c.getOutputSize(inLen);
       
   169         if (actualOut != expOut) {
       
   170             throw new RuntimeException("Cipher " + c + ", in: " + inLen +
       
   171                     ", expOut: " + expOut + ", actual: " + actualOut);
       
   172         }
       
   173     }
       
   174 
       
   175     private static byte[] getRandBuf(int len) {
       
   176         byte[] buf = new byte[len];
       
   177         SR.nextBytes(buf);
       
   178         return buf;
       
   179     }
       
   180 }
       
   181