mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-01 03:30:34 +00:00
8048596: Tests for AEAD ciphers
Reviewed-by: valeriep
This commit is contained in:
parent
7cd090f230
commit
b6bee08125
753
jdk/test/com/sun/crypto/provider/Cipher/AEAD/Encrypt.java
Normal file
753
jdk/test/com/sun/crypto/provider/Cipher/AEAD/Encrypt.java
Normal file
@ -0,0 +1,753 @@
|
||||
/*
|
||||
* 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.nio.ByteBuffer;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8048596
|
||||
* @summary AEAD encryption/decryption test
|
||||
*/
|
||||
|
||||
/*
|
||||
* The test does the following:
|
||||
* - create an input text and additional data
|
||||
* - generate a secret key
|
||||
* - instantiate a cipher according to the GCM transformation
|
||||
* - generate an outputText using a single-part encryption/decryption
|
||||
* in AEAD mode
|
||||
* - perform 16 different combinations of multiple-part encryption/decryption
|
||||
* operation in AEAD mode (in encryption mode new Cipher object is created
|
||||
* and initialized with the same secret key and parameters)
|
||||
* - check that all 17 results are equal
|
||||
*
|
||||
* Combinations:
|
||||
*
|
||||
* combination #1
|
||||
* updateAAD(byte[] src)
|
||||
* update(byte[], int, int)
|
||||
* doFinal(byte[], int, int)
|
||||
*
|
||||
* combination #2
|
||||
* updateAAD(byte[] src)
|
||||
* update(byte[], int, int)
|
||||
* doFinal(byte[], int, int, byte[], int)
|
||||
*
|
||||
* combination #3
|
||||
* updateAAD(byte[] src)
|
||||
* update(byte[], int, int, byte[], int)
|
||||
* doFinal(byte[], int, int)
|
||||
*
|
||||
* combination #4
|
||||
* updateAAD(byte[] src)
|
||||
* update(byte[], int, int, byte[], int)
|
||||
* doFinal(byte[], int, int, byte[], int)
|
||||
*
|
||||
* combination #5 - #8 are similar to #1 -#4,
|
||||
* but with updateAAD(byte[] src, int offset, int len)
|
||||
*
|
||||
* combination #9 - #12 are similar to #1 - #4,
|
||||
* but with updateAAD(ByteBuffer src)
|
||||
*
|
||||
* combination #13 - #16 are similar to #9 - #12 but with directly allocated
|
||||
* ByteBuffer and update(ByteBuffer input, ByteBuffer output)
|
||||
*
|
||||
*/
|
||||
public class Encrypt {
|
||||
|
||||
private static final String ALGORITHMS[] = { "AES", "Rijndael" };
|
||||
private static final int KEY_STRENGTHS[] = { 128, 192, 256 };
|
||||
private static final int TEXT_LENGTHS[] = { 0, 256, 1024 };
|
||||
private static final int AAD_LENGTHS[] = { 0, 8, 128, 256, 1024 };
|
||||
private static final int ARRAY_OFFSET = 8;
|
||||
|
||||
private final String transformation;
|
||||
private final Provider provider;
|
||||
private final SecretKey key;
|
||||
private final int textLength;
|
||||
private final int AADLength;
|
||||
|
||||
/**
|
||||
* @param provider Security provider
|
||||
* @param algorithm Security algorithm to test
|
||||
* @param mode The mode (GCM is only expected)
|
||||
* @param padding Algorithm padding
|
||||
* @param keyStrength key length
|
||||
* @param textLength Plain text length
|
||||
* @param AADLength Additional data length
|
||||
*/
|
||||
public Encrypt(Provider provider, String algorithm, String mode,
|
||||
String padding, int keyStrength, int textLength, int AADLength)
|
||||
throws Exception {
|
||||
|
||||
// init a secret Key
|
||||
KeyGenerator kg = KeyGenerator.getInstance(algorithm, provider);
|
||||
kg.init(keyStrength);
|
||||
key = kg.generateKey();
|
||||
|
||||
this.provider = provider;
|
||||
this.transformation = algorithm + "/" + mode + "/" + padding;
|
||||
this.textLength = textLength;
|
||||
this.AADLength = AADLength;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Provider p = Security.getProvider("SunJCE");
|
||||
for (String alg : ALGORITHMS) {
|
||||
for (int keyStrength : KEY_STRENGTHS) {
|
||||
if (keyStrength > Cipher.getMaxAllowedKeyLength(alg)) {
|
||||
// skip this if this key length is larger than what's
|
||||
// configured in the JCE jurisdiction policy files
|
||||
continue;
|
||||
}
|
||||
for (int textLength : TEXT_LENGTHS) {
|
||||
for (int AADLength : AAD_LENGTHS) {
|
||||
Encrypt test = new Encrypt(p, alg,
|
||||
"GCM", "NoPadding", keyStrength, textLength,
|
||||
AADLength);
|
||||
Cipher cipher = test.createCipher(Cipher.ENCRYPT_MODE,
|
||||
null);
|
||||
AlgorithmParameters params = cipher.getParameters();
|
||||
test.doTest(params);
|
||||
System.out.println("Test " + alg + ":"
|
||||
+ keyStrength + ":" + textLength + ":"
|
||||
+ AADLength + " passed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void doTest(AlgorithmParameters params) throws Exception {
|
||||
System.out.println("Test transformation = " + transformation
|
||||
+ ", textLength = " + textLength
|
||||
+ ", AADLength = " + AADLength);
|
||||
byte[] input = Helper.generateBytes(textLength);
|
||||
byte[] AAD = Helper.generateBytes(AADLength);
|
||||
byte[] result = execute(Cipher.ENCRYPT_MODE, AAD, input, params);
|
||||
result = execute(Cipher.DECRYPT_MODE, AAD, result, params);
|
||||
if (!Arrays.equals(input, result)) {
|
||||
throw new RuntimeException("Test failed");
|
||||
}
|
||||
System.out.println("Test passed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Cipher object for the requested encryption/decryption mode.
|
||||
*
|
||||
* @param mode encryption or decryption mode
|
||||
* @return Cipher object initiated to perform requested mode operation
|
||||
*/
|
||||
private Cipher createCipher(int mode, AlgorithmParameters params)
|
||||
throws Exception {
|
||||
Cipher ci;
|
||||
if (Cipher.ENCRYPT_MODE == mode) {
|
||||
// create a new Cipher object for encryption
|
||||
ci = Cipher.getInstance(transformation, provider);
|
||||
|
||||
// initiate it with the saved parameters
|
||||
if (params != null) {
|
||||
ci.init(Cipher.ENCRYPT_MODE, key, params);
|
||||
} else {
|
||||
// initiate the cipher without parameters
|
||||
ci.init(Cipher.ENCRYPT_MODE, key);
|
||||
}
|
||||
} else {
|
||||
// it is expected that parameters already generated
|
||||
// before decryption
|
||||
ci = Cipher.getInstance(transformation, provider);
|
||||
ci.init(Cipher.DECRYPT_MODE, key, params);
|
||||
}
|
||||
|
||||
return ci;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test AEAD combinations
|
||||
*
|
||||
* @param mode decryption or encryption
|
||||
* @param AAD additional data for AEAD operations
|
||||
* @param inputText plain text to decrypt/encrypt
|
||||
* @return output text after encrypt/decrypt
|
||||
*/
|
||||
public byte[] execute(int mode, byte[] AAD, byte[] inputText,
|
||||
AlgorithmParameters params) throws Exception {
|
||||
|
||||
Cipher cipher = createCipher(mode, params);
|
||||
|
||||
// results of each combination will be saved in the outputTexts
|
||||
List<byte[]> outputTexts = new ArrayList<>();
|
||||
|
||||
// generate a standard outputText using a single-part en/de-cryption
|
||||
cipher.updateAAD(AAD);
|
||||
byte[] output = cipher.doFinal(inputText);
|
||||
|
||||
// execute multiple-part encryption/decryption combinations
|
||||
combination_1(outputTexts, mode, AAD, inputText, params);
|
||||
combination_2(outputTexts, mode, AAD, inputText, params);
|
||||
combination_3(outputTexts, mode, AAD, inputText, params);
|
||||
combination_4(outputTexts, mode, AAD, inputText, params);
|
||||
combination_5(outputTexts, mode, AAD, inputText, params);
|
||||
combination_6(outputTexts, mode, AAD, inputText, params);
|
||||
combination_7(outputTexts, mode, AAD, inputText, params);
|
||||
combination_8(outputTexts, mode, AAD, inputText, params);
|
||||
combination_9(outputTexts, mode, AAD, inputText, params);
|
||||
combination_10(outputTexts, mode, AAD, inputText, params);
|
||||
combination_11(outputTexts, mode, AAD, inputText, params);
|
||||
combination_12(outputTexts, mode, AAD, inputText, params);
|
||||
combination_13(outputTexts, mode, AAD, inputText, params);
|
||||
combination_14(outputTexts, mode, AAD, inputText, params);
|
||||
combination_15(outputTexts, mode, AAD, inputText, params);
|
||||
combination_16(outputTexts, mode, AAD, inputText, params);
|
||||
|
||||
for (int k = 0; k < outputTexts.size(); k++) {
|
||||
if (!Arrays.equals(output, outputTexts.get(k))) {
|
||||
throw new RuntimeException("Combination #" + k + " failed");
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #1:
|
||||
* updateAAD(byte[] src)
|
||||
* update(byte[], int, int)
|
||||
* doFinal(byte[], int, int)
|
||||
*/
|
||||
private void combination_1(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
Cipher c = createCipher(mode, params);
|
||||
c.updateAAD(AAD);
|
||||
byte[] part11 = c.update(plainText, 0, plainText.length);
|
||||
int part11_length = part11 == null ? 0 : part11.length;
|
||||
byte[] part12 = c.doFinal();
|
||||
byte[] outputText1 = new byte[part11_length + part12.length];
|
||||
if (part11 != null) {
|
||||
System.arraycopy(part11, 0, outputText1, 0, part11_length);
|
||||
}
|
||||
System.arraycopy(part12, 0, outputText1, part11_length, part12.length);
|
||||
results.add(outputText1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #2:
|
||||
* updateAAD(byte[] src)
|
||||
* update(byte[], int, int)
|
||||
* doFinal(byte[], int, int, byte[], int)
|
||||
*/
|
||||
private void combination_2(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
Cipher c = createCipher(mode, params);
|
||||
c.updateAAD(AAD);
|
||||
int t = 0;
|
||||
int offset = 0;
|
||||
if (plainText.length > ARRAY_OFFSET) {
|
||||
t = plainText.length - ARRAY_OFFSET;
|
||||
offset = ARRAY_OFFSET;
|
||||
}
|
||||
byte[] part21 = c.update(plainText, 0, t);
|
||||
byte[] part22 = new byte[c.getOutputSize(plainText.length)];
|
||||
int len2 = c.doFinal(plainText, t, offset, part22, 0);
|
||||
int part21Length = part21 != null ? part21.length : 0;
|
||||
byte[] outputText2 = new byte[part21Length + len2];
|
||||
if (part21 != null) {
|
||||
System.arraycopy(part21, 0, outputText2, 0, part21Length);
|
||||
}
|
||||
System.arraycopy(part22, 0, outputText2, part21Length, len2);
|
||||
results.add(outputText2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #3
|
||||
* updateAAD(byte[] src)
|
||||
* update(byte[], int, int, byte[], int)
|
||||
* doFinal(byte[], int, int)
|
||||
*/
|
||||
private void combination_3(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
Cipher ci = createCipher(mode, params);
|
||||
ci.updateAAD(AAD);
|
||||
byte[] part31 = new byte[ci.getOutputSize(plainText.length)];
|
||||
int offset = plainText.length > ARRAY_OFFSET ? ARRAY_OFFSET : 0;
|
||||
int len = ci.update(plainText, 0, plainText.length - offset, part31, 0);
|
||||
byte[] part32 = ci.doFinal(plainText, plainText.length - offset,
|
||||
offset);
|
||||
byte[] outputText3 = new byte[len + part32.length];
|
||||
System.arraycopy(part31, 0, outputText3, 0, len);
|
||||
System.arraycopy(part32, 0, outputText3, len, part32.length);
|
||||
results.add(outputText3);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #4:
|
||||
* updateAAD(byte[] src)
|
||||
* update(byte[], int, int, byte[], int)
|
||||
* doFinal(byte[], int, int, byte[], int)
|
||||
*/
|
||||
private void combination_4(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
Cipher ci = createCipher(mode, params);
|
||||
ci.updateAAD(AAD);
|
||||
byte[] part41 = new byte[ci.getOutputSize(plainText.length)];
|
||||
int offset = plainText.length > ARRAY_OFFSET ? ARRAY_OFFSET : 0;
|
||||
int len = ci.update(plainText, 0, plainText.length - offset, part41, 0);
|
||||
int rest4 = ci.doFinal(plainText, plainText.length - offset, offset,
|
||||
part41, len);
|
||||
byte[] outputText4 = new byte[len + rest4];
|
||||
System.arraycopy(part41, 0, outputText4, 0, outputText4.length);
|
||||
results.add(outputText4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #5:
|
||||
* updateAAD(byte[] src, int offset, int len)
|
||||
* update(byte[], int, int)
|
||||
* doFinal(byte[], int, int)
|
||||
*/
|
||||
private void combination_5(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
Cipher c = createCipher(mode, params);
|
||||
c.updateAAD(AAD, 0, AAD.length);
|
||||
byte[] part51 = c.update(plainText, 0, plainText.length);
|
||||
byte[] part52 = c.doFinal();
|
||||
int part51Length = part51 != null ? part51.length : 0;
|
||||
byte[] outputText5 = new byte[part51Length + part52.length];
|
||||
if (part51 != null) {
|
||||
System.arraycopy(part51, 0, outputText5, 0, part51Length);
|
||||
}
|
||||
System.arraycopy(part52, 0, outputText5, part51Length, part52.length);
|
||||
results.add(outputText5);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #6:
|
||||
* updateAAD(byte[] src, int offset, int len)
|
||||
* updateAAD(byte[] src, int offset, int len)
|
||||
* update(byte[], int, int) doFinal(byte[], int, int, byte[], int)
|
||||
*/
|
||||
private void combination_6(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
Cipher c = createCipher(mode, params);
|
||||
c.updateAAD(AAD, 0, AAD.length / 2);
|
||||
c.updateAAD(AAD, AAD.length / 2, AAD.length - AAD.length / 2);
|
||||
int t = 0;
|
||||
int offset = 0;
|
||||
if (plainText.length > ARRAY_OFFSET) {
|
||||
t = plainText.length - ARRAY_OFFSET;
|
||||
offset = ARRAY_OFFSET;
|
||||
}
|
||||
byte[] part61 = c.update(plainText, 0, t);
|
||||
byte[] part62 = new byte[c.getOutputSize(plainText.length)];
|
||||
int len = c.doFinal(plainText, t, offset, part62, 0);
|
||||
int part61Length = part61 != null ? part61.length : 0;
|
||||
byte[] outputText6 = new byte[part61Length + len];
|
||||
if (part61 != null) {
|
||||
System.arraycopy(part61, 0, outputText6, 0, part61Length);
|
||||
}
|
||||
System.arraycopy(part62, 0, outputText6, part61Length, len);
|
||||
results.add(outputText6);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #7
|
||||
* updateAAD(byte[] src, int offset, int len)
|
||||
* updateAAD(byte[] src, src.length, 0)
|
||||
* update(byte[], int, int, byte[], int) doFinal(byte[],int, int)
|
||||
*/
|
||||
private void combination_7(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
Cipher ci = createCipher(mode, params);
|
||||
ci.updateAAD(AAD, 0, AAD.length);
|
||||
ci.updateAAD(AAD, AAD.length, 0);
|
||||
byte[] part71 = new byte[ci.getOutputSize(plainText.length)];
|
||||
int offset = plainText.length > ARRAY_OFFSET ? ARRAY_OFFSET : 0;
|
||||
int len = ci.update(plainText, 0, plainText.length - offset, part71, 0);
|
||||
byte[] part72 = ci.doFinal(plainText, plainText.length - offset, offset);
|
||||
byte[] outputText7 = new byte[len + part72.length];
|
||||
System.arraycopy(part71, 0, outputText7, 0, len);
|
||||
System.arraycopy(part72, 0, outputText7, len, part72.length);
|
||||
results.add(outputText7);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #8:
|
||||
* updateAAD(byte[] src, 0, 0)
|
||||
* updateAAD(byte[] src, 0, src.length)
|
||||
* update(byte[], int, int, byte[], int)
|
||||
* doFinal(byte[], int, int, byte[], int)
|
||||
*/
|
||||
private void combination_8(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
Cipher ci = createCipher(mode, params);
|
||||
ci.updateAAD(AAD, 0, 0);
|
||||
ci.updateAAD(AAD, 0, AAD.length);
|
||||
byte[] part81 = new byte[ci.getOutputSize(plainText.length)];
|
||||
int offset = plainText.length > ARRAY_OFFSET ? ARRAY_OFFSET : 0;
|
||||
int len = ci.update(plainText, 0, plainText.length - offset, part81, 0);
|
||||
int rest = ci.doFinal(plainText, plainText.length - offset, offset,
|
||||
part81, len);
|
||||
byte[] outputText8 = new byte[len + rest];
|
||||
System.arraycopy(part81, 0, outputText8, 0, outputText8.length);
|
||||
results.add(outputText8);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #9:
|
||||
* updateAAD(ByteBuffer src)
|
||||
* update(byte[], int, int) doFinal(byte[], int, int)
|
||||
*/
|
||||
private void combination_9(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
|
||||
// prepare ByteBuffer to test
|
||||
ByteBuffer buf = ByteBuffer.allocate(AAD.length);
|
||||
buf.put(AAD);
|
||||
buf.position(0);
|
||||
buf.limit(AAD.length);
|
||||
|
||||
// Get Cipher object and do the combination
|
||||
Cipher c = createCipher(mode, params);
|
||||
c.updateAAD(buf);
|
||||
byte[] part91 = c.update(plainText, 0, plainText.length);
|
||||
int part91_length = part91 == null ? 0 : part91.length;
|
||||
byte[] part92 = c.doFinal();
|
||||
byte[] outputText9 = new byte[part91_length + part92.length];
|
||||
|
||||
// form result of the combination
|
||||
if (part91 != null) {
|
||||
System.arraycopy(part91, 0, outputText9, 0, part91_length);
|
||||
}
|
||||
System.arraycopy(part92, 0, outputText9, part91_length, part92.length);
|
||||
results.add(outputText9);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #10:
|
||||
* updateAAD(ByteBuffer src)
|
||||
* updateAAD(ByteBuffer src) update(byte[], int, int)
|
||||
* doFinal(byte[], int, int, byte[], int)
|
||||
*/
|
||||
private void combination_10(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
|
||||
// prepare ByteBuffer to test
|
||||
ByteBuffer buf = ByteBuffer.allocate(AAD.length);
|
||||
buf.put(AAD);
|
||||
buf.position(0);
|
||||
buf.limit(AAD.length / 2);
|
||||
|
||||
// get a Cipher object and do the combination
|
||||
Cipher c = createCipher(mode, params);
|
||||
|
||||
// process the first half of AAD data
|
||||
c.updateAAD(buf);
|
||||
|
||||
// process the rest of AAD data
|
||||
buf.limit(AAD.length);
|
||||
c.updateAAD(buf);
|
||||
|
||||
// prapare variables for the combination
|
||||
int t = 0;
|
||||
int offset = 0;
|
||||
if (plainText.length > ARRAY_OFFSET) {
|
||||
t = plainText.length - ARRAY_OFFSET;
|
||||
offset = ARRAY_OFFSET;
|
||||
}
|
||||
|
||||
// encrypt the text
|
||||
byte[] part10_1 = c.update(plainText, 0, t);
|
||||
int part10_1_Length = part10_1 != null ? part10_1.length : 0;
|
||||
byte[] part10_2 = new byte[c.getOutputSize(plainText.length)];
|
||||
int len2 = c.doFinal(plainText, t, offset, part10_2, 0);
|
||||
|
||||
// form the combination's result
|
||||
byte[] outputText10 = new byte[part10_1_Length + len2];
|
||||
if (part10_1 != null) {
|
||||
System.arraycopy(part10_1, 0, outputText10, 0, part10_1_Length);
|
||||
}
|
||||
System.arraycopy(part10_2, 0, outputText10, part10_1_Length, len2);
|
||||
results.add(outputText10);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #11
|
||||
* updateAAD(ByteBuffer src1)
|
||||
* updateAAD(ByteBuffer src2)
|
||||
* update(byte[],int, int, byte[], int)
|
||||
* doFinal(byte[], int, int)
|
||||
*/
|
||||
private void combination_11(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
|
||||
// prepare ByteBuffer1 to test
|
||||
ByteBuffer buf1 = ByteBuffer.allocate(AAD.length / 2);
|
||||
buf1.put(AAD, 0, AAD.length / 2);
|
||||
buf1.position(0);
|
||||
buf1.limit(AAD.length / 2);
|
||||
|
||||
// get a Cipher object and do combination
|
||||
Cipher ci = createCipher(mode, params);
|
||||
|
||||
// process the first half of AAD data
|
||||
ci.updateAAD(buf1);
|
||||
|
||||
// prepare ByteBuffer2 to test
|
||||
ByteBuffer buf2 = ByteBuffer.allocate(AAD.length - AAD.length / 2);
|
||||
buf2.put(AAD, AAD.length / 2, AAD.length - AAD.length / 2);
|
||||
buf2.position(0);
|
||||
buf2.limit(AAD.length - AAD.length / 2);
|
||||
|
||||
// process the rest of AAD data
|
||||
ci.updateAAD(buf2);
|
||||
|
||||
// encrypt plain text
|
||||
byte[] part11_1 = new byte[ci.getOutputSize(plainText.length)];
|
||||
int offset = plainText.length > ARRAY_OFFSET ? ARRAY_OFFSET : 0;
|
||||
int len_11 = ci.update(plainText, 0, plainText.length - offset,
|
||||
part11_1, 0);
|
||||
byte[] part11_2 = ci.doFinal(plainText, plainText.length - offset,
|
||||
offset);
|
||||
byte[] outputText11 = new byte[len_11 + part11_2.length];
|
||||
System.arraycopy(part11_1, 0, outputText11, 0, len_11);
|
||||
System.arraycopy(part11_2, 0, outputText11, len_11, part11_2.length);
|
||||
results.add(outputText11);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #12:
|
||||
* updateAAD(ByteBuffer src)
|
||||
* updateAAD(ByteBuffer emptyByteBuffer)
|
||||
* update(byte[], int, int, byte[], int)
|
||||
* doFinal(byte[], int, int, byte[], int)
|
||||
*/
|
||||
private void combination_12(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
|
||||
// prepare ByteBuffer to test
|
||||
ByteBuffer buf = ByteBuffer.allocate(AAD.length);
|
||||
buf.put(AAD);
|
||||
buf.position(0);
|
||||
buf.limit(AAD.length);
|
||||
Cipher ci = createCipher(mode, params);
|
||||
ci.updateAAD(buf);
|
||||
|
||||
// prepare an empty ByteBuffer
|
||||
ByteBuffer emptyBuf = ByteBuffer.allocate(0);
|
||||
emptyBuf.put(new byte[0]);
|
||||
ci.updateAAD(emptyBuf);
|
||||
byte[] part12_1 = new byte[ci.getOutputSize(plainText.length)];
|
||||
int offset = plainText.length > ARRAY_OFFSET ? ARRAY_OFFSET : 0;
|
||||
int len12 = ci.update(plainText, 0, plainText.length - offset,
|
||||
part12_1, 0);
|
||||
int rest12 = ci.doFinal(plainText, plainText.length - offset, offset,
|
||||
part12_1, len12);
|
||||
byte[] outputText12 = new byte[len12 + rest12];
|
||||
System.arraycopy(part12_1, 0, outputText12, 0, outputText12.length);
|
||||
results.add(outputText12);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #13:
|
||||
* updateAAD(ByteBuffer src), where src is directly allocated
|
||||
* update(ByteBuffer input, ByteBuffer out)
|
||||
* doFinal(ByteBuffer input, ByteBuffer out)
|
||||
*/
|
||||
private void combination_13(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
Cipher c = createCipher(mode, params);
|
||||
|
||||
// prepare ByteBuffer to test
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(AAD.length);
|
||||
buf.put(AAD);
|
||||
buf.position(0);
|
||||
buf.limit(AAD.length);
|
||||
c.updateAAD(buf);
|
||||
|
||||
// prepare buffers to encrypt/decrypt
|
||||
ByteBuffer in = ByteBuffer.allocateDirect(plainText.length);
|
||||
in.put(plainText);
|
||||
in.position(0);
|
||||
in.limit(plainText.length);
|
||||
ByteBuffer output = ByteBuffer.allocateDirect(
|
||||
c.getOutputSize(in.limit()));
|
||||
output.position(0);
|
||||
output.limit(c.getOutputSize(in.limit()));
|
||||
|
||||
// process input text
|
||||
c.update(in, output);
|
||||
c.doFinal(in, output);
|
||||
int resultSize = output.position();
|
||||
byte[] result13 = new byte[resultSize];
|
||||
output.position(0);
|
||||
output.limit(resultSize);
|
||||
output.get(result13, 0, resultSize);
|
||||
results.add(result13);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #14:
|
||||
* updateAAD(ByteBuffer src) updateAAD(ByteBuffer src),
|
||||
* where src is directly allocated
|
||||
* update(ByteBuffer input, ByteBuffer out)
|
||||
* doFinal(ByteBuffer input, ByteBuffer out)
|
||||
*/
|
||||
private void combination_14(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
Cipher c = createCipher(mode, params);
|
||||
// prepare ByteBuffer to test
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(AAD.length);
|
||||
buf.put(AAD);
|
||||
|
||||
// process the first half of AAD data
|
||||
buf.position(0);
|
||||
buf.limit(AAD.length / 2);
|
||||
c.updateAAD(buf);
|
||||
|
||||
// process the rest of AAD data
|
||||
buf.limit(AAD.length);
|
||||
c.updateAAD(buf);
|
||||
|
||||
// prepare buffers to encrypt/decrypt
|
||||
ByteBuffer in = ByteBuffer.allocate(plainText.length);
|
||||
in.put(plainText);
|
||||
in.position(0);
|
||||
in.limit(plainText.length);
|
||||
ByteBuffer out = ByteBuffer.allocate(c.getOutputSize(in.limit()));
|
||||
out.position(0);
|
||||
out.limit(c.getOutputSize(in.limit()));
|
||||
|
||||
// process input text
|
||||
c.update(in, out);
|
||||
c.doFinal(in, out);
|
||||
int resultSize = out.position();
|
||||
byte[] result14 = new byte[resultSize];
|
||||
out.position(0);
|
||||
out.limit(resultSize);
|
||||
out.get(result14, 0, resultSize);
|
||||
results.add(result14);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #15
|
||||
* updateAAD(ByteBuffer src1), where src1 is directly allocated
|
||||
* updateAAD(ByteBuffer src2), where src2 is directly allocated
|
||||
* doFinal(ByteBuffer input, ByteBuffer out)
|
||||
*/
|
||||
private void combination_15(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
Cipher c = createCipher(mode, params);
|
||||
|
||||
// prepare ByteBuffer1 to test
|
||||
ByteBuffer buf1 = ByteBuffer.allocateDirect(AAD.length / 2);
|
||||
buf1.put(AAD, 0, AAD.length / 2);
|
||||
buf1.position(0);
|
||||
buf1.limit(AAD.length / 2);
|
||||
|
||||
// process the first half of AAD data
|
||||
c.updateAAD(buf1);
|
||||
|
||||
// prepare ByteBuffer2 to test
|
||||
ByteBuffer buf2 = ByteBuffer.allocateDirect(
|
||||
AAD.length - AAD.length / 2);
|
||||
buf2.put(AAD, AAD.length / 2, AAD.length - AAD.length / 2);
|
||||
buf2.position(0);
|
||||
buf2.limit(AAD.length - AAD.length / 2);
|
||||
|
||||
// process the rest of AAD data
|
||||
c.updateAAD(buf2);
|
||||
|
||||
// prepare buffers to encrypt/decrypt
|
||||
ByteBuffer in = ByteBuffer.allocateDirect(plainText.length);
|
||||
in.put(plainText);
|
||||
in.position(0);
|
||||
in.limit(plainText.length);
|
||||
ByteBuffer output = ByteBuffer.allocateDirect(
|
||||
c.getOutputSize(in.limit()));
|
||||
output.position(0);
|
||||
output.limit(c.getOutputSize(in.limit()));
|
||||
|
||||
// process input text
|
||||
c.doFinal(in, output);
|
||||
int resultSize = output.position();
|
||||
byte[] result15 = new byte[resultSize];
|
||||
output.position(0);
|
||||
output.limit(resultSize);
|
||||
output.get(result15, 0, resultSize);
|
||||
results.add(result15);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute multiple-part encryption/decryption combination #16:
|
||||
* updateAAD(ByteBuffer src)
|
||||
* updateAAD(ByteBuffer emptyByteBuffer)
|
||||
* update(ByteBuffer input, ByteBuffer out)
|
||||
* doFinal(EmptyByteBuffer, ByteBuffer out)
|
||||
*/
|
||||
private void combination_16(List<byte[]> results, int mode, byte[] AAD,
|
||||
byte[] plainText, AlgorithmParameters params) throws Exception {
|
||||
Cipher c = createCipher(mode, params);
|
||||
|
||||
// prepare ByteBuffer to test
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(AAD.length);
|
||||
buf.put(AAD);
|
||||
buf.position(0);
|
||||
buf.limit(AAD.length);
|
||||
c.updateAAD(buf);
|
||||
|
||||
// prepare empty ByteBuffer
|
||||
ByteBuffer emptyBuf = ByteBuffer.allocateDirect(0);
|
||||
emptyBuf.put(new byte[0]);
|
||||
c.updateAAD(emptyBuf);
|
||||
|
||||
// prepare buffers to encrypt/decrypt
|
||||
ByteBuffer in = ByteBuffer.allocateDirect(plainText.length);
|
||||
in.put(plainText);
|
||||
in.position(0);
|
||||
in.limit(plainText.length);
|
||||
ByteBuffer output = ByteBuffer.allocateDirect(
|
||||
c.getOutputSize(in.limit()));
|
||||
output.position(0);
|
||||
output.limit(c.getOutputSize(in.limit()));
|
||||
|
||||
// process input text with an empty buffer
|
||||
c.update(in, output);
|
||||
ByteBuffer emptyBuf2 = ByteBuffer.allocate(0);
|
||||
emptyBuf2.put(new byte[0]);
|
||||
c.doFinal(emptyBuf2, output);
|
||||
int resultSize = output.position();
|
||||
byte[] result16 = new byte[resultSize];
|
||||
output.position(0);
|
||||
output.limit(resultSize);
|
||||
output.get(result16, 0, resultSize);
|
||||
results.add(result16);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* 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.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.Arrays;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8048596
|
||||
* @summary Check if GCMParameterSpec works as expected
|
||||
*/
|
||||
public class GCMParameterSpecTest {
|
||||
|
||||
private static final int[] IV_LENGTHS = { 96, 8, 1024 };
|
||||
private static final int[] KEY_LENGTHS = { 128, 192, 256 };
|
||||
private static final int[] DATA_LENGTHS = { 0, 128, 1024 };
|
||||
private static final int[] AAD_LENGTHS = { 0, 128, 1024 };
|
||||
private static final int[] TAG_LENGTHS = { 128, 120, 112, 104, 96 };
|
||||
private static final int[] OFFSETS = { 0, 2, 5, 99 };
|
||||
private static final String TRANSFORMATION = "AES/GCM/NoPadding";
|
||||
private static final String TEMPLATE = "Test:\n tag = %d\n"
|
||||
+ " IV length = %d\n data length = %d\n"
|
||||
+ " AAD length = %d\n offset = %d\n keylength = %d\n";
|
||||
|
||||
private final byte[] IV;
|
||||
private final byte[] IVO;
|
||||
private final byte[] data;
|
||||
private final byte[] AAD;
|
||||
private final SecretKey key;
|
||||
private final int tagLength;
|
||||
private final int IVlength;
|
||||
private final int offset;
|
||||
|
||||
/**
|
||||
* Initialize IV, IV with offset, plain text, AAD and SecretKey
|
||||
*
|
||||
* @param keyLength length of a secret key
|
||||
* @param tagLength tag length
|
||||
* @param IVlength IV length
|
||||
* @param offset offset in a buffer for IV
|
||||
* @param textLength plain text length
|
||||
* @param AADLength AAD length
|
||||
*/
|
||||
public GCMParameterSpecTest(int keyLength, int tagLength, int IVlength,
|
||||
int offset, int textLength, int AADLength)
|
||||
throws NoSuchAlgorithmException, NoSuchProviderException {
|
||||
this.tagLength = tagLength; // save tag length
|
||||
this.IVlength = IVlength; // save IV length
|
||||
this.offset = offset; // save IV offset
|
||||
|
||||
// prepare IV
|
||||
IV = Helper.generateBytes(IVlength);
|
||||
|
||||
// prepare IV with offset
|
||||
IVO = new byte[this.IVlength + this.offset];
|
||||
System.arraycopy(IV, 0, IVO, offset, this.IVlength);
|
||||
|
||||
// prepare data
|
||||
data = Helper.generateBytes(textLength);
|
||||
|
||||
// prepare AAD
|
||||
AAD = Helper.generateBytes(AADLength);
|
||||
|
||||
// init a secret key
|
||||
KeyGenerator kg = KeyGenerator.getInstance("AES", "SunJCE");
|
||||
kg.init(keyLength);
|
||||
key = kg.generateKey();
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the test for each key length, tag length, IV length, plain text
|
||||
* length, AAD length and offset.
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
boolean success = true;
|
||||
for (int k : KEY_LENGTHS) {
|
||||
if (k > Cipher.getMaxAllowedKeyLength(TRANSFORMATION)) {
|
||||
// skip this if this key length is larger than what's
|
||||
// allowed in the jce jurisdiction policy files
|
||||
continue;
|
||||
}
|
||||
for (int t : TAG_LENGTHS) {
|
||||
for (int n : IV_LENGTHS) {
|
||||
for (int p : DATA_LENGTHS) {
|
||||
for (int a : AAD_LENGTHS) {
|
||||
for (int o : OFFSETS) {
|
||||
System.out.printf(TEMPLATE, t, n, p, a, o, k);
|
||||
success &= new GCMParameterSpecTest(
|
||||
k, t, n, o, p, a).doTest();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
throw new RuntimeException("At least one test case failed");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the test:
|
||||
* - check if result of encryption of plain text is the same
|
||||
* when parameters constructed with different GCMParameterSpec
|
||||
* constructors are used
|
||||
* - check if GCMParameterSpec.getTLen() is equal to actual tag length
|
||||
* - check if ciphertext has the same length as plaintext
|
||||
*/
|
||||
private boolean doTest() throws Exception {
|
||||
GCMParameterSpec spec1 = new GCMParameterSpec(tagLength, IV);
|
||||
GCMParameterSpec spec2 = new GCMParameterSpec(tagLength, IVO, offset,
|
||||
IVlength);
|
||||
byte[] cipherText1 = getCipherTextBySpec(spec1);
|
||||
if (cipherText1 == null) {
|
||||
return false;
|
||||
}
|
||||
byte[] cipherText2 = getCipherTextBySpec(spec2);
|
||||
if (cipherText2 == null) {
|
||||
return false;
|
||||
}
|
||||
if (!Arrays.equals(cipherText1, cipherText2)) {
|
||||
System.out.println("Cipher texts are different");
|
||||
return false;
|
||||
}
|
||||
if (spec1.getTLen() != spec2.getTLen()) {
|
||||
System.out.println("Tag lengths are not equal");
|
||||
return false;
|
||||
}
|
||||
byte[] recoveredText1 = recoverCipherText(cipherText1, spec2);
|
||||
if (recoveredText1 == null) {
|
||||
return false;
|
||||
}
|
||||
byte[] recoveredText2 = recoverCipherText(cipherText2, spec1);
|
||||
if (recoveredText2 == null) {
|
||||
return false;
|
||||
}
|
||||
if (!Arrays.equals(recoveredText1, recoveredText2)) {
|
||||
System.out.println("Recovered texts are different");
|
||||
return false;
|
||||
}
|
||||
if (!Arrays.equals(recoveredText1, data)) {
|
||||
System.out.println("Recovered and original texts are not equal");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypt a plain text, and check if GCMParameterSpec.getIV()
|
||||
* is equal to Cipher.getIV()
|
||||
*/
|
||||
private byte[] getCipherTextBySpec(GCMParameterSpec spec) throws Exception {
|
||||
// init a cipher
|
||||
Cipher cipher = createCipher(Cipher.ENCRYPT_MODE, spec);
|
||||
cipher.updateAAD(AAD);
|
||||
byte[] cipherText = cipher.doFinal(data);
|
||||
|
||||
// check IVs
|
||||
if (!Arrays.equals(cipher.getIV(), spec.getIV())) {
|
||||
System.out.println("IV in parameters is incorrect");
|
||||
return null;
|
||||
}
|
||||
if (spec.getTLen() != (cipherText.length - data.length) * 8) {
|
||||
System.out.println("Tag length is incorrect");
|
||||
return null;
|
||||
}
|
||||
return cipherText;
|
||||
}
|
||||
|
||||
private byte[] recoverCipherText(byte[] cipherText, GCMParameterSpec spec)
|
||||
throws Exception {
|
||||
// init a cipher
|
||||
Cipher cipher = createCipher(Cipher.DECRYPT_MODE, spec);
|
||||
|
||||
// check IVs
|
||||
if (!Arrays.equals(cipher.getIV(), spec.getIV())) {
|
||||
System.out.println("IV in parameters is incorrect");
|
||||
return null;
|
||||
}
|
||||
|
||||
cipher.updateAAD(AAD);
|
||||
return cipher.doFinal(cipherText);
|
||||
}
|
||||
|
||||
private Cipher createCipher(int mode, GCMParameterSpec spec)
|
||||
throws Exception {
|
||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION, "SunJCE");
|
||||
cipher.init(mode, key, spec);
|
||||
return cipher;
|
||||
}
|
||||
}
|
||||
33
jdk/test/com/sun/crypto/provider/Cipher/AEAD/Helper.java
Normal file
33
jdk/test/com/sun/crypto/provider/Cipher/AEAD/Helper.java
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
public class Helper {
|
||||
|
||||
public static byte[] generateBytes(int length) {
|
||||
byte[] bytes = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
bytes[i] = (byte) (i % 256);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
87
jdk/test/com/sun/crypto/provider/Cipher/AEAD/KeyWrapper.java
Normal file
87
jdk/test/com/sun/crypto/provider/Cipher/AEAD/KeyWrapper.java
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.security.AlgorithmParameters;
|
||||
import java.security.Key;
|
||||
import java.util.Arrays;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8048596
|
||||
* @summary Check if a key wrapper works properly with GCM mode
|
||||
*/
|
||||
public class KeyWrapper {
|
||||
|
||||
static final String AES = "AES";
|
||||
static final String TRANSFORMATION = "AES/GCM/NoPadding";
|
||||
static final String PROVIDER = "SunJCE";
|
||||
static final int KEY_LENGTH = 128;
|
||||
|
||||
public static void main(String argv[]) throws Exception {
|
||||
doTest(PROVIDER, TRANSFORMATION);
|
||||
}
|
||||
|
||||
private static void doTest(String provider, String algo) throws Exception {
|
||||
SecretKey key;
|
||||
SecretKey keyToWrap;
|
||||
|
||||
// init a secret Key
|
||||
KeyGenerator kg = KeyGenerator.getInstance(AES, PROVIDER);
|
||||
kg.init(KEY_LENGTH);
|
||||
key = kg.generateKey();
|
||||
keyToWrap = kg.generateKey();
|
||||
|
||||
// initialization
|
||||
Cipher cipher = Cipher.getInstance(algo, provider);
|
||||
cipher.init(Cipher.WRAP_MODE, key);
|
||||
AlgorithmParameters params = cipher.getParameters();
|
||||
|
||||
// wrap the key
|
||||
byte[] keyWrapper = cipher.wrap(keyToWrap);
|
||||
try {
|
||||
// check if we can't wrap it again with the same key/IV
|
||||
keyWrapper = cipher.wrap(keyToWrap);
|
||||
throw new RuntimeException(
|
||||
"FAILED: expected IllegalStateException hasn't "
|
||||
+ "been thrown ");
|
||||
} catch (IllegalStateException ise) {
|
||||
System.out.println(ise.getMessage());
|
||||
System.out.println("Expected exception");
|
||||
}
|
||||
|
||||
// unwrap the key
|
||||
cipher.init(Cipher.UNWRAP_MODE, key, params);
|
||||
cipher.unwrap(keyWrapper, algo, Cipher.SECRET_KEY);
|
||||
|
||||
// check if we can unwrap second time
|
||||
Key unwrapKey = cipher.unwrap(keyWrapper, algo, Cipher.SECRET_KEY);
|
||||
|
||||
if (!Arrays.equals(keyToWrap.getEncoded(), unwrapKey.getEncoded())) {
|
||||
throw new RuntimeException(
|
||||
"FAILED: original and unwrapped keys are not equal");
|
||||
}
|
||||
}
|
||||
}
|
||||
317
jdk/test/com/sun/crypto/provider/Cipher/AEAD/ReadWriteSkip.java
Normal file
317
jdk/test/com/sun/crypto/provider/Cipher/AEAD/ReadWriteSkip.java
Normal file
@ -0,0 +1,317 @@
|
||||
/*
|
||||
* 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.GeneralSecurityException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.CipherInputStream;
|
||||
import javax.crypto.CipherOutputStream;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8048596
|
||||
* @summary Test CICO AEAD read/write/skip operations
|
||||
*/
|
||||
public class ReadWriteSkip {
|
||||
|
||||
static enum BufferType {
|
||||
BYTE_ARRAY_BUFFERING, INT_BYTE_BUFFERING
|
||||
}
|
||||
|
||||
static final int KEY_LENGTHS[] = {128, 192, 256};
|
||||
static final int TXT_LENGTHS[] = {800, 0};
|
||||
static final int AAD_LENGTHS[] = {0, 100};
|
||||
static final int BLOCK = 50;
|
||||
static final int SAVE = 45;
|
||||
static final int DISCARD = BLOCK - SAVE;
|
||||
static final String PROVIDER = "SunJCE";
|
||||
static final String AES = "AES";
|
||||
static final String GCM = "GCM";
|
||||
static final String PADDING = "NoPadding";
|
||||
static final String TRANSFORM = AES + "/" + GCM + "/" + PADDING;
|
||||
|
||||
final SecretKey key;
|
||||
final byte[] plaintext;
|
||||
final byte[] AAD;
|
||||
final int textLength;;
|
||||
final int keyLength;
|
||||
Cipher encryptCipher;
|
||||
Cipher decryptCipher;
|
||||
CipherInputStream ciInput;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
boolean success = true;
|
||||
for (int keyLength : KEY_LENGTHS) {
|
||||
if (keyLength > Cipher.getMaxAllowedKeyLength(TRANSFORM)) {
|
||||
// skip this if this key length is larger than what's
|
||||
// configured in the jce jurisdiction policy files
|
||||
continue;
|
||||
}
|
||||
for (int textLength : TXT_LENGTHS) {
|
||||
for (int AADLength : AAD_LENGTHS) {
|
||||
System.out.println("Key length = " + keyLength
|
||||
+ ", text length = " + textLength
|
||||
+ ", AAD length = " + AADLength);
|
||||
try {
|
||||
run(keyLength, textLength, AADLength);
|
||||
System.out.println("Test case passed");
|
||||
} catch (Exception e) {
|
||||
System.out.println("Test case failed: " + e);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
throw new RuntimeException("At least one test case failed");
|
||||
}
|
||||
|
||||
System.out.println("Test passed");
|
||||
}
|
||||
|
||||
ReadWriteSkip(int keyLength, int textLength, int AADLength)
|
||||
throws Exception {
|
||||
this.keyLength = keyLength;
|
||||
this.textLength = textLength;
|
||||
|
||||
// init AAD
|
||||
this.AAD = Helper.generateBytes(AADLength);
|
||||
|
||||
// init a secret Key
|
||||
KeyGenerator kg = KeyGenerator.getInstance(AES, PROVIDER);
|
||||
kg.init(this.keyLength);
|
||||
this.key = kg.generateKey();
|
||||
|
||||
this.plaintext = Helper.generateBytes(textLength);
|
||||
}
|
||||
|
||||
final void doTest(BufferType type) throws Exception {
|
||||
// init ciphers
|
||||
encryptCipher = createCipher(Cipher.ENCRYPT_MODE);
|
||||
decryptCipher = createCipher(Cipher.DECRYPT_MODE);
|
||||
|
||||
// init cipher input stream
|
||||
ciInput = new CipherInputStream(new ByteArrayInputStream(plaintext),
|
||||
encryptCipher);
|
||||
|
||||
runTest(type);
|
||||
}
|
||||
|
||||
void runTest(BufferType type) throws Exception {}
|
||||
|
||||
private Cipher createCipher(int mode) throws GeneralSecurityException {
|
||||
Cipher cipher = Cipher.getInstance(TRANSFORM, PROVIDER);
|
||||
if (mode == Cipher.ENCRYPT_MODE) {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
} else {
|
||||
if (encryptCipher != null) {
|
||||
cipher.init(Cipher.DECRYPT_MODE, key,
|
||||
encryptCipher.getParameters());
|
||||
} else {
|
||||
throw new RuntimeException("Can't create a cipher");
|
||||
}
|
||||
}
|
||||
cipher.updateAAD(AAD);
|
||||
return cipher;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run test cases
|
||||
*/
|
||||
static void run(int keyLength, int textLength, int AADLength)
|
||||
throws Exception {
|
||||
new ReadWriteTest(keyLength, textLength, AADLength)
|
||||
.doTest(BufferType.BYTE_ARRAY_BUFFERING);
|
||||
new ReadWriteTest(keyLength, textLength, AADLength)
|
||||
.doTest(BufferType.INT_BYTE_BUFFERING);
|
||||
new SkipTest(keyLength, textLength, AADLength)
|
||||
.doTest(BufferType.BYTE_ARRAY_BUFFERING);
|
||||
new SkipTest(keyLength, textLength, AADLength)
|
||||
.doTest(BufferType.INT_BYTE_BUFFERING);
|
||||
}
|
||||
|
||||
static void check(byte[] first, byte[] second) {
|
||||
if (!Arrays.equals(first, second)) {
|
||||
throw new RuntimeException("Arrays are not equal");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* CICO AEAD read/write functional test.
|
||||
*
|
||||
* Check if encrypt/decrypt operations work correctly.
|
||||
*
|
||||
* Test scenario:
|
||||
* - initializes plain text
|
||||
* - for given AEAD algorithm instantiates encrypt and decrypt Ciphers
|
||||
* - instantiates CipherInputStream with the encrypt Cipher
|
||||
* - instantiates CipherOutputStream with the decrypt Cipher
|
||||
* - performs reading from the CipherInputStream (encryption data)
|
||||
* and writing to the CipherOutputStream (decryption). As a result,
|
||||
* output of the CipherOutputStream should be equal
|
||||
* with original plain text
|
||||
* - check if the original plain text is equal to output
|
||||
* of the CipherOutputStream
|
||||
* - if it is equal the test passes, otherwise it fails
|
||||
*/
|
||||
static class ReadWriteTest extends ReadWriteSkip {
|
||||
|
||||
public ReadWriteTest(int keyLength, int textLength, int AADLength)
|
||||
throws Exception {
|
||||
super(keyLength, textLength, AADLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runTest(BufferType bufType) throws IOException,
|
||||
GeneralSecurityException {
|
||||
|
||||
ByteArrayOutputStream baOutput = new ByteArrayOutputStream();
|
||||
try (CipherOutputStream ciOutput = new CipherOutputStream(baOutput,
|
||||
decryptCipher)) {
|
||||
if (bufType == BufferType.BYTE_ARRAY_BUFFERING) {
|
||||
doByteTest(ciOutput);
|
||||
} else {
|
||||
doIntTest(ciOutput);
|
||||
}
|
||||
}
|
||||
|
||||
check(plaintext, baOutput.toByteArray());
|
||||
}
|
||||
|
||||
/*
|
||||
* Implements byte array buffering type test case
|
||||
*/
|
||||
public void doByteTest(CipherOutputStream out) throws IOException {
|
||||
byte[] buffer = Helper.generateBytes(textLength + 1);
|
||||
int len = ciInput.read(buffer);
|
||||
while (len != -1) {
|
||||
out.write(buffer, 0, len);
|
||||
len = ciInput.read(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Implements integer buffering type test case
|
||||
*/
|
||||
public void doIntTest(CipherOutputStream out) throws IOException {
|
||||
int buffer = ciInput.read();
|
||||
while (buffer != -1) {
|
||||
out.write(buffer);
|
||||
buffer = ciInput.read();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* CICO AEAD SKIP functional test.
|
||||
*
|
||||
* Checks if the encrypt/decrypt operations work correctly
|
||||
* when skip() method is used.
|
||||
*
|
||||
* Test scenario:
|
||||
* - initializes a plain text
|
||||
* - initializes ciphers
|
||||
* - initializes cipher streams
|
||||
* - split plain text to TEXT_SIZE/BLOCK blocks
|
||||
* - read from CipherInputStream2 one block at time
|
||||
* - the last DISCARD = BLOCK - SAVE bytes are skipping for each block
|
||||
* - therefore, plain text data go through CipherInputStream1 (encrypting)
|
||||
* and CipherInputStream2 (decrypting)
|
||||
* - as a result, output should equal to the original text
|
||||
* except DISCART byte for each block
|
||||
* - check result buffers
|
||||
*/
|
||||
static class SkipTest extends ReadWriteSkip {
|
||||
|
||||
private final int numberOfBlocks;
|
||||
private final byte[] outputText;
|
||||
|
||||
public SkipTest(int keyLength, int textLength, int AADLength)
|
||||
throws Exception {
|
||||
super(keyLength, textLength, AADLength);
|
||||
numberOfBlocks = this.textLength / BLOCK;
|
||||
outputText = new byte[numberOfBlocks * SAVE];
|
||||
}
|
||||
|
||||
private void doByteTest(int blockNum, CipherInputStream cis)
|
||||
throws IOException {
|
||||
int index = blockNum * SAVE;
|
||||
int len = cis.read(outputText, index, SAVE);
|
||||
index += len;
|
||||
int read = 0;
|
||||
while (len != SAVE && read != -1) {
|
||||
read = cis.read(outputText, index, SAVE - len);
|
||||
len += read;
|
||||
index += read;
|
||||
}
|
||||
}
|
||||
|
||||
private void doIntTest(int blockNum, CipherInputStream cis)
|
||||
throws IOException {
|
||||
int i = blockNum * SAVE;
|
||||
for (int j = 0; j < SAVE && i < outputText.length; j++, i++) {
|
||||
int b = cis.read();
|
||||
if (b != -1) {
|
||||
outputText[i] = (byte) b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runTest(BufferType type) throws IOException,
|
||||
NoSuchAlgorithmException {
|
||||
try (CipherInputStream cis = new CipherInputStream(ciInput,
|
||||
decryptCipher)) {
|
||||
for (int i = 0; i < numberOfBlocks; i++) {
|
||||
if (type == BufferType.BYTE_ARRAY_BUFFERING) {
|
||||
doByteTest(i, cis);
|
||||
} else {
|
||||
doIntTest(i, cis);
|
||||
}
|
||||
if (cis.available() >= DISCARD) {
|
||||
cis.skip(DISCARD);
|
||||
} else {
|
||||
for (int k = 0; k < DISCARD; k++) {
|
||||
cis.read();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte[] expectedText = new byte[numberOfBlocks * SAVE];
|
||||
for (int m = 0; m < numberOfBlocks; m++) {
|
||||
for (int n = 0; n < SAVE; n++) {
|
||||
expectedText[m * SAVE + n] = plaintext[m * BLOCK + n];
|
||||
}
|
||||
}
|
||||
check(expectedText, outputText);
|
||||
}
|
||||
}
|
||||
}
|
||||
423
jdk/test/com/sun/crypto/provider/Cipher/AEAD/SameBuffer.java
Normal file
423
jdk/test/com/sun/crypto/provider/Cipher/AEAD/SameBuffer.java
Normal file
@ -0,0 +1,423 @@
|
||||
/*
|
||||
* 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.nio.ByteBuffer;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8048596
|
||||
* @summary Check if AEAD operations work correctly when buffers used
|
||||
* for storing plain text and cipher text are overlapped or the same
|
||||
*/
|
||||
public class SameBuffer {
|
||||
|
||||
private static final String PROVIDER = "SunJCE";
|
||||
private static final String AES = "AES";
|
||||
private static final String GCM = "GCM";
|
||||
private static final String PADDING = "NoPadding";
|
||||
private static final int OFFSET = 2;
|
||||
private static final int OFFSETS = 4;
|
||||
private static final int KEY_LENGTHS[] = { 128, 192, 256 };
|
||||
private static final int TEXT_LENGTHS[] = { 0, 1024 };
|
||||
private static final int AAD_LENGTHS[] = { 0, 1024 };
|
||||
|
||||
private final Provider provider;
|
||||
private final SecretKey key;
|
||||
private final String transformation;
|
||||
private final int textLength;
|
||||
private final int AADLength;
|
||||
|
||||
/**
|
||||
* Constructor of the test
|
||||
*
|
||||
* @param provider security provider
|
||||
* @param keyStrength key length
|
||||
* @param textLength length of data
|
||||
* @param AADLength AAD length
|
||||
*/
|
||||
public SameBuffer(Provider provider, String algorithm, String mode,
|
||||
String padding, int keyStrength, int textLength, int AADLength)
|
||||
throws Exception {
|
||||
|
||||
// init a secret key
|
||||
KeyGenerator kg = KeyGenerator.getInstance(algorithm, provider);
|
||||
kg.init(keyStrength);
|
||||
key = kg.generateKey();
|
||||
|
||||
this.transformation = algorithm + "/" + mode + "/" + padding;
|
||||
this.provider = provider;
|
||||
this.textLength = textLength;
|
||||
this.AADLength = AADLength;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Provider p = Security.getProvider(PROVIDER);
|
||||
for (int keyLength : KEY_LENGTHS) {
|
||||
for (int textLength : TEXT_LENGTHS) {
|
||||
for (int AADLength : AAD_LENGTHS) {
|
||||
for (int i = 0; i < OFFSETS; i++) {
|
||||
// try different offsets
|
||||
int offset = i * OFFSET;
|
||||
runTest(p, AES, GCM, PADDING, keyLength, textLength,
|
||||
AADLength, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Run single test case with given parameters
|
||||
*/
|
||||
static void runTest(Provider p, String algo, String mode,
|
||||
String padding, int keyLength, int textLength, int AADLength,
|
||||
int offset) throws Exception {
|
||||
System.out.println("Testing " + keyLength + " key length; "
|
||||
+ textLength + " text lenght; " + AADLength + " AAD length; "
|
||||
+ offset + " offset");
|
||||
if (keyLength > Cipher.getMaxAllowedKeyLength(algo)) {
|
||||
// skip this if this key length is larger than what's
|
||||
// configured in the jce jurisdiction policy files
|
||||
return;
|
||||
}
|
||||
SameBuffer test = new SameBuffer(p, algo, mode,
|
||||
padding, keyLength, textLength, AADLength);
|
||||
|
||||
/*
|
||||
* There are four test cases:
|
||||
* 1. AAD and text are placed in separated byte arrays
|
||||
* 2. AAD and text are placed in the same byte array
|
||||
* 3. AAD and text are placed in separated byte buffers
|
||||
* 4. AAD and text are placed in the same byte buffer
|
||||
*/
|
||||
Cipher ci = test.createCipher(Cipher.ENCRYPT_MODE, null);
|
||||
AlgorithmParameters params = ci.getParameters();
|
||||
test.doTestWithSeparateArrays(offset, params);
|
||||
test.doTestWithSameArrays(offset, params);
|
||||
test.doTestWithSeparatedBuffer(offset, params);
|
||||
test.doTestWithSameBuffer(offset, params);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the test in case when AAD and text are placed in separated byte
|
||||
* arrays.
|
||||
*/
|
||||
private void doTestWithSeparateArrays(int offset,
|
||||
AlgorithmParameters params) throws Exception {
|
||||
// prepare buffers to test
|
||||
Cipher c = createCipher(Cipher.ENCRYPT_MODE, params);
|
||||
int outputLength = c.getOutputSize(textLength);
|
||||
int outputBufSize = outputLength + offset * 2;
|
||||
|
||||
byte[] inputText = Helper.generateBytes(outputBufSize);
|
||||
byte[] AAD = Helper.generateBytes(AADLength);
|
||||
|
||||
// do the test
|
||||
runGCMWithSeparateArray(Cipher.ENCRYPT_MODE, AAD, inputText, offset * 2,
|
||||
textLength, offset, params);
|
||||
int tagLength = c.getParameters()
|
||||
.getParameterSpec(GCMParameterSpec.class).getTLen() / 8;
|
||||
runGCMWithSeparateArray(Cipher.DECRYPT_MODE, AAD, inputText, offset,
|
||||
textLength + tagLength, offset, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the test in case when AAD and text are placed in the same byte
|
||||
* array.
|
||||
*/
|
||||
private void doTestWithSameArrays(int offset, AlgorithmParameters params)
|
||||
throws Exception {
|
||||
// prepare buffers to test
|
||||
Cipher c = createCipher(Cipher.ENCRYPT_MODE, params);
|
||||
int outputLength = c.getOutputSize(textLength);
|
||||
int outputBufSize = AADLength + outputLength + offset * 2;
|
||||
|
||||
byte[] AAD_and_text = Helper.generateBytes(outputBufSize);
|
||||
|
||||
// do the test
|
||||
runGCMWithSameArray(Cipher.ENCRYPT_MODE, AAD_and_text, AADLength + offset,
|
||||
textLength, params);
|
||||
int tagLength = c.getParameters()
|
||||
.getParameterSpec(GCMParameterSpec.class).getTLen() / 8;
|
||||
runGCMWithSameArray(Cipher.DECRYPT_MODE, AAD_and_text, AADLength + offset,
|
||||
textLength + tagLength, params);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the test in case when AAD and text are placed in separated ByteBuffer
|
||||
*/
|
||||
private void doTestWithSeparatedBuffer(int offset,
|
||||
AlgorithmParameters params) throws Exception {
|
||||
// prepare AAD byte buffers to test
|
||||
byte[] AAD = Helper.generateBytes(AADLength);
|
||||
ByteBuffer AAD_Buf = ByteBuffer.allocate(AADLength);
|
||||
AAD_Buf.put(AAD, 0, AAD.length);
|
||||
AAD_Buf.flip();
|
||||
|
||||
// prepare text byte buffer to encrypt/decrypt
|
||||
Cipher c = createCipher(Cipher.ENCRYPT_MODE, params);
|
||||
int outputLength = c.getOutputSize(textLength);
|
||||
int outputBufSize = outputLength + offset;
|
||||
byte[] inputText = Helper.generateBytes(outputBufSize);
|
||||
ByteBuffer plainTextBB = ByteBuffer.allocateDirect(inputText.length);
|
||||
plainTextBB.put(inputText);
|
||||
plainTextBB.position(offset);
|
||||
plainTextBB.limit(offset + textLength);
|
||||
|
||||
// do test
|
||||
runGCMWithSeparateBuffers(Cipher.ENCRYPT_MODE, AAD_Buf, plainTextBB, offset,
|
||||
textLength, params);
|
||||
int tagLength = c.getParameters()
|
||||
.getParameterSpec(GCMParameterSpec.class).getTLen() / 8;
|
||||
plainTextBB.position(offset);
|
||||
plainTextBB.limit(offset + textLength + tagLength);
|
||||
runGCMWithSeparateBuffers(Cipher.DECRYPT_MODE, AAD_Buf, plainTextBB, offset,
|
||||
textLength + tagLength, params);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the test in case when AAD and text are placed in the same ByteBuffer
|
||||
*/
|
||||
private void doTestWithSameBuffer(int offset, AlgorithmParameters params)
|
||||
throws Exception {
|
||||
// calculate output length
|
||||
Cipher c = createCipher(Cipher.ENCRYPT_MODE, params);
|
||||
int outputLength = c.getOutputSize(textLength);
|
||||
|
||||
// prepare byte buffer contained AAD and plain text
|
||||
int bufSize = AADLength + offset + outputLength;
|
||||
byte[] AAD_and_Text = Helper.generateBytes(bufSize);
|
||||
ByteBuffer AAD_and_Text_Buf = ByteBuffer.allocate(bufSize);
|
||||
AAD_and_Text_Buf.put(AAD_and_Text, 0, AAD_and_Text.length);
|
||||
|
||||
// do test
|
||||
runGCMWithSameBuffer(Cipher.ENCRYPT_MODE, AAD_and_Text_Buf, offset,
|
||||
textLength, params);
|
||||
int tagLength = c.getParameters()
|
||||
.getParameterSpec(GCMParameterSpec.class).getTLen() / 8;
|
||||
AAD_and_Text_Buf.limit(AADLength + offset + textLength + tagLength);
|
||||
runGCMWithSameBuffer(Cipher.DECRYPT_MODE, AAD_and_Text_Buf, offset,
|
||||
textLength + tagLength, params);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute GCM encryption/decryption of a text placed in a byte array.
|
||||
* AAD is placed in the separated byte array.
|
||||
* Data are processed twice:
|
||||
* - in a separately allocated buffer
|
||||
* - in the text buffer
|
||||
* Check if two results are equal
|
||||
*/
|
||||
private void runGCMWithSeparateArray(int mode, byte[] AAD, byte[] text,
|
||||
int txtOffset, int lenght, int offset, AlgorithmParameters params)
|
||||
throws Exception {
|
||||
// first, generate the cipher text at an allocated buffer
|
||||
Cipher cipher = createCipher(mode, params);
|
||||
cipher.updateAAD(AAD);
|
||||
byte[] outputText = cipher.doFinal(text, txtOffset, lenght);
|
||||
|
||||
// new cipher for encrypt operation
|
||||
Cipher anotherCipher = createCipher(mode, params);
|
||||
anotherCipher.updateAAD(AAD);
|
||||
|
||||
// next, generate cipher text again at the same buffer of plain text
|
||||
int myoff = offset;
|
||||
int off = anotherCipher.update(text, txtOffset, lenght, text, myoff);
|
||||
anotherCipher.doFinal(text, myoff + off);
|
||||
|
||||
// check if two resutls are equal
|
||||
if (!isEqual(text, myoff, outputText, 0, outputText.length)) {
|
||||
throw new RuntimeException("Two results not equal, mode:" + mode);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute GCM encrption/decryption of a text. The AAD and text to process
|
||||
* are placed in the same byte array. Data are processed twice:
|
||||
* - in a separetly allocated buffer
|
||||
* - in a buffer that shares content of the AAD_and_Text_BA
|
||||
* Check if two results are equal
|
||||
*/
|
||||
private void runGCMWithSameArray(int mode, byte[] array, int txtOffset,
|
||||
int length, AlgorithmParameters params) throws Exception {
|
||||
// first, generate cipher text at an allocated buffer
|
||||
Cipher cipher = createCipher(mode, params);
|
||||
cipher.updateAAD(array, 0, AADLength);
|
||||
byte[] outputText = cipher.doFinal(array, txtOffset, length);
|
||||
|
||||
// new cipher for encrypt operation
|
||||
Cipher anotherCipher = createCipher(mode, params);
|
||||
anotherCipher.updateAAD(array, 0, AADLength);
|
||||
|
||||
// next, generate cipher text again at the same buffer of plain text
|
||||
int off = anotherCipher.update(array, txtOffset, length,
|
||||
array, txtOffset);
|
||||
anotherCipher.doFinal(array, txtOffset + off);
|
||||
|
||||
// check if two results are equal or not
|
||||
if (!isEqual(array, txtOffset, outputText, 0,
|
||||
outputText.length)) {
|
||||
throw new RuntimeException(
|
||||
"Two results are not equal, mode:" + mode);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute GCM encryption/decryption of textBB. AAD and text to process are
|
||||
* placed in different byte buffers. Data are processed twice:
|
||||
* - in a separately allocated buffer
|
||||
* - in a buffer that shares content of the textBB
|
||||
* Check if results are equal
|
||||
*/
|
||||
private void runGCMWithSeparateBuffers(int mode, ByteBuffer buffer,
|
||||
ByteBuffer textBB, int txtOffset, int dataLength,
|
||||
AlgorithmParameters params) throws Exception {
|
||||
// take offset into account
|
||||
textBB.position(txtOffset);
|
||||
textBB.mark();
|
||||
|
||||
// first, generate the cipher text at an allocated buffer
|
||||
Cipher cipher = createCipher(mode, params);
|
||||
cipher.updateAAD(buffer);
|
||||
buffer.flip();
|
||||
ByteBuffer outBB = ByteBuffer.allocateDirect(
|
||||
cipher.getOutputSize(dataLength));
|
||||
|
||||
cipher.doFinal(textBB, outBB);// get cipher text in outBB
|
||||
outBB.flip();
|
||||
|
||||
// restore positions
|
||||
textBB.reset();
|
||||
|
||||
// next, generate cipher text again in a buffer that shares content
|
||||
Cipher anotherCipher = createCipher(mode, params);
|
||||
anotherCipher.updateAAD(buffer);
|
||||
buffer.flip();
|
||||
ByteBuffer buf2 = textBB.duplicate(); // buf2 shares textBuf context
|
||||
buf2.limit(txtOffset + anotherCipher.getOutputSize(dataLength));
|
||||
int dataProcessed2 = anotherCipher.doFinal(textBB, buf2);
|
||||
buf2.position(txtOffset);
|
||||
buf2.limit(txtOffset + dataProcessed2);
|
||||
|
||||
if (!buf2.equals(outBB)) {
|
||||
throw new RuntimeException(
|
||||
"Two results are not equal, mode:" + mode);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute GCM encryption/decryption of text. AAD and a text to process are
|
||||
* placed in the same buffer. Data is processed twice:
|
||||
* - in a separately allocated buffer
|
||||
* - in a buffer that shares content of the AAD_and_Text_BB
|
||||
*/
|
||||
private void runGCMWithSameBuffer(int mode, ByteBuffer buffer,
|
||||
int txtOffset, int length, AlgorithmParameters params)
|
||||
throws Exception {
|
||||
|
||||
// allocate a separate buffer
|
||||
Cipher cipher = createCipher(mode, params);
|
||||
ByteBuffer outBB = ByteBuffer.allocateDirect(
|
||||
cipher.getOutputSize(length));
|
||||
|
||||
// first, generate the cipher text at an allocated buffer
|
||||
buffer.flip();
|
||||
buffer.limit(AADLength);
|
||||
cipher.updateAAD(buffer);
|
||||
buffer.limit(AADLength + txtOffset + length);
|
||||
buffer.position(AADLength + txtOffset);
|
||||
cipher.doFinal(buffer, outBB);
|
||||
outBB.flip(); // cipher text in outBB
|
||||
|
||||
// next, generate cipherText again in the same buffer
|
||||
Cipher anotherCipher = createCipher(mode, params);
|
||||
buffer.flip();
|
||||
buffer.limit(AADLength);
|
||||
anotherCipher.updateAAD(buffer);
|
||||
buffer.limit(AADLength + txtOffset + length);
|
||||
buffer.position(AADLength + txtOffset);
|
||||
|
||||
// share textBuf context
|
||||
ByteBuffer buf2 = buffer.duplicate();
|
||||
buf2.limit(AADLength + txtOffset + anotherCipher.getOutputSize(length));
|
||||
int dataProcessed2 = anotherCipher.doFinal(buffer, buf2);
|
||||
buf2.position(AADLength + txtOffset);
|
||||
buf2.limit(AADLength + txtOffset + dataProcessed2);
|
||||
|
||||
if (!buf2.equals(outBB)) {
|
||||
throw new RuntimeException(
|
||||
"Two results are not equal, mode:" + mode);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEqual(byte[] A, int offsetA, byte[] B, int offsetB,
|
||||
int bytesToCompare) {
|
||||
System.out.println("offsetA: " + offsetA + " offsetB: " + offsetA
|
||||
+ " bytesToCompare: " + bytesToCompare);
|
||||
for (int i = 0; i < bytesToCompare; i++) {
|
||||
int setA = i + offsetA;
|
||||
int setB = i + offsetB;
|
||||
if (setA > A.length - 1 || setB > B.length - 1
|
||||
|| A[setA] != B[setB]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a Cipher object for testing: for encryption it creates new Cipher
|
||||
* based on previously saved parameters (it is prohibited to use the same
|
||||
* Cipher twice for encription during GCM mode), or returns initiated
|
||||
* existing Cipher.
|
||||
*/
|
||||
private Cipher createCipher(int mode, AlgorithmParameters params)
|
||||
throws Exception {
|
||||
Cipher cipher = Cipher.getInstance(transformation, provider);
|
||||
if (Cipher.ENCRYPT_MODE == mode) {
|
||||
// initiate it with the saved parameters
|
||||
if (params != null) {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key, params);
|
||||
} else {
|
||||
// intiate the cipher and save parameters
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
}
|
||||
} else if (cipher != null) {
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, params);
|
||||
} else {
|
||||
throw new RuntimeException("Can't create cipher");
|
||||
}
|
||||
|
||||
return cipher;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.security.AlgorithmParameters;
|
||||
import java.util.Arrays;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SealedObject;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8048596
|
||||
* @summary Check if the seal/unseal feature works properly in AEAD/GCM mode.
|
||||
*/
|
||||
public class SealedObjectTest {
|
||||
|
||||
private static final String AES = "AES";
|
||||
private static final String TRANSFORMATION = "AES/GCM/NoPadding";
|
||||
private static final String PROVIDER = "SunJCE";
|
||||
private static final int KEY_LENGTH = 128;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the test:
|
||||
* - init a cipher with AES/GCM/NoPadding transformation
|
||||
* - seal an object
|
||||
* - check if we can't seal it again with the same key/IV
|
||||
* - unseal the object using different methods of SealedObject class
|
||||
* - check if the original and sealed objects are equal
|
||||
*/
|
||||
static void doTest() throws Exception {
|
||||
// init a secret Key
|
||||
KeyGenerator kg = KeyGenerator.getInstance(AES, PROVIDER);
|
||||
kg.init(KEY_LENGTH);
|
||||
SecretKey key = kg.generateKey();
|
||||
|
||||
// initialization
|
||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION, PROVIDER);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
AlgorithmParameters params = cipher.getParameters();
|
||||
|
||||
// seal an object
|
||||
SealedObject so = new SealedObject(key, cipher);
|
||||
try {
|
||||
// check if we can't seal it again with the same key/IV
|
||||
so = new SealedObject(key, cipher);
|
||||
throw new RuntimeException(
|
||||
"FAILED: expected IllegalStateException hasn't "
|
||||
+ "been thrown");
|
||||
} catch (IllegalStateException ise) {
|
||||
System.out.println("Expected exception when seal it again with"
|
||||
+ " the same key/IV: " + ise);
|
||||
}
|
||||
|
||||
// unseal the object using getObject(Cipher) and compare
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, params);
|
||||
SecretKey unsealedKey = (SecretKey) so.getObject(cipher);
|
||||
assertKeysSame(unsealedKey, key, "SealedObject.getObject(Cipher)");
|
||||
|
||||
// unseal the object using getObject(Key) and compare
|
||||
unsealedKey = (SecretKey) so.getObject(key);
|
||||
assertKeysSame(unsealedKey, key, "SealedObject.getObject(Key)");
|
||||
|
||||
// unseal the object using getObject(Key, String) and compare
|
||||
unsealedKey = (SecretKey) so.getObject(key, PROVIDER);
|
||||
|
||||
assertKeysSame(unsealedKey, key,
|
||||
"SealedObject.getObject(Key, String)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two SecretKey objects.
|
||||
*
|
||||
* @param key1 first key
|
||||
* @param key2 second key
|
||||
* @param meth method that was used for unsealing the SecretKey object
|
||||
* @return true if key1 and key2 are the same, false otherwise.
|
||||
*/
|
||||
static void assertKeysSame(SecretKey key1, SecretKey key2, String meth) {
|
||||
if (!Arrays.equals(key1.getEncoded(), key2.getEncoded())) {
|
||||
throw new RuntimeException(
|
||||
"FAILED: original and unsealed objects aren't the same for "
|
||||
+ meth);
|
||||
}
|
||||
}
|
||||
}
|
||||
174
jdk/test/com/sun/crypto/provider/Cipher/AEAD/WrongAAD.java
Normal file
174
jdk/test/com/sun/crypto/provider/Cipher/AEAD/WrongAAD.java
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user