Path: blob/master/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPoly.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* @modules jdk.crypto.cryptoki28* @run main/othervm TestChaChaPoly29* @summary test for PKCS#11 ChaCha20-Poly1305 Cipher.30*/3132import java.nio.ByteBuffer;33import java.security.AlgorithmParameters;34import java.security.InvalidAlgorithmParameterException;35import java.security.NoSuchAlgorithmException;36import java.security.GeneralSecurityException;37import java.security.Provider;38import java.security.SecureRandom;39import java.security.spec.InvalidParameterSpecException;40import java.util.Arrays;41import java.util.HexFormat;4243import javax.crypto.Cipher;44import javax.crypto.spec.ChaCha20ParameterSpec;45import javax.crypto.spec.IvParameterSpec;46import javax.crypto.spec.SecretKeySpec;47import javax.crypto.NoSuchPaddingException;4849import jdk.test.lib.Utils;5051public class TestChaChaPoly extends PKCS11Test {5253private static final byte[] NONCE54= HexFormat.of().parseHex("012345670123456701234567");55private static final SecretKeySpec KEY = new SecretKeySpec(56HexFormat.of().parseHex("0123456701234567012345670123456701234567012345670123456701234567"),57"ChaCha20");58private static final ChaCha20ParameterSpec CHACHA20_PARAM_SPEC59= new ChaCha20ParameterSpec(NONCE, 0);60private static final IvParameterSpec IV_PARAM_SPEC61= new IvParameterSpec(NONCE);62private static final String ALGO = "ChaCha20-Poly1305";63private static final SecureRandom RAND = new SecureRandom();64private static Provider p;6566@Override67public void main(Provider p) throws Exception {68System.out.println("Testing " + p.getName());69try {70Cipher.getInstance(ALGO, p);71} catch (NoSuchAlgorithmException nsae) {72System.out.println("Skip; no support for " + ALGO);73return;74}75this.p = p;76testTransformations();77testInit();78testAEAD();79testGetBlockSize();80testGetIV();81testInterop("SunJCE");82}8384private static void testTransformations() throws Exception {85System.out.println("== transformations ==");8687checkTransformation(p, ALGO, true);88checkTransformation(p, ALGO + "/None/NoPadding", true);89checkTransformation(p, ALGO + "/ECB/NoPadding", false);90checkTransformation(p, ALGO + "/None/PKCS5Padding", false);91}9293private static void checkTransformation(Provider p, String t,94boolean expected) throws Exception {95try {96Cipher.getInstance(t, p);97if (!expected) {98throw new RuntimeException( "Should reject transformation: " +99t);100} else {101System.out.println("Accepted transformation: " + t);102}103} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {104if (!expected) {105System.out.println("Rejected transformation: " + t);106} else {107throw new RuntimeException("Should accept transformation: " +108t, e);109}110}111}112113private static void testInit() throws Exception {114testInitOnCrypt(Cipher.ENCRYPT_MODE);115testInitOnCrypt(Cipher.DECRYPT_MODE);116}117118private static void testInitOnCrypt(int opMode) throws Exception {119System.out.println("== init (" + getOpModeName(opMode) + ") ==");120121// Need to acquire new Cipher object as ChaCha20-Poly1305 cipher122// disallow reusing the same key and iv pair123Cipher.getInstance(ALGO, p).init(opMode, KEY, IV_PARAM_SPEC);124Cipher c = Cipher.getInstance(ALGO, p);125c.init(opMode, KEY, IV_PARAM_SPEC, RAND);126AlgorithmParameters params = c.getParameters();127Cipher.getInstance(ALGO, p).init(opMode, KEY, params, RAND);128129try {130// try with invalid param131Cipher.getInstance(ALGO, p).init(opMode, KEY, CHACHA20_PARAM_SPEC);132throw new RuntimeException("Should reject non-IvparameterSpec");133} catch (InvalidAlgorithmParameterException e) {134System.out.println("Expected IAPE - " + e);135}136}137138private static void testAEAD() throws Exception {139byte[] expectedPt = HexFormat.of().parseHex("01234567");140byte[] ct = testUpdateAAD(Cipher.ENCRYPT_MODE, expectedPt);141byte[] pt = testUpdateAAD(Cipher.DECRYPT_MODE, ct);142if (pt != null && !Arrays.equals(pt, expectedPt)) {143System.out.println("ciphertext: " + Arrays.toString(ct));144System.out.println("plaintext: " + Arrays.toString(pt));145throw new RuntimeException("AEAD failed");146}147}148149private static byte[] testUpdateAAD(int opMode, byte[] input)150throws Exception {151String opModeName = getOpModeName(opMode);152System.out.println("== updateAAD (" + opModeName + ") ==");153154byte[] aad = HexFormat.of().parseHex("0000");155ByteBuffer aadBuf = ByteBuffer.wrap(aad);156157Cipher ccp = Cipher.getInstance(ALGO, p);158try {159ccp.updateAAD(aadBuf);160throw new RuntimeException(161"Should throw ISE for setting AAD on uninit'ed Cipher");162} catch (IllegalStateException e) {163System.out.println("Expected ISE - " + e);164}165166ccp.init(opMode, KEY, IV_PARAM_SPEC);167ccp.update(input);168try {169ccp.updateAAD(aad);170throw new RuntimeException(171"Should throw ISE for setting AAD after update");172} catch (IllegalStateException e) {173System.out.println("Expected ISE - " + e);174}175176ccp.init(opMode, KEY, IV_PARAM_SPEC);177ccp.updateAAD(aadBuf);178return ccp.doFinal(input);179}180181private static void testGetBlockSize() throws Exception {182testGetBlockSize(Cipher.ENCRYPT_MODE);183testGetBlockSize(Cipher.DECRYPT_MODE);184}185186private static void testGetBlockSize(int opMode) throws Exception {187System.out.println("== getBlockSize (" + getOpModeName(opMode) + ") ==");188Cipher c = Cipher.getInstance(ALGO, p);189if (c.getBlockSize() != 0) {190throw new RuntimeException("Block size must be 0");191}192}193194private static void testGetIV() throws Exception {195testGetIV(Cipher.ENCRYPT_MODE);196testGetIV(Cipher.DECRYPT_MODE);197}198199private static void testGetIV(int opMode) throws Exception {200System.out.println("== getIv (" + getOpModeName(opMode) + ") ==");201202try {203Cipher.getInstance(ALGO, p).getIV();204Cipher.getInstance(ALGO, p).getParameters();205} catch (Exception e) {206throw new RuntimeException("Should not throw ex", e);207}208// first init w/ key only209AlgorithmParameters params = null;210for (int i = 0; i < 6; i++) {211System.out.println("IV test# " + i);212Cipher c = Cipher.getInstance(ALGO, p);213byte[] expectedIV = NONCE;214try {215switch (i) {216case 0 -> {217c.init(opMode, KEY);218expectedIV = null; // randomly-generated219}220case 1 -> {221c.init(opMode, KEY, RAND);222expectedIV = null; // randomly-generated223}224case 2 -> {225c.init(opMode, KEY, IV_PARAM_SPEC);226params = c.getParameters();227if (params == null) {228throw new RuntimeException("Params should not be null");229}230}231case 3 -> c.init(opMode, KEY, IV_PARAM_SPEC, RAND);232case 4 -> c.init(opMode, KEY, params);233case 5 -> c.init(opMode, KEY, params, RAND);234}235checkIV(c, expectedIV);236System.out.println("=> Passed");237} catch (GeneralSecurityException e) {238if (opMode == Cipher.DECRYPT_MODE && i < 2) {239System.out.println("=> Passed: Expected Ex thrown");240} else {241throw new RuntimeException("Should not throw ex", e);242}243}244}245}246247private static void checkIV(Cipher c, byte[] expectedIv) {248// the specified cipher has been initialized; the returned IV and249// AlgorithmParameters object should be non-null250byte[] iv = c.getIV();251AlgorithmParameters params = c.getParameters();252// fail if either is null253if (iv == null || params == null) {254throw new RuntimeException("getIV()/getParameters() should " +255"not return null");256}257258// check iv matches if not null259if (expectedIv != null && !Arrays.equals(expectedIv, iv)) {260throw new RuntimeException("IV should match expected value");261}262263try {264byte[] iv2 = params.getParameterSpec(IvParameterSpec.class).getIV();265if (!Arrays.equals(iv, iv2)) {266throw new RuntimeException("IV values should be consistent");267}268} catch (InvalidParameterSpecException ipe) {269// should never happen270throw new AssertionError();271}272}273274private static void testInterop(String interopProv) throws Exception {275testInterop(Cipher.getInstance(ALGO, p),276Cipher.getInstance(ALGO, interopProv));277testInterop(Cipher.getInstance(ALGO, interopProv),278Cipher.getInstance(ALGO, p));279}280281private static void testInterop(Cipher encCipher, Cipher decCipher)282throws Exception {283System.out.println("Interop: " + encCipher.getProvider().getName() +284" -> " + encCipher.getProvider().getName());285byte[] pt = HexFormat.of().parseHex("012345678901234567890123456789");286encCipher.init(Cipher.ENCRYPT_MODE, KEY);287byte[] ct = encCipher.doFinal(pt);288decCipher.init(Cipher.DECRYPT_MODE, KEY, encCipher.getParameters());289byte[] pt2 = decCipher.doFinal(ct);290if (!Arrays.equals(pt, pt2)) {291System.out.println("HexDump/pt: " + HexFormat.of().formatHex(pt));292System.out.println("HexDump/pt2: " + HexFormat.of().formatHex(pt2));293throw new RuntimeException("Recovered data should match");294}295System.out.println("=> Passed");296}297298private static String getOpModeName(int opMode) {299switch (opMode) {300case Cipher.ENCRYPT_MODE:301return "ENCRYPT";302303case Cipher.DECRYPT_MODE:304return "DECRYPT";305306case Cipher.WRAP_MODE:307return "WRAP";308309case Cipher.UNWRAP_MODE:310return "UNWRAP";311312default:313return "";314}315}316317public static void main(String[] args) throws Exception {318main(new TestChaChaPoly(), args);319}320}321322323