/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intel.diceros.test.aes; import com.intel.diceros.provider.util.Arrays; import com.intel.diceros.test.BaseBlockCipherTest; import com.intel.diceros.test.util.Hex; import javax.crypto.*; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; /** * This class does the correctness test of AES CTR mode algorithm */ public abstract class AESAbstarctTest extends BaseBlockCipherTest { protected String cipherName; protected String providerName; protected String[] cipherTests; // data public static final int BYTEBUFFER_SIZE = 1000; public AESAbstarctTest(String cipherName, String providerName, String[] cipherTests) { super("AES"); this.cipherName = cipherName; this.providerName = providerName; this.cipherTests = cipherTests; } public AESAbstarctTest() { super("AES"); } /** * AES Test with byte array as input data, first encrypt the * <code>input</code>, compare the cipherText with the <code>output</code> to * verify the encryption then decrypt the cipherText, compare the plainText * with the <code>input</code> to verify the decryption * * @param strength * the key length * @param keyBytes * the key * @param ivBytes * the intialize vector * @param input * the plainText data * @param output * the cipherText data * @throws Exception */ protected void byteArrayTest(int strength, byte[] keyBytes, byte[] ivBytes, byte[] input, byte[] output) throws Exception { Key key; IvParameterSpec iv; Cipher in, out; CipherInputStream cIn; CipherOutputStream cOut; ByteArrayInputStream bIn; ByteArrayOutputStream bOut; key = new SecretKeySpec(keyBytes, "AES"); iv = new IvParameterSpec(ivBytes); in = Cipher.getInstance(this.cipherName, this.providerName); out = Cipher.getInstance(this.cipherName, this.providerName); try { out.init(Cipher.ENCRYPT_MODE, key, iv); } catch (Exception e) { fail("AES failed initialisation - " + e.toString(), e); } try { in.init(Cipher.DECRYPT_MODE, key, iv); } catch (Exception e) { fail("AES failed initialisation - " + e.toString(), e); } // // encryption pass // bOut = new ByteArrayOutputStream(); cOut = new CipherOutputStream(bOut, out); try { for (int i = 0; i != input.length / 2; i++) { cOut.write(input[i]); } cOut.write(input, input.length / 2, input.length - input.length / 2); cOut.close(); } catch (IOException e) { fail("AES failed encryption - " + e.toString(), e); } byte[] bytes; bytes = bOut.toByteArray(); if (!Arrays.areEqual(bytes, output)) { fail("AES failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); } // // decryption pass // bIn = new ByteArrayInputStream(output); cIn = new CipherInputStream(bIn, in); byte[] decByte = null;//= in.doFinal(bytes); try { DataInputStream dIn = new DataInputStream(cIn); decByte = new byte[input.length]; for (int i = 0; i != input.length / 2; i++) { decByte[i] = (byte) dIn.read(); } dIn.readFully(decByte, input.length / 2, decByte.length - input.length / 2); } catch (Exception e) { fail("AES failed encryption - " + e.toString(), e); } if (!Arrays.areEqual(decByte, input)) { fail("AES failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(decByte))); } } /** * AES Test with byteBuffer as input data, first encrypt the * <code>input</code>, compare the cipherText with the <code>output</code> to * verify the encryption then decrypt the cipherText, compare the plainText * with the <code>input</code> to verify the decryption * * @param strength * the key length * @param keyBytes * the key * @param ivBytes * the intialize vector * @param input * the plainText data * @param output * the cipherText data * @throws NoSuchAlgorithmException * @throws NoSuchProviderException * @throws NoSuchPaddingException * @throws ShortBufferException * @throws Exception * @throws BadPaddingException */ protected void byteBufferTest(int strength, byte[] keyBytes, byte[] ivBytes, ByteBuffer input, ByteBuffer output) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, ShortBufferException, BadPaddingException, IllegalBlockSizeException { ByteBuffer decResult = ByteBuffer.allocateDirect(BYTEBUFFER_SIZE); ByteBuffer encResult = ByteBuffer.allocateDirect(BYTEBUFFER_SIZE); Key key; Cipher enc, dec; IvParameterSpec iv; key = new SecretKeySpec(keyBytes, "AES"); iv = new IvParameterSpec(ivBytes); enc = Cipher.getInstance(this.cipherName, this.providerName); dec = Cipher.getInstance(this.cipherName, this.providerName); try { enc.init(Cipher.ENCRYPT_MODE, key, iv); } catch (Exception e) { fail("AES failed initialisation - " + e.toString(), e); } try { dec.init(Cipher.DECRYPT_MODE, key, iv); } catch (Exception e) { fail("AES failed initialisation - " + e.toString(), e); } // // encryption pass // enc.doFinal(input, encResult); input.flip(); encResult.flip(); if (!output.equals(encResult)) { fail("AES failed encryption - expected " + new String(Hex.encode(output.array())) + " got " + new String(Hex.encode(encResult.array()))); } // // decryption pass // dec.doFinal(encResult, decResult); decResult.flip(); if (!input.equals(decResult)) { byte[] inArray = new byte[input.remaining()]; byte[] decResultArray = new byte[decResult.remaining()]; input.get(inArray); decResult.get(decResultArray); fail("AES failed decryption - expected " + new String(Hex.encode(inArray)) + " got " + new String(Hex.encode(decResultArray))); } } /** * AES Test with both byte arry and direct byte buffer as input data, first * encrypt the <code>inputByteArray</code> and <code>inputByteBuffer</code>, * then decrypt the ciphertext result and compare it with the * <code>inputByteArray</code> and <code>inputByteBuffer</code>. * * @param strength * the key length * @param keyBytes * the key data * @param inputByteArray * the input byte array * @param inputByteBuffer * the input direct byte buffer * @throws NoSuchAlgorithmException * @throws NoSuchProviderException * @throws NoSuchPaddingException * @throws ShortBufferException * @throws Exception * @throws BadPaddingException */ protected void mixTest(int strength,byte[] keyBytes, byte[] ivBytes, byte[] inputByteArray, ByteBuffer inputByteBuffer) throws NoSuchAlgorithmException,NoSuchProviderException, NoSuchPaddingException, ShortBufferException, Exception, BadPaddingException { ByteBuffer output = ByteBuffer.allocateDirect(BYTEBUFFER_SIZE); ByteBuffer decResult = ByteBuffer.allocateDirect(BYTEBUFFER_SIZE); Key key; IvParameterSpec iv; Cipher enc, dec; key = new SecretKeySpec(keyBytes, "AES"); iv = new IvParameterSpec(ivBytes); enc = Cipher.getInstance(this.cipherName, this.providerName); dec = Cipher.getInstance(this.cipherName, this.providerName); try { enc.init(Cipher.ENCRYPT_MODE, key, iv); } catch (Exception e) { fail("AES failed initialisation - " + e.toString(), e); } try { dec.init(Cipher.DECRYPT_MODE, key, iv); } catch (Exception e) { fail("AES failed initialisation - " + e.toString(), e); } // // encryption pass // byte[] bytes = null; bytes = enc.update(inputByteArray); if (bytes != null) { output.put(bytes); } enc.update(inputByteBuffer, output); output.put(enc.doFinal()); output.flip(); // // decryption pass // dec.doFinal(output, decResult); inputByteBuffer.flip(); decResult.flip(); ByteBuffer totalInput = ByteBuffer.allocateDirect(BYTEBUFFER_SIZE); totalInput.put(inputByteArray); totalInput.put(inputByteBuffer); totalInput.flip(); // inputByteBuffer.flip(); if (!totalInput.equals(decResult)) { byte[] inArray = new byte[totalInput.remaining()]; byte[] decResultArray = new byte[decResult.remaining()]; totalInput.get(inArray); decResult.get(decResultArray); fail("AES failed decryption - expected " + new String(Hex.encode(inArray)) + " got " + new String(Hex.encode(decResultArray))); } } /** * Perform the aes correctness test. */ public void performTest() throws Exception { for (int i = 0; i != cipherTests.length; i += 5) { byteArrayTest(Integer.parseInt(cipherTests[i]), Hex.decode(cipherTests[i + 1]), Hex.decode(cipherTests[i + 2]), Hex.decode(cipherTests[i + 3]), Hex.decode(cipherTests[i + 4])); } for (int i = 0; i != cipherTests.length; i += 5) { byte[] inputBytes = Hex.decode(cipherTests[i + 3]); byte[] outputBytes = Hex.decode(cipherTests[i + 4]); ByteBuffer inputBuffer = ByteBuffer.allocateDirect(inputBytes.length); ByteBuffer outputBuffer = ByteBuffer.allocateDirect(outputBytes.length); inputBuffer.put(inputBytes); inputBuffer.flip(); outputBuffer.put(outputBytes); outputBuffer.flip(); byteBufferTest(Integer.parseInt(cipherTests[i]), Hex.decode(cipherTests[i + 1]), Hex.decode(cipherTests[i + 2]), inputBuffer, outputBuffer); } for (int i = 0; i != cipherTests.length; i += 5) { byte[] inputBytes = Hex.decode(cipherTests[i+3]); ByteBuffer inputBuffer = ByteBuffer.allocateDirect(inputBytes.length); inputBuffer.put(inputBytes); inputBuffer.flip(); mixTest(Integer.parseInt(cipherTests[i]), Hex.decode(cipherTests[i+1]), Hex.decode(cipherTests[i+2]), inputBytes, inputBuffer); } } }