package no.ntnu.item.csv.cryptoutil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.DigestInputStream;
import java.security.DigestOutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import no.ntnu.item.cryptoutil.CryptoStreamer;
import no.ntnu.item.cryptoutil.Cryptoutil;
import no.ntnu.item.csv.fileutils.FileUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class CryptoStreamerTest {
private CryptoStreamer cryptoStreamer;
private final String testfile = "src/test/resources/smallloremipsum.txt";
private final String encryptedOutputFile = "/tmp/testenc.txt";
private final String decryptedOutputFile = "/tmp/testdec.txt";
private byte[] tmpDigest;
@Before
public void setUp() {
this.cryptoStreamer = new CryptoStreamer();
}
@After
public void tearDown() {
File f = new File(encryptedOutputFile);
File f2 = new File(decryptedOutputFile);
if (f.exists()) {
f.delete();
}
if (f2.exists()) {
f2.delete();
}
}
@Test
public void testEncryptionAndDecryptionToMemory() throws IOException {
InputStream is = new FileInputStream(testfile);
byte[] cipherText = this.cryptoStreamer.encrypt(is);
Assert.assertNotNull(cipherText);
Assert.assertTrue(cipherText.length > 2);
byte[] plainText = Cryptoutil
.symDecrypt(cipherText, this.cryptoStreamer.getSecretKey(),
this.cryptoStreamer.getIv());
File f = new File(testfile);
FileInputStream fis = new FileInputStream(f);
Assert.assertArrayEquals(
FileUtils.readDataBinary(fis, (int) f.length()), plainText);
}
@Test
public void testEncryptionOfStream() throws IOException {
FileInputStream fis = new FileInputStream(this.testfile);
InputStream foo = this.cryptoStreamer
.getEncryptedAndHashedInputStream(fis);
FileOutputStream out = new FileOutputStream(this.encryptedOutputFile);
byte[] buffer = new byte[1024];
int numRead = 0;
while ((numRead = foo.read(buffer)) >= 0) {
out.write(buffer, 0, numRead);
}
this.tmpDigest = this.cryptoStreamer.finish();
Assert.assertEquals(Cryptoutil.SYM_SIZE / 8, tmpDigest.length);
byte[] cipher = FileUtils.readDataBinary(new FileInputStream(
this.encryptedOutputFile), (int) new File(
this.encryptedOutputFile).length());
Assert.assertTrue(cipher.length > 10);
byte[] plain = Cryptoutil
.symDecrypt(cipher, this.cryptoStreamer.getSecretKey(),
this.cryptoStreamer.getIv());
File f = new File(this.testfile);
byte[] orgPlain = FileUtils.readDataBinary(new FileInputStream(f),
(int) f.length());
Assert.assertArrayEquals(orgPlain, plain);
}
@Test
public void testDecryptionOfStream() throws IOException {
testEncryptionOfStream();
FileOutputStream os = new FileOutputStream(this.decryptedOutputFile);
OutputStream ros = this.cryptoStreamer
.getDecryptedAndHashedOutputStream(os);
FileInputStream fin = new FileInputStream(this.encryptedOutputFile);
byte[] buffer = new byte[1024];
int numRead = 0;
while ((numRead = fin.read(buffer)) >= 0) {
ros.write(buffer, 0, numRead);
}
ros.flush();
ros.close();
byte[] digest = this.cryptoStreamer.finish();
Assert.assertEquals(Cryptoutil.SYM_SIZE / 8, digest.length);
Assert.assertArrayEquals(this.tmpDigest, digest);
File f = new File(this.decryptedOutputFile);
byte[] plain = FileUtils.readDataBinary(new FileInputStream(f),
(int) f.length());
f = new File(this.testfile);
byte[] realplain = FileUtils.readDataBinary(new FileInputStream(f),
(int) f.length());
Assert.assertArrayEquals(realplain, plain);
}
@Test
public void testThatADigestStreamIsTransparent()
throws FileNotFoundException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException {
// Does not test our functionality, just makes sure that this works.
Cipher cip = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey sk = Cryptoutil.generateSymmetricKey();
cip.init(Cipher.ENCRYPT_MODE, sk);
MessageDigest md = MessageDigest.getInstance("SHA-256");
FileInputStream fis = new FileInputStream(testfile);
DigestInputStream dig = new DigestInputStream(fis, md);
CipherInputStream cipI = new CipherInputStream(dig, cip);
FileOutputStream fos = new FileOutputStream("/tmp/test.txt");
byte buffer[] = new byte[1024];
int numRead = 0;
try {
while ((numRead = cipI.read(buffer)) >= 0) {
fos.write(buffer, 0, numRead);
}
cipI.close();
byte[] tmpdigest = dig.getMessageDigest().digest();
// System.out.println(getHex(tmpdigest));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] iv = cip.getIV();
cip.init(Cipher.DECRYPT_MODE, sk, new IvParameterSpec(iv));
fis = new FileInputStream("/tmp/test.txt");
fos = new FileOutputStream("/tmp/decrypted.txt");
DigestOutputStream digO = new DigestOutputStream(fos, md);
CipherOutputStream cipO = new CipherOutputStream(digO, cip);
buffer = new byte[2048];
numRead = 0;
try {
while ((numRead = fis.read(buffer)) >= 0) {
cipO.write(buffer, 0, numRead);
}
fis.close();
cipO.flush();
cipO.close();
// byte[] digest = dig.getMessageDigest().digest();
// System.out.println(getHex(digest));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static final String HEXES = "0123456789ABCDEF";
public static String getHex(byte[] raw) {
if (raw == null) {
return null;
}
final StringBuilder hex = new StringBuilder(2 * raw.length);
for (final byte b : raw) {
hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(
HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
}