/* Copyright 2014 Duncan Jones
*
* Licensed 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 org.cryptonode.jncryptor;
import static org.junit.Assert.*;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.Random;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.junit.Test;
public class AES256JNCryptorOutputStreamTest {
private static final Random RANDOM = new Random();
/**
* Test reading using password constructor.
*
* @throws Exception
*/
@Test
public void testUsingPassword() throws Exception {
byte[] plaintext = getRandomBytes(127);
final String password = "Testing1234";
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
AES256JNCryptorOutputStream cryptorStream = new AES256JNCryptorOutputStream(
byteStream, password.toCharArray());
cryptorStream.write(plaintext);
cryptorStream.close();
byte[] encrypted = byteStream.toByteArray();
JNCryptor cryptor = new AES256JNCryptor();
byte[] result = cryptor.decryptData(encrypted, password.toCharArray());
assertArrayEquals(plaintext, result);
}
/**
* Test writing using write(byte b) method
*
* @throws Exception
*/
@Test
public void testUsingPasswordAndSingleBytes() throws Exception {
byte[] plaintext = getRandomBytes(127);
final String password = "Testing1234";
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
AES256JNCryptorOutputStream cryptorStream = new AES256JNCryptorOutputStream(
byteStream, password.toCharArray());
for (byte b : plaintext) {
cryptorStream.write(b);
}
cryptorStream.close();
byte[] encrypted = byteStream.toByteArray();
JNCryptor cryptor = new AES256JNCryptor();
byte[] result = cryptor.decryptData(encrypted, password.toCharArray());
assertArrayEquals(plaintext, result);
}
/**
* Test reading using SecretKey constructor.
*
* @throws Exception
*/
@Test
public void testUsingKeys() throws Exception {
byte[] plaintext = getRandomBytes(256);
byte[] encryptionSalt = getRandomBytes(8);
byte[] hmacSalt = getRandomBytes(8);
final String password = "Testing1234";
JNCryptor cryptor = new AES256JNCryptor();
SecretKey hmacKey = cryptor
.keyForPassword(password.toCharArray(), hmacSalt);
SecretKey encryptionKey = cryptor.keyForPassword(password.toCharArray(),
encryptionSalt);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
AES256JNCryptorOutputStream cryptorStream = new AES256JNCryptorOutputStream(
byteStream, encryptionKey, hmacKey);
cryptorStream.write(plaintext);
cryptorStream.close();
byte[] encrypted = byteStream.toByteArray();
byte[] result = cryptor.decryptData(encrypted, encryptionKey, hmacKey);
assertArrayEquals(plaintext, result);
}
/**
* Test using the reference password test vectors.
*/
@Test
public void testReferencePasswordVectors() throws Exception {
List<PasswordTestVector> passwordVectors = TestVectorReader
.readPasswordVectors();
for (PasswordTestVector vector : passwordVectors) {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
char[] password = vector.getPassword().toCharArray();
AES256JNCryptorOutputStream cryptorStream = new AES256JNCryptorOutputStream(
byteStream, password);
cryptorStream.write(vector.getPlaintext());
cryptorStream.close();
byte[] encrypted = byteStream.toByteArray();
JNCryptor cryptor = new AES256JNCryptor();
byte[] result = cryptor.decryptData(encrypted, password);
assertArrayEquals(
"Stream encryption failed for password test " + vector.getTitle(),
vector.getPlaintext(), result);
}
}
/**
* Test using the reference key test vectors.
*/
@Test
public void testReferenceKeyVectors() throws Exception {
List<KeyTestVector> keyVectors = TestVectorReader.readKeyVectors();
for (KeyTestVector vector : keyVectors) {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
SecretKey key = new SecretKeySpec(vector.getEncryptionKey(), "AES");
SecretKey hmacKey = new SecretKeySpec(vector.getHmacKey(), "AES");
AES256JNCryptorOutputStream cryptorStream = new AES256JNCryptorOutputStream(
byteStream, key, hmacKey);
cryptorStream.write(vector.getExpectedPlaintext());
cryptorStream.close();
byte[] encrypted = byteStream.toByteArray();
JNCryptor cryptor = new AES256JNCryptor();
byte[] result = cryptor.decryptData(encrypted, key, hmacKey);
assertArrayEquals(
"Stream encryption failed for password test " + vector.getTitle(),
vector.getExpectedPlaintext(), result);
}
}
/**
* Test with a larger amount of encrypted data, and multiple write() calls.
*
* @throws Exception
*/
@Test
public void testMultipleWriteCalls() throws Exception {
byte[] plaintext = getRandomBytes(50000);
final String password = "Testing1234";
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
AES256JNCryptorOutputStream cryptorStream = new AES256JNCryptorOutputStream(
byteStream, password.toCharArray());
int offset = 0;
while (offset < plaintext.length) {
int n = Math.min(16383, plaintext.length - offset);
cryptorStream.write(plaintext, offset, n);
offset += n;
}
cryptorStream.close();
byte[] encrypted = byteStream.toByteArray();
JNCryptor cryptor = new AES256JNCryptor();
byte[] result = cryptor.decryptData(encrypted, password.toCharArray());
assertArrayEquals(plaintext, result);
}
/**
* Test passing in a null password
*
* @throws Exception
*/
@Test(expected = NullPointerException.class)
// TODO check for specific message
public void testNullPassword() throws Exception {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
AES256JNCryptorOutputStream cryptorStream = new AES256JNCryptorOutputStream(
byteStream, null);
cryptorStream.close();
}
/**
* Test passing in an invalid password
*
* @throws Exception
*/
@Test(expected = IllegalArgumentException.class)
// TODO check for specific message
public void testInvalidPassword() throws Exception {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
AES256JNCryptorOutputStream cryptorStream = new AES256JNCryptorOutputStream(
byteStream, new char[0]);
cryptorStream.close();
}
@Test
public void testBadIterations() throws Exception {
try {
new AES256JNCryptorOutputStream(new ByteArrayOutputStream(),
"foo".toCharArray(), -1);
fail();
} catch (IllegalArgumentException e) {
// expected
}
}
private static byte[] getRandomBytes(int length) {
byte[] result = new byte[length];
RANDOM.nextBytes(result);
return result;
}
}