org.cryptonode.jncryptor.AES256v2CryptorTest.java Source code

Java tutorial

Introduction

Here is the source code for org.cryptonode.jncryptor.AES256v2CryptorTest.java

Source

/*    Copyright 2013 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.assertArrayEquals;
import static org.junit.Assert.assertEquals;

import java.util.Random;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

import org.apache.commons.io.Charsets;
import org.cryptonode.jncryptor.AES256v2Cryptor;
import org.cryptonode.jncryptor.CryptorException;
import org.cryptonode.jncryptor.InvalidHMACException;
import org.junit.Assert;
import org.junit.Test;

/**
 * 
 */
public class AES256v2CryptorTest {

    private static final Random RANDOM = new Random();

    /**
     * Performs a simple round-trip encryption and decryption.
     * 
     * @throws Exception
     */
    @Test
    public void testEncryptionAndDecryption() throws Exception {
        String password = "1234";
        byte[] plaintext = "Hello, World!".getBytes();

        AES256v2Cryptor cryptor = new AES256v2Cryptor();
        byte[] ciphertext = cryptor.encryptData(plaintext, password.toCharArray());
        byte[] plaintext2 = cryptor.decryptData(ciphertext, password.toCharArray());
        Assert.assertArrayEquals(plaintext, plaintext2);
    }

    /**
     * Creates a valid ciphertext, modifies the MAC and verifies that the
     * decryption fails.
     * 
     * @throws Exception
     */
    @Test(expected = InvalidHMACException.class)
    public void testBrokenHMAC() throws Exception {
        String password = "1234";
        byte[] plaintext = "Hello, World!".getBytes();

        AES256v2Cryptor cryptor = new AES256v2Cryptor();
        byte[] ciphertext = cryptor.encryptData(plaintext, password.toCharArray());

        // Change one byte in the HMAC
        ciphertext[ciphertext.length - 1] = (byte) (ciphertext[ciphertext.length - 1] + 1);

        cryptor.decryptData(ciphertext, password.toCharArray());
    }

    /**
     * Tests an exception is thrown when the ciphertext is in a bad format.
     * 
     * @throws Exception
     */
    @Test(expected = CryptorException.class)
    public void testBadInput() throws Exception {
        final byte[] nonsenseData = new byte[] { 0x45, 0x55 };
        new AES256v2Cryptor().decryptData(nonsenseData, "blah".toCharArray());
    }

    /**
     * Tests decryption of a known ciphertext.
     * 
     * @throws Exception
     */
    @Test
    public void testKnownCiphertext() throws Exception {
        final String password = "P@ssw0rd!";
        final String expectedPlaintextString = "Hello, World! Let's use a few blocks " + "with a longer sentence.";

        // TODO confirm this with Rob Napier
        String knownCiphertext = "02013F194AA9969CF70C8ACB76824DE4CB6CDCF78B7449A87C679FB8EDB6"
                + "A0109C513481DE877F3A855A184C4947F2B3E8FEF7E916E4739F9F889A717FCAF277402866341008A"
                + "09FD3EBAC7FA26C969DD7EE72CFB695547C971A75D8BF1CC5980E0C727BD9F97F6B7489F687813BEB"
                + "94DEB61031260C246B9B0A78C2A52017AA8C92";

        byte[] ciphertext = DatatypeConverter.parseHexBinary(knownCiphertext);

        AES256v2Cryptor cryptor = new AES256v2Cryptor();
        byte[] plaintext = cryptor.decryptData(ciphertext, password.toCharArray());

        String plaintextString = new String(plaintext, Charsets.UTF_8);

        assertEquals(expectedPlaintextString, plaintextString);
    }

    // @Test
    // public void makeKnownCiphertext() throws Exception {
    // final String password = "P@ssw0rd!";
    // final String plaintextString = "Hello, World! Let's use a few blocks "
    // + "with a longer sentence.";
    //
    // final byte[] plaintext = plaintextString.getBytes("US-ASCII");
    //
    // AES256v2Cryptor cryptor = new AES256v2Cryptor();
    // byte[] ciphertext = cryptor.encryptData(plaintext, password.toCharArray());
    //
    // System.out.println(DatatypeConverter.printHexBinary(plaintext));
    // System.out.println(DatatypeConverter.printHexBinary(ciphertext));
    // }

    /**
     * Tests a {@link NullPointerException} is thrown when the ciphertext is null
     * during decryption.
     * 
     * @throws Exception
     */
    @Test(expected = NullPointerException.class)
    public void testNullCiphertextInDecrypt() throws Exception {
        new AES256v2Cryptor().decryptData(null, "blah".toCharArray());
    }

    /**
     * Tests a {@link NullPointerException} is thrown when the plaintext is null
     * during encryption.
     * 
     * @throws Exception
     */
    @Test(expected = NullPointerException.class)
    public void testNullPlaintextInEncrypt() throws Exception {
        new AES256v2Cryptor().encryptData(null, "blah".toCharArray());
    }

    /**
     * Performs an encryption followed by a decryption and confirms the data is
     * the same. Uses the key-based methods.
     * 
     * @throws Exception
     */
    @Test
    public void testKeyBasedEncryptionAndDecryption() throws Exception {
        SecretKey encryptionKey = makeRandomAESKey();
        SecretKey hmacKey = makeRandomAESKey();

        final byte[] plaintext = "Hello, World!".getBytes();

        AES256v2Cryptor cryptor = new AES256v2Cryptor();
        byte[] ciphertext = cryptor.encryptData(plaintext, encryptionKey, hmacKey);
        byte[] newPlaintext = cryptor.decryptData(ciphertext, encryptionKey, hmacKey);
        assertArrayEquals(plaintext, newPlaintext);
    }

    private static SecretKey makeRandomAESKey() {
        byte[] keyBytes = new byte[16];
        RANDOM.nextBytes(keyBytes);

        return new SecretKeySpec(keyBytes, "AES");
    }

    /**
     * Checks an exception is thrown when a bad salt length is suggested.
     * 
     * @throws Exception
     */
    @Test(expected = IllegalArgumentException.class)
    public void testBadSaltLengthForKey() throws Exception {
        new AES256v2Cryptor().keyForPassword(null, new byte[AES256v2Cryptor.SALT_LENGTH + 1]);
    }

    /**
     * Tests we return the correct version number.
     * 
     * @throws Exception
     */
    @Test
    public void testVersionNumber() throws Exception {
        assertEquals(2, new AES256v2Cryptor().getVersionNumber());
    }

    /**
     * Tests we get an exception if we try to decrypt a key-based ciphertext with
     * a password.
     * 
     * @throws Exception
     */
    @Test(expected = IllegalArgumentException.class)
    public void testDecryptionMismatch() throws Exception {
        SecretKey encryptionKey = makeRandomAESKey();
        SecretKey hmacKey = makeRandomAESKey();

        final byte[] plaintext = "Hello, World!".getBytes();

        AES256v2Cryptor cryptor = new AES256v2Cryptor();
        byte[] ciphertext = cryptor.encryptData(plaintext, encryptionKey, hmacKey);

        cryptor.decryptData(ciphertext, "whoops!".toCharArray());
    }
}