/* * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.nio.ByteBuffer; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; import java.util.Random; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; /** * @test * @bug 8041787 * @summary verify that Mac.update works with different size ByteBuffer * @author Alexander Fomin * @run main PBMacBuffer */ public class PBMacBuffer { private final int LARGE_SIZE = 500000; public static void main(String[] args) { String[] PBMAC1Algorithms = { "HmacPBESHA1", "PBEWithHmacSHA1", "PBEWithHmacSHA224", "PBEWithHmacSHA256", "PBEWithHmacSHA384", "PBEWithHmacSHA512" }; String[] PBKDF2Algorithms = { "PBKDF2WithHmacSHA1", "PBKDF2WithHmacSHA224", "PBKDF2WithHmacSHA256", "PBKDF2WithHmacSHA384", "PBKDF2WithHmacSHA512" }; PBMacBuffer testRunner = new PBMacBuffer(); boolean failed = false; for (String thePBMacAlgo : PBMAC1Algorithms) { for (String thePBKDF2Algo : PBKDF2Algorithms) { System.out.println("Running test with " + thePBMacAlgo + " and " + thePBKDF2Algo + ":"); try { if (!testRunner.doTest(thePBMacAlgo, thePBKDF2Algo)) { failed = true; } } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException e) { failed = true; e.printStackTrace(System.out); System.out.println("Test FAILED."); } } } if (failed) { throw new RuntimeException("One or more tests failed...."); } } /** * Tests Mac.update(ByteBuffer input) method. Three test cases are * performed: - large ByteBuffer test case to test if the update() method * process a large ByteBuffer correctly; - empty ByteBuffer test case to * test if the update() method process an empty ByteBuffer correctly; - NULL * ByteBuffer test case to test if the update() method throws expected * IllegalArgumentException exception. * * @param theMacAlgo PBMAC algorithm to test * @param thePBKDF2Algo PBKDF2 algorithm to test * @return true - test passed; false - otherwise. * @throws NoSuchAlgorithmException * @throws InvalidKeyException * @throws InvalidKeySpecException * @see javax.crypto.Mac */ protected boolean doTest(String theMacAlgo, String thePBKDF2Algo) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException { // obtain a SecretKey using PBKDF2 SecretKey key = getSecretKey(thePBKDF2Algo); // Instantiate Mac object and init it with a SecretKey Mac theMac = Mac.getInstance(theMacAlgo); theMac.init(key); // Do large ByteBuffer test case if (!largeByteBufferTest(theMac)) { System.out.println("Large ByteBuffer test case failed."); return false; } // Do empty ByteBuffer test case if (!emptyByteBufferTest(theMac)) { System.out.println("Empty ByteBuffer test case failed."); return false; } // Do null ByteBuffer test case if (!nullByteBufferTest(theMac)) { System.out.println("NULL ByteBuffer test case failed."); return false; } return true; } /** * Large ByteBuffer test case. Generate random ByteBuffer of LARGE_SIZE * size. Performs MAC operation with the given Mac object (theMac * parameter).Verifies the assertion "Upon return, the buffer's position * will be equal to its limit; its limit will not have changed". * * @param theMac MAC object to test. * @return true - test case passed; false - otherwise; */ protected boolean largeByteBufferTest(Mac theMac) { ByteBuffer buf = generateRandomByteBuffer(LARGE_SIZE); int limitBefore = buf.limit(); theMac.update(buf); theMac.doFinal(); int limitAfter = buf.limit(); int positonAfter = buf.position(); if (limitAfter != limitBefore) { System.out.println("FAIL: Buffer's limit has been chenged."); return false; } if (positonAfter != limitAfter) { System.out.println("FAIL: " + "Buffer's position isn't equal to its limit"); return false; } return true; } /** * Empty ByteBuffer test case. Generates an empty ByteBuffer. Perform MAC * operation. No exceptions are expected. * * @param theMac * @return true - test case pass; exception otherwise */ protected boolean emptyByteBufferTest(Mac theMac) { ByteBuffer buf = generateRandomByteBuffer(0); theMac.update(buf); theMac.doFinal(); return true; } /** * NULL ByteBuffer test case. Pass NULL ByteBuffer to Mac.update(ByteBuffer * buffer) method. An IllegalArgumentException expected. * * @param theMac Mac object to test. * @return true - test case pass; false - otherwise. */ protected boolean nullByteBufferTest(Mac theMac) { try { ByteBuffer buf = null; theMac.update(buf); theMac.doFinal(); } catch (IllegalArgumentException e) { // expected exception has been thrown return true; } System.out.println("FAIL: " + "IllegalArgumentException hasn't been thrown as expected"); return false; } /** * Get SecretKey for the given PBKDF2 algorithm. * * @param thePBKDF2Algorithm - PBKDF2 algorithm * @return SecretKey according to thePBKDF2Algorithm * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException */ protected SecretKey getSecretKey(String thePBKDF2Algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException { // Prepare salt byte[] salt = new byte[64]; // PKCS #5 v2.1 recommendation new SecureRandom().nextBytes(salt); // Generate secret key PBEKeySpec pbeKeySpec = new PBEKeySpec( "A #pwd# implied to be hidden!".toCharArray(), salt, 1000, 128); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(thePBKDF2Algorithm); return keyFactory.generateSecret(pbeKeySpec); } /** * An utility method to generate a random ByteBuffer of the requested size. * * @param size size of the ByteBuffer. * @return ByteBuffer populated random data; */ private ByteBuffer generateRandomByteBuffer(int size) { // generate randome byte array byte[] data = new byte[size]; new Random().nextBytes(data); // create ByteBuffer ByteBuffer bb = ByteBuffer.wrap(data); return bb; } }