Path: blob/master/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyOutputSize.java
41152 views
/*1* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/**24* @test25* @bug 825541026* @summary Check ChaCha20-Poly1305 cipher output size27* @library /test/lib ..28* @build jdk.test.lib.Convert29* @run main TestChaChaPolyOutputSize30*/3132import java.nio.ByteBuffer;33import java.security.GeneralSecurityException;34import java.security.Key;35import java.security.SecureRandom;36import java.security.Provider;37import java.security.NoSuchAlgorithmException;38import javax.crypto.Cipher;39import javax.crypto.spec.ChaCha20ParameterSpec;40import javax.crypto.spec.IvParameterSpec;41import javax.crypto.spec.SecretKeySpec;4243public class TestChaChaPolyOutputSize extends PKCS11Test {4445private static final SecureRandom SR = new SecureRandom();4647private static final SecretKeySpec KEY = new SecretKeySpec(new byte[32],48"ChaCha20");4950private static final String ALGO = "ChaCha20-Poly1305";5152public static void main(String args[]) throws Exception {53main(new TestChaChaPolyOutputSize(), args);54}5556@Override57public void main(Provider p) throws GeneralSecurityException {58System.out.println("Testing " + p.getName());59try {60Cipher.getInstance(ALGO, p);61} catch (NoSuchAlgorithmException nsae) {62System.out.println("Skip; no support for " + ALGO);63return;64}65testGetOutSize(p);66testMultiPartAEADDec(p);67}6869private static void testGetOutSize(Provider p)70throws GeneralSecurityException {7172Cipher ccp = Cipher.getInstance(ALGO, p);73ccp.init(Cipher.ENCRYPT_MODE, KEY,74new IvParameterSpec(getRandBuf(12)));7576// Encryption lengths are calculated as the input length plus the tag77// length (16).78testOutLen(ccp, 0, 16);79testOutLen(ccp, 5, 21);80testOutLen(ccp, 5120, 5136);81// perform an update, then test with a final block82byte[] input = new byte[5120];83SR.nextBytes(input);84byte[] updateOut = ccp.update(input);85testOutLen(ccp, 1024, 1040 +86(5120 - (updateOut == null? 0 : updateOut.length)));8788// Decryption lengths are handled differently for AEAD mode. The length89// should be zero for anything up to and including the first 16 bytes90// (since that's the tag). Anything above that should be the input91// length plus any unprocessed input (via update calls), minus the92// 16 byte tag.93ccp.init(Cipher.DECRYPT_MODE, KEY, new IvParameterSpec(getRandBuf(12)));94testOutLen(ccp, 0, 0);95testOutLen(ccp, 5, 0);96testOutLen(ccp, 16, 0);97testOutLen(ccp, 5120, 5104);98// Perform an update, then test with the length of a final chunk99// of data.100updateOut = ccp.update(input);101testOutLen(ccp, 1024, 6128 - (updateOut == null? 0 : updateOut.length));102}103104private static void testMultiPartAEADDec(Provider p)105throws GeneralSecurityException {106IvParameterSpec ivps = new IvParameterSpec(getRandBuf(12));107108// Encrypt some data so we can test decryption.109byte[] pText = getRandBuf(2048);110ByteBuffer pTextBase = ByteBuffer.wrap(pText);111112Cipher enc = Cipher.getInstance(ALGO, p);113enc.init(Cipher.ENCRYPT_MODE, KEY, ivps);114ByteBuffer ctBuf = ByteBuffer.allocateDirect(115enc.getOutputSize(pText.length));116enc.doFinal(pTextBase, ctBuf);117118// Create a new direct plain text ByteBuffer which will catch the119// decrypted data.120ByteBuffer ptBuf = ByteBuffer.allocateDirect(pText.length);121122// Set the cipher text buffer limit to roughly half the data so we can123// do an update/final sequence.124ctBuf.position(0).limit(1024);125126Cipher dec = Cipher.getInstance(ALGO, p);127dec.init(Cipher.DECRYPT_MODE, KEY, ivps);128dec.update(ctBuf, ptBuf);129System.out.println("CTBuf: " + ctBuf);130System.out.println("PTBuf: " + ptBuf);131ctBuf.limit(ctBuf.capacity());132dec.doFinal(ctBuf, ptBuf);133134// NOTE: do not use flip() which will set limit based on current135// position. ptBuf curr pos = 2048 vs pTextBase pos = 0136ptBuf.flip();137pTextBase.flip();138System.out.println("PT Base:" + pTextBase);139System.out.println("PT Actual:" + ptBuf);140141if (pTextBase.compareTo(ptBuf) != 0) {142StringBuilder sb = new StringBuilder();143sb.append("Plaintext mismatch: Original: ").144append(pTextBase.toString()).append("\nActual :").145append(ptBuf);146throw new RuntimeException(sb.toString());147}148}149150private static void testOutLen(Cipher c, int inLen, int expOut) {151int actualOut = c.getOutputSize(inLen);152if (actualOut != expOut) {153throw new RuntimeException("Cipher " + c + ", in: " + inLen +154", expOut: " + expOut + ", actual: " + actualOut);155}156}157158private static byte[] getRandBuf(int len) {159byte[] buf = new byte[len];160SR.nextBytes(buf);161return buf;162}163}164165166