Path: blob/master/test/jdk/javax/crypto/CipherSpi/CipherByteBufferOverwriteTest.java
41152 views
/*1* Copyright (c) 2019, 2020, 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 818138626* @summary CipherSpi ByteBuffer to byte array conversion fails for27* certain data overlap conditions28* @run main CipherByteBufferOverwriteTest AES/CBC/PKCS5Padding 0 false29* @run main CipherByteBufferOverwriteTest AES/CBC/PKCS5Padding 0 true30* @run main CipherByteBufferOverwriteTest AES/CBC/PKCS5Padding 4 false31* @run main CipherByteBufferOverwriteTest AES/CBC/PKCS5Padding 4 true32* @run main CipherByteBufferOverwriteTest AES/GCM/NoPadding 0 false33* @run main CipherByteBufferOverwriteTest AES/GCM/NoPadding 0 true34* @run main CipherByteBufferOverwriteTest AES/GCM/NoPadding 4 false35* @run main CipherByteBufferOverwriteTest AES/GCM/NoPadding 4 true36*/3738import java.math.BigInteger;39import java.security.spec.AlgorithmParameterSpec;40import javax.crypto.Cipher;41import javax.crypto.SecretKey;42import javax.crypto.spec.GCMParameterSpec;43import javax.crypto.spec.IvParameterSpec;44import javax.crypto.spec.SecretKeySpec;45import java.nio.ByteBuffer;46import java.util.Arrays;4748public class CipherByteBufferOverwriteTest {4950private static final boolean DEBUG = false;5152private static String transformation;5354// must be larger than the temp array size, i.e. 4096, hardcoded in55// javax.crypto.CipherSpi class56private static final int PLAINTEXT_SIZE = 8192;57// leave room for padding58private static final int CIPHERTEXT_BUFFER_SIZE = PLAINTEXT_SIZE + 32;5960private static final SecretKey KEY = new SecretKeySpec(new byte[16], "AES");61private static AlgorithmParameterSpec params;6263private static ByteBuffer inBuf;64private static ByteBuffer outBuf;6566private enum BufferType {67ALLOCATE, DIRECT, WRAP;68}6970public static void main(String[] args) throws Exception {7172transformation = args[0];73int offset = Integer.parseInt(args[1]);74boolean useRO = Boolean.parseBoolean(args[2]);7576if (transformation.equalsIgnoreCase("AES/GCM/NoPadding")) {77params = new GCMParameterSpec(16 * 8, new byte[16]);78} else {79params = new IvParameterSpec(new byte[16]);80}81// an all-zeros plaintext is the easiest way to demonstrate the issue,82// but it fails with any plaintext, of course83byte[] expectedPT = new byte[PLAINTEXT_SIZE];84byte[] buf = new byte[offset + CIPHERTEXT_BUFFER_SIZE];85System.arraycopy(expectedPT, 0, buf, 0, PLAINTEXT_SIZE);8687// generate expected cipher text using byte[] methods88Cipher c = Cipher.getInstance(transformation);89c.init(Cipher.ENCRYPT_MODE, KEY, params);90byte[] expectedCT = c.doFinal(expectedPT);9192// Test#1: against ByteBuffer generated with allocate(int) call93prepareBuffers(BufferType.ALLOCATE, useRO, buf.length,94buf, 0, PLAINTEXT_SIZE, offset);9596runTest(offset, expectedPT, expectedCT);97System.out.println("\tALLOCATE: passed");9899// Test#2: against direct ByteBuffer100prepareBuffers(BufferType.DIRECT, useRO, buf.length,101buf, 0, PLAINTEXT_SIZE, offset);102103runTest(offset, expectedPT, expectedCT);104System.out.println("\tDIRECT: passed");105106// Test#3: against ByteBuffer wrapping existing array107prepareBuffers(BufferType.WRAP, useRO, buf.length,108buf, 0, PLAINTEXT_SIZE, offset);109110runTest(offset, expectedPT, expectedCT);111System.out.println("\tWRAP: passed");112113System.out.println("All Tests Passed");114}115116private static void prepareBuffers(BufferType type,117boolean useRO, int bufSz, byte[] in, int inOfs, int inLen,118int outOfs) {119switch (type) {120case ALLOCATE:121outBuf = ByteBuffer.allocate(bufSz);122inBuf = outBuf.slice();123inBuf.put(in, inOfs, inLen);124inBuf.rewind();125inBuf.limit(inLen);126outBuf.position(outOfs);127break;128case DIRECT:129outBuf = ByteBuffer.allocateDirect(bufSz);130inBuf = outBuf.slice();131inBuf.put(in, inOfs, inLen);132inBuf.rewind();133inBuf.limit(inLen);134outBuf.position(outOfs);135break;136case WRAP:137if (in.length < bufSz) {138throw new RuntimeException("ERROR: Input buffer too small");139}140outBuf = ByteBuffer.wrap(in);141inBuf = ByteBuffer.wrap(in, inOfs, inLen);142outBuf.position(outOfs);143break;144}145if (useRO) {146inBuf = inBuf.asReadOnlyBuffer();147}148if (DEBUG) {149System.out.println("inBuf, pos = " + inBuf.position() +150", capacity = " + inBuf.capacity() +151", limit = " + inBuf.limit() +152", remaining = " + inBuf.remaining());153System.out.println("outBuf, pos = " + outBuf.position() +154", capacity = " + outBuf.capacity() +155", limit = " + outBuf.limit() +156", remaining = " + outBuf.remaining());157}158}159160private static void runTest(int ofs, byte[] expectedPT, byte[] expectedCT)161throws Exception {162163Cipher c = Cipher.getInstance(transformation);164c.init(Cipher.ENCRYPT_MODE, KEY, params);165int ciphertextSize = c.doFinal(inBuf, outBuf);166167// read out the encrypted result168outBuf.position(ofs);169byte[] finalCT = new byte[ciphertextSize];170if (DEBUG) {171System.out.println("runTest, ciphertextSize = " + ciphertextSize);172System.out.println("runTest, ofs = " + ofs +173", remaining = " + finalCT.length +174", limit = " + outBuf.limit());175}176outBuf.get(finalCT);177178if (!Arrays.equals(finalCT, expectedCT)) {179System.err.println("Ciphertext mismatch:" +180"\nresult (len=" + finalCT.length + "):\n" +181String.format("%0" + (finalCT.length << 1) + "x",182new BigInteger(1, finalCT)) +183"\nexpected (len=" + expectedCT.length + "):\n" +184String.format("%0" + (expectedCT.length << 1) + "x",185new BigInteger(1, expectedCT)));186throw new Exception("ERROR: Ciphertext does not match");187}188189// now do decryption190outBuf.position(ofs);191outBuf.limit(ofs + ciphertextSize);192c.init(Cipher.DECRYPT_MODE, KEY, params);193ByteBuffer finalPTBuf = ByteBuffer.allocate(194c.getOutputSize(outBuf.remaining()));195c.doFinal(outBuf, finalPTBuf);196197// read out the decrypted result198finalPTBuf.flip();199byte[] finalPT = new byte[finalPTBuf.remaining()];200finalPTBuf.get(finalPT);201202if (!Arrays.equals(finalPT, expectedPT)) {203System.err.println("Ciphertext mismatch " +204"):\nresult (len=" + finalCT.length + "):\n" +205String.format("%0" + (finalCT.length << 1) + "x",206new BigInteger(1, finalCT)) +207"\nexpected (len=" + expectedCT.length + "):\n" +208String.format("%0" + (expectedCT.length << 1) + "x",209new BigInteger(1, expectedCT)));210throw new Exception("ERROR: Plaintext does not match");211}212}213}214215216217