Path: blob/master/test/jdk/com/sun/crypto/provider/Cipher/AEAD/ReadWriteSkip.java
41161 views
/*1* Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.ByteArrayInputStream;24import java.io.ByteArrayOutputStream;25import java.io.IOException;26import java.security.GeneralSecurityException;27import java.security.NoSuchAlgorithmException;28import java.util.Arrays;29import javax.crypto.Cipher;30import javax.crypto.CipherInputStream;31import javax.crypto.CipherOutputStream;32import javax.crypto.KeyGenerator;33import javax.crypto.SecretKey;3435/*36* @test37* @bug 804859638* @summary Test CICO AEAD read/write/skip operations39*/40public class ReadWriteSkip {4142static enum BufferType {43BYTE_ARRAY_BUFFERING, INT_BYTE_BUFFERING44}4546static final int KEY_LENGTHS[] = {128, 192, 256};47static final int TXT_LENGTHS[] = {800, 0};48static final int AAD_LENGTHS[] = {0, 100};49static final int BLOCK = 50;50static final int SAVE = 45;51static final int DISCARD = BLOCK - SAVE;52static final String PROVIDER = "SunJCE";53static final String AES = "AES";54static final String GCM = "GCM";55static final String PADDING = "NoPadding";56static final String TRANSFORM = AES + "/" + GCM + "/" + PADDING;5758final SecretKey key;59final byte[] plaintext;60final byte[] AAD;61final int textLength;;62final int keyLength;63Cipher encryptCipher;64Cipher decryptCipher;65CipherInputStream ciInput;6667public static void main(String[] args) throws Exception {68boolean success = true;69for (int keyLength : KEY_LENGTHS) {70if (keyLength > Cipher.getMaxAllowedKeyLength(TRANSFORM)) {71// skip this if this key length is larger than what's72// configured in the jce jurisdiction policy files73continue;74}75for (int textLength : TXT_LENGTHS) {76for (int AADLength : AAD_LENGTHS) {77System.out.println("Key length = " + keyLength78+ ", text length = " + textLength79+ ", AAD length = " + AADLength);80try {81run(keyLength, textLength, AADLength);82System.out.println("Test case passed");83} catch (Exception e) {84System.out.println("Test case failed: " + e);85success = false;86}87}88}89}9091if (!success) {92throw new RuntimeException("At least one test case failed");93}9495System.out.println("Test passed");96}9798ReadWriteSkip(int keyLength, int textLength, int AADLength)99throws Exception {100this.keyLength = keyLength;101this.textLength = textLength;102103// init AAD104this.AAD = Helper.generateBytes(AADLength);105106// init a secret Key107KeyGenerator kg = KeyGenerator.getInstance(AES, PROVIDER);108kg.init(this.keyLength);109this.key = kg.generateKey();110111this.plaintext = Helper.generateBytes(textLength);112}113114final void doTest(BufferType type) throws Exception {115// init ciphers116encryptCipher = createCipher(Cipher.ENCRYPT_MODE);117decryptCipher = createCipher(Cipher.DECRYPT_MODE);118119// init cipher input stream120ciInput = new CipherInputStream(new ByteArrayInputStream(plaintext),121encryptCipher);122123runTest(type);124}125126void runTest(BufferType type) throws Exception {}127128private Cipher createCipher(int mode) throws GeneralSecurityException {129Cipher cipher = Cipher.getInstance(TRANSFORM, PROVIDER);130if (mode == Cipher.ENCRYPT_MODE) {131cipher.init(Cipher.ENCRYPT_MODE, key);132} else {133if (encryptCipher != null) {134cipher.init(Cipher.DECRYPT_MODE, key,135encryptCipher.getParameters());136} else {137throw new RuntimeException("Can't create a cipher");138}139}140cipher.updateAAD(AAD);141return cipher;142}143144/*145* Run test cases146*/147static void run(int keyLength, int textLength, int AADLength)148throws Exception {149new ReadWriteTest(keyLength, textLength, AADLength)150.doTest(BufferType.BYTE_ARRAY_BUFFERING);151new ReadWriteTest(keyLength, textLength, AADLength)152.doTest(BufferType.INT_BYTE_BUFFERING);153new SkipTest(keyLength, textLength, AADLength)154.doTest(BufferType.BYTE_ARRAY_BUFFERING);155new SkipTest(keyLength, textLength, AADLength)156.doTest(BufferType.INT_BYTE_BUFFERING);157}158159static void check(byte[] first, byte[] second) {160if (!Arrays.equals(first, second)) {161throw new RuntimeException("Arrays are not equal");162}163}164165/*166* CICO AEAD read/write functional test.167*168* Check if encrypt/decrypt operations work correctly.169*170* Test scenario:171* - initializes plain text172* - for given AEAD algorithm instantiates encrypt and decrypt Ciphers173* - instantiates CipherInputStream with the encrypt Cipher174* - instantiates CipherOutputStream with the decrypt Cipher175* - performs reading from the CipherInputStream (encryption data)176* and writing to the CipherOutputStream (decryption). As a result,177* output of the CipherOutputStream should be equal178* with original plain text179* - check if the original plain text is equal to output180* of the CipherOutputStream181* - if it is equal the test passes, otherwise it fails182*/183static class ReadWriteTest extends ReadWriteSkip {184185public ReadWriteTest(int keyLength, int textLength, int AADLength)186throws Exception {187super(keyLength, textLength, AADLength);188}189190@Override191public void runTest(BufferType bufType) throws IOException,192GeneralSecurityException {193194ByteArrayOutputStream baOutput = new ByteArrayOutputStream();195try (CipherOutputStream ciOutput = new CipherOutputStream(baOutput,196decryptCipher)) {197if (bufType == BufferType.BYTE_ARRAY_BUFFERING) {198doByteTest(ciOutput);199} else {200doIntTest(ciOutput);201}202}203204check(plaintext, baOutput.toByteArray());205}206207/*208* Implements byte array buffering type test case209*/210public void doByteTest(CipherOutputStream out) throws IOException {211byte[] buffer = Helper.generateBytes(textLength + 1);212int len = ciInput.read(buffer);213while (len != -1) {214out.write(buffer, 0, len);215len = ciInput.read(buffer);216}217}218219/*220* Implements integer buffering type test case221*/222public void doIntTest(CipherOutputStream out) throws IOException {223int buffer = ciInput.read();224while (buffer != -1) {225out.write(buffer);226buffer = ciInput.read();227}228}229}230231/*232* CICO AEAD SKIP functional test.233*234* Checks if the encrypt/decrypt operations work correctly235* when skip() method is used.236*237* Test scenario:238* - initializes a plain text239* - initializes ciphers240* - initializes cipher streams241* - split plain text to TEXT_SIZE/BLOCK blocks242* - read from CipherInputStream2 one block at time243* - the last DISCARD = BLOCK - SAVE bytes are skipping for each block244* - therefore, plain text data go through CipherInputStream1 (encrypting)245* and CipherInputStream2 (decrypting)246* - as a result, output should equal to the original text247* except DISCART byte for each block248* - check result buffers249*/250static class SkipTest extends ReadWriteSkip {251252private final int numberOfBlocks;253private final byte[] outputText;254255public SkipTest(int keyLength, int textLength, int AADLength)256throws Exception {257super(keyLength, textLength, AADLength);258numberOfBlocks = this.textLength / BLOCK;259outputText = new byte[numberOfBlocks * SAVE];260}261262private void doByteTest(int blockNum, CipherInputStream cis)263throws IOException {264int index = blockNum * SAVE;265int len = cis.read(outputText, index, SAVE);266index += len;267int read = 0;268while (len != SAVE && read != -1) {269read = cis.read(outputText, index, SAVE - len);270len += read;271index += read;272}273}274275private void doIntTest(int blockNum, CipherInputStream cis)276throws IOException {277int i = blockNum * SAVE;278for (int j = 0; j < SAVE && i < outputText.length; j++, i++) {279int b = cis.read();280if (b != -1) {281outputText[i] = (byte) b;282}283}284}285286@Override287public void runTest(BufferType type) throws IOException,288NoSuchAlgorithmException {289try (CipherInputStream cis = new CipherInputStream(ciInput,290decryptCipher)) {291for (int i = 0; i < numberOfBlocks; i++) {292if (type == BufferType.BYTE_ARRAY_BUFFERING) {293doByteTest(i, cis);294} else {295doIntTest(i, cis);296}297if (cis.available() >= DISCARD) {298cis.skip(DISCARD);299} else {300for (int k = 0; k < DISCARD; k++) {301cis.read();302}303}304}305}306307byte[] expectedText = new byte[numberOfBlocks * SAVE];308for (int m = 0; m < numberOfBlocks; m++) {309for (int n = 0; n < SAVE; n++) {310expectedText[m * SAVE + n] = plaintext[m * BLOCK + n];311}312}313check(expectedText, outputText);314}315}316}317318319