Path: blob/master/test/jdk/javax/crypto/CipherSpi/DirectBBRemaining.java
41149 views
/*1* Copyright (c) 2012, 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 714250926* @summary Cipher.doFinal(ByteBuffer,ByteBuffer) fails to27* process when in.remaining() == 028* @key randomness29*/3031import java.nio.ByteBuffer;32import java.security.SecureRandom;33import java.util.Arrays;34import java.util.Random;3536import javax.crypto.Cipher;37import javax.crypto.SecretKey;38import javax.crypto.spec.SecretKeySpec;3940/*41* Simple test case to show that Cipher.doFinal(ByteBuffer, ByteBuffer) fails to42* process the data internally buffered inBB the cipher when input.remaining()43* == 0 and at least one buffer is a direct buffer.44*/45public class DirectBBRemaining {4647private static Random random = new SecureRandom();48private static int testSizes = 40;49private static int outputFrequency = 5;5051public static void main(String args[]) throws Exception {52boolean failedOnce = false;53Exception failedReason = null;5455byte[] keyBytes = new byte[8];56random.nextBytes(keyBytes);57SecretKey key = new SecretKeySpec(keyBytes, "DES");5859Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding", "SunJCE");60cipher.init(Cipher.ENCRYPT_MODE, key);6162/*63* Iterate through various sizes to make sure that the code does empty64* blocks, single partial blocks, 1 full block, full + partial blocks,65* multiple full blocks, etc. 5 blocks (using DES) is probably overkill66* but will feel more confident the fix isn't breaking anything.67*/68System.out.println("Output test results for every "69+ outputFrequency + " tests...");7071for (int size = 0; size <= testSizes; size++) {72boolean output = (size % outputFrequency) == 0;73if (output) {74System.out.print("\nTesting buffer size: " + size + ":");75}7677int outSize = cipher.getOutputSize(size);7879try {80encrypt(cipher, size,81ByteBuffer.allocate(size),82ByteBuffer.allocate(outSize),83ByteBuffer.allocateDirect(size),84ByteBuffer.allocateDirect(outSize),85output);86} catch (Exception e) {87System.out.print("\n Failed with size " + size);88failedOnce = true;89failedReason = e;9091// If we got an exception, let's be safe for future92// testing and reset the cipher to a known good state.93cipher.init(Cipher.ENCRYPT_MODE, key);94}95}96if (failedOnce) {97throw failedReason;98}99System.out.println("\nTest Passed...");100}101102private enum TestVariant {103104HEAP_HEAP, HEAP_DIRECT, DIRECT_HEAP, DIRECT_DIRECT105};106107private static void encrypt(Cipher cipher, int size,108ByteBuffer heapIn, ByteBuffer heapOut,109ByteBuffer directIn, ByteBuffer directOut,110boolean output) throws Exception {111112ByteBuffer inBB = null;113ByteBuffer outBB = null;114115// Set up data and encrypt to known/expected values.116byte[] testdata = new byte[size];117random.nextBytes(testdata);118byte[] expected = cipher.doFinal(testdata);119120for (TestVariant tv : TestVariant.values()) {121if (output) {122System.out.print(" " + tv);123}124125switch (tv) {126case HEAP_HEAP:127inBB = heapIn;128outBB = heapOut;129break;130case HEAP_DIRECT:131inBB = heapIn;132outBB = directOut;133break;134case DIRECT_HEAP:135inBB = directIn;136outBB = heapOut;137break;138case DIRECT_DIRECT:139inBB = directIn;140outBB = directOut;141break;142}143144inBB.clear();145outBB.clear();146147inBB.put(testdata);148inBB.flip();149150// Process all data in one shot, but don't call doFinal() yet.151// May store up to n-1 bytes (w/block size n) internally.152cipher.update(inBB, outBB);153if (inBB.hasRemaining()) {154throw new Exception("buffer not empty");155}156157// finish encryption and process all data buffered158cipher.doFinal(inBB, outBB);159outBB.flip();160161// validate output size162if (outBB.remaining() != expected.length) {163throw new Exception(164"incomplete encryption output, expected "165+ expected.length + " bytes but was only "166+ outBB.remaining() + " bytes");167}168169// validate output data170byte[] encrypted = new byte[outBB.remaining()];171outBB.get(encrypted);172if (!Arrays.equals(expected, encrypted)) {173throw new Exception("bad encryption output");174}175176if (!Arrays.equals(cipher.doFinal(), cipher.doFinal())) {177throw new Exception("Internal buffers still held data!");178}179}180}181}182183184