| /* |
| * Copyright (c) 2007, 2015, 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.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.security.AlgorithmParameters; |
| import java.security.InvalidAlgorithmParameterException; |
| import java.security.InvalidKeyException; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.NoSuchProviderException; |
| import java.util.Arrays; |
| import javax.crypto.CipherInputStream; |
| import javax.crypto.CipherOutputStream; |
| import javax.crypto.NoSuchPaddingException; |
| import javax.crypto.SecretKey; |
| import javax.crypto.Cipher; |
| import javax.crypto.KeyGenerator; |
| |
| /* |
| * @test |
| * @bug 8048596 |
| * @summary Check if wrong or empty AAD is rejected |
| */ |
| public class WrongAAD { |
| |
| private static final String PROVIDER = "SunJCE"; |
| private static final String TRANSFORMATION = "AES/GCM/NoPadding"; |
| private static final int TEXT_SIZE = 800; |
| private static final int KEY_SIZE = 128; |
| private static final int AAD_SIZE = 128; |
| |
| private final SecretKey key; |
| private final byte[] plainText; |
| private final Cipher encryptCipher; |
| |
| public WrongAAD() throws Exception { |
| // init a secret key |
| KeyGenerator kg = KeyGenerator.getInstance("AES", PROVIDER); |
| kg.init(KEY_SIZE); |
| key = kg.generateKey(); |
| |
| // generate a plain text |
| plainText = Helper.generateBytes(TEXT_SIZE); |
| |
| // init AADs |
| byte[] AAD = Helper.generateBytes(AAD_SIZE); |
| |
| // init a cipher |
| encryptCipher = createCipher(Cipher.ENCRYPT_MODE, null); |
| encryptCipher.updateAAD(AAD); |
| } |
| |
| public static void main(String[] args) throws Exception { |
| WrongAAD test = new WrongAAD(); |
| test.decryptWithEmptyAAD(); |
| test.decryptWithWrongAAD(); |
| } |
| |
| /* |
| * Attempt to decrypt a cipher text using Cipher object |
| * initialized without AAD used for encryption. |
| */ |
| private void decryptWithEmptyAAD() throws Exception { |
| System.out.println("decryptWithEmptyAAD() started"); |
| // initialize it with empty AAD to get exception during decryption |
| Cipher decryptCipher = createCipher(Cipher.DECRYPT_MODE, |
| encryptCipher.getParameters()); |
| try (ByteArrayOutputStream baOutput = new ByteArrayOutputStream(); |
| CipherOutputStream ciOutput = new CipherOutputStream(baOutput, |
| decryptCipher)) { |
| if (decrypt(ciOutput, baOutput)) { |
| throw new RuntimeException( |
| "Decryption has been perfomed successfully in" |
| + " spite of the decrypt Cipher has NOT been" |
| + " initialized with AAD"); |
| } |
| } |
| System.out.println("decryptWithEmptyAAD() passed"); |
| } |
| |
| /* |
| * Attempt to decrypt the cipher text using Cipher object |
| * initialized with some fake AAD. |
| */ |
| private void decryptWithWrongAAD() throws Exception { |
| System.out.println("decrypt with wrong AAD"); |
| |
| // initialize it with wrong AAD to get an exception during decryption |
| Cipher decryptCipher = createCipher(Cipher.DECRYPT_MODE, |
| encryptCipher.getParameters()); |
| byte[] someAAD = Helper.generateBytes(AAD_SIZE + 1); |
| decryptCipher.updateAAD(someAAD); |
| |
| // init output stream |
| try (ByteArrayOutputStream baOutput = new ByteArrayOutputStream(); |
| CipherOutputStream ciOutput = new CipherOutputStream(baOutput, |
| decryptCipher);) { |
| if (decrypt(ciOutput, baOutput)) { |
| throw new RuntimeException( |
| "A decryption has been perfomed successfully in" |
| + " spite of the decrypt Cipher has been" |
| + " initialized with fake AAD"); |
| } |
| } |
| |
| System.out.println("Passed"); |
| } |
| |
| private boolean decrypt(CipherOutputStream ciOutput, |
| ByteArrayOutputStream baOutput) throws IOException { |
| try (ByteArrayInputStream baInput = new ByteArrayInputStream(plainText); |
| CipherInputStream ciInput = new CipherInputStream(baInput, |
| encryptCipher)) { |
| byte[] buffer = new byte[TEXT_SIZE]; |
| int len = ciInput.read(buffer); |
| |
| while (len != -1) { |
| ciOutput.write(buffer, 0, len); |
| len = ciInput.read(buffer); |
| } |
| ciOutput.flush(); |
| byte[] recoveredText = baOutput.toByteArray(); |
| System.out.println("recoveredText: " + new String(recoveredText)); |
| |
| /* |
| * See bug 8012900, AEADBadTagException is swalloed by CI/CO streams |
| * If recovered text is empty, than decryption failed |
| */ |
| if (recoveredText.length == 0) { |
| return false; |
| } |
| return Arrays.equals(plainText, recoveredText); |
| } catch (IllegalStateException e) { |
| System.out.println("Expected IllegalStateException: " |
| + e.getMessage()); |
| e.printStackTrace(System.out); |
| return false; |
| } |
| } |
| |
| private Cipher createCipher(int mode, AlgorithmParameters params) |
| throws NoSuchAlgorithmException, NoSuchProviderException, |
| NoSuchPaddingException, InvalidKeyException, |
| InvalidAlgorithmParameterException { |
| Cipher cipher = Cipher.getInstance(TRANSFORMATION, PROVIDER); |
| if (params != null) { |
| cipher.init(mode, key, params); |
| } else { |
| cipher.init(mode, key); |
| } |
| return cipher; |
| } |
| } |