| /* |
| * 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; |
| } |
| |
| } |