Path: blob/master/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyNoReuse.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* @library /test/lib ..27* @run main/othervm TestChaChaPolyNoReuse28* @summary Test PKCS#11 ChaCha20-Poly1305 Cipher Implementation29* (key/nonce reuse check)30*/3132import java.util.*;33import javax.crypto.Cipher;34import java.security.spec.AlgorithmParameterSpec;35import java.security.Provider;36import java.security.NoSuchAlgorithmException;37import javax.crypto.spec.ChaCha20ParameterSpec;38import javax.crypto.spec.IvParameterSpec;39import javax.crypto.spec.SecretKeySpec;40import javax.crypto.AEADBadTagException;41import javax.crypto.SecretKey;42import java.security.InvalidKeyException;43import java.security.InvalidAlgorithmParameterException;4445public class TestChaChaPolyNoReuse extends PKCS11Test {4647private static final String KEY_ALGO = "ChaCha20";48private static final String CIPHER_ALGO = "ChaCha20-Poly1305";4950/**51* Basic TestMethod interface definition52*/53public interface TestMethod {54/**55* Runs the actual test case56*57* @param provider the provider to provide the requested Cipher obj.58*59* @return true if the test passes, false otherwise.60*/61boolean run(Provider p);62}6364public static class TestData {65public TestData(String name, String keyStr, String nonceStr, int ctr,66int dir, String inputStr, String aadStr, String outStr) {67testName = Objects.requireNonNull(name);68HexFormat hex = HexFormat.of();69key = hex.parseHex(keyStr);70nonce = hex.parseHex(nonceStr);71if ((counter = ctr) < 0) {72throw new IllegalArgumentException(73"counter must be 0 or greater");74}75direction = dir;76if (direction != Cipher.ENCRYPT_MODE) {77throw new IllegalArgumentException(78"Direction must be ENCRYPT_MODE");79}80input = hex.parseHex(inputStr);81aad = (aadStr != null) ? hex.parseHex(aadStr) : null;82expOutput = hex.parseHex(outStr);83}8485public final String testName;86public final byte[] key;87public final byte[] nonce;88public final int counter;89public final int direction;90public final byte[] input;91public final byte[] aad;92public final byte[] expOutput;93}9495public static final List<TestData> aeadTestList =96new LinkedList<TestData>() {{97add(new TestData("RFC 7539 Sample AEAD Test Vector",98"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",99"070000004041424344454647",1001, Cipher.ENCRYPT_MODE,101"4c616469657320616e642047656e746c656d656e206f662074686520636c6173" +102"73206f66202739393a204966204920636f756c64206f6666657220796f75206f" +103"6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73" +104"637265656e20776f756c642062652069742e",105"50515253c0c1c2c3c4c5c6c7",106"d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d6" +107"3dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b36" +108"92ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc" +109"3ff4def08e4b7a9de576d26586cec64b61161ae10b594f09e26a7e902ecbd060" +110"0691"));111}};112113/**114* Make sure we do not use this Cipher object without initializing it115* at all116*/117public static final TestMethod noInitTest = new TestMethod() {118@Override119public boolean run(Provider p) {120System.out.println("----- No Init Test -----");121try {122Cipher cipher = Cipher.getInstance(CIPHER_ALGO, p);123TestData testData = aeadTestList.get(0);124125// Attempting to use the cipher without initializing it126// should throw an IllegalStateException127try {128cipher.updateAAD(testData.aad);129throw new RuntimeException(130"Expected IllegalStateException not thrown");131} catch (IllegalStateException ise) {132// Do nothing, this is what we expected to happen133}134} catch (Exception exc) {135System.out.println("Unexpected exception: " + exc);136exc.printStackTrace();137return false;138}139140return true;141}142};143144/**145* Attempt to run two full encryption operations without an init in146* between.147*/148public static final TestMethod encTwiceNoInit = new TestMethod() {149@Override150public boolean run(Provider p) {151System.out.println("----- Encrypt 2nd time without init -----");152try {153AlgorithmParameterSpec spec;154Cipher cipher = Cipher.getInstance(CIPHER_ALGO, p);155TestData testData = aeadTestList.get(0);156spec = new IvParameterSpec(testData.nonce);157SecretKey key = new SecretKeySpec(testData.key, KEY_ALGO);158159// Initialize and encrypt160cipher.init(testData.direction, key, spec);161cipher.updateAAD(testData.aad);162cipher.doFinal(testData.input);163System.out.println("First encryption complete");164165// Now attempt to encrypt again without changing the key/IV166// This should fail.167try {168cipher.updateAAD(testData.aad);169} catch (IllegalStateException ise) {170// Do nothing, this is what we expected to happen171}172try {173cipher.doFinal(testData.input);174throw new RuntimeException(175"Expected IllegalStateException not thrown");176} catch (IllegalStateException ise) {177// Do nothing, this is what we expected to happen178}179} catch (Exception exc) {180System.out.println("Unexpected exception: " + exc);181exc.printStackTrace();182return false;183}184185return true;186}187};188189/**190* Encrypt once successfully, then attempt to init with the same191* key and nonce.192*/193public static final TestMethod encTwiceInitSameParams = new TestMethod() {194@Override195public boolean run(Provider p) {196System.out.println("----- Encrypt, then init with same params " +197"-----");198try {199AlgorithmParameterSpec spec;200Cipher cipher = Cipher.getInstance(CIPHER_ALGO, p);201TestData testData = aeadTestList.get(0);202spec = new IvParameterSpec(testData.nonce);203SecretKey key = new SecretKeySpec(testData.key, KEY_ALGO);204205// Initialize then encrypt206cipher.init(testData.direction, key, spec);207cipher.updateAAD(testData.aad);208cipher.doFinal(testData.input);209System.out.println("First encryption complete");210211// Initializing after the completed encryption with212// the same key and nonce should fail.213try {214cipher.init(testData.direction, key, spec);215throw new RuntimeException(216"Expected IKE or IAPE not thrown");217} catch (InvalidKeyException |218InvalidAlgorithmParameterException e) {219// Do nothing, this is what we expected to happen220}221} catch (Exception exc) {222System.out.println("Unexpected exception: " + exc);223exc.printStackTrace();224return false;225}226227return true;228}229};230231public static final List<TestMethod> testMethodList =232Arrays.asList(noInitTest, encTwiceNoInit, encTwiceInitSameParams);233234@Override235public void main(Provider p) throws Exception {236System.out.println("Testing " + p.getName());237try {238Cipher.getInstance(CIPHER_ALGO, p);239} catch (NoSuchAlgorithmException nsae) {240System.out.println("Skip; no support for " + CIPHER_ALGO);241return;242}243244int testsPassed = 0;245int testNumber = 0;246247for (TestMethod tm : testMethodList) {248testNumber++;249boolean result = tm.run(p);250System.out.println("Result: " + (result ? "PASS" : "FAIL"));251if (result) {252testsPassed++;253}254}255256System.out.println("Total Tests: " + testNumber +257", Tests passed: " + testsPassed);258if (testsPassed < testNumber) {259throw new RuntimeException(260"Not all tests passed. See output for failure info");261}262}263264public static void main(String[] args) throws Exception {265main(new TestChaChaPolyNoReuse(), args);266}267}268269270