com.github.aelstad.keccakj.keyak.KeyakTestUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.github.aelstad.keccakj.keyak.KeyakTestUtils.java

Source

/*
 * Copyright 2014 Amund Elstad.
 *
 * 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 com.github.aelstad.keccakj.keyak;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import javax.crypto.AEADBadTagException;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;

import org.apache.commons.codec.binary.Hex;
import org.junit.Assert;

import com.github.aelstad.keccakj.spi.LakeKeyakCipher;
import com.github.aelstad.keccakj.spi.LakeKeyakKey;

public class KeyakTestUtils {
    public interface TestCommand {
    }

    public static class ForgetCommand implements TestCommand {
    }

    public static class PairCommand implements TestCommand {
        byte[] ad = new byte[0];
        byte[] plaintext = new byte[0];
        byte[] ciphertext = new byte[0];
        byte[] tag = new byte[0];
    }

    public static class KeyakTest {
        byte[] key;
        byte[] nonce;

        List<TestCommand> commands = new ArrayList<TestCommand>();
    }

    public List<KeyakTest> parseTests(InputStream is) throws Exception {
        List<KeyakTest> rv = new ArrayList<KeyakTest>();

        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String line;

        KeyakTest nextTest = new KeyakTest();
        PairCommand pc = new PairCommand();
        while ((line = br.readLine()) != null) {
            String token = null;
            String value = null;

            if (line.contains("forget")) {
                nextTest.commands.add(new ForgetCommand());
                continue;
            } else if (line.contains(":")) {
                String[] splitted = line.split(":");
                token = splitted[0].trim();
                value = splitted.length > 1 ? splitted[1].replace(" ", "") : null;
            } else {
                continue;
            }
            if (token.equalsIgnoreCase("initialize with") && nextTest.commands.size() > 0) {
                rv.add(nextTest);
                nextTest = new KeyakTest();
            }

            if (token != null && value != null && token.length() > 0 && value.length() > 0) {
                if (token.equalsIgnoreCase("key")) {
                    nextTest.key = Hex.decodeHex(value.toCharArray());
                } else if (token.equalsIgnoreCase("nonce")) {
                    nextTest.nonce = Hex.decodeHex(value.toCharArray());
                } else if (token.equalsIgnoreCase("ciphertext")) {
                    pc.ciphertext = Hex.decodeHex(value.toCharArray());
                } else if (token.equalsIgnoreCase("plaintext")) {
                    pc.plaintext = Hex.decodeHex(value.toCharArray());
                } else if (token.equalsIgnoreCase("associated data")) {
                    pc.ad = Hex.decodeHex(value.toCharArray());
                } else if (token.equalsIgnoreCase("tag")) {
                    pc.tag = Hex.decodeHex(value.toCharArray());
                    if (pc.tag.length > 16) {
                        byte[] tmp = pc.tag;
                        pc.tag = new byte[16];
                        System.arraycopy(tmp, 0, pc.tag, 0, 16);
                    }

                    nextTest.commands.add(pc);
                    pc = new PairCommand();
                }
            }
        }
        if (nextTest.commands.size() > 0)
            rv.add(nextTest);

        return rv;
    }

    public static String toHex(byte[] buf) {
        if (buf == null)
            return "";
        return new String(Hex.encodeHex(buf));
    }

    public void runTests(List<KeyakTest> tests) throws Exception {
        LakeKeyak wrapper = new LakeKeyak();
        LakeKeyak unwrapper = new LakeKeyak();
        LakeKeyak unwrapperFailing = new LakeKeyak();

        for (KeyakTest dt : tests) {
            System.out.println("initialize with:");
            System.out.println("key: " + toHex(dt.key));
            System.out.println("nonce: " + toHex(dt.nonce));

            wrapper.init(dt.key, dt.nonce);
            unwrapper.init(dt.key, dt.nonce);
            unwrapperFailing.init(dt.key, dt.nonce);

            LakeKeyakCipher lkEncryptingCipher = new LakeKeyakCipher();
            lkEncryptingCipher.init(Cipher.ENCRYPT_MODE, new LakeKeyakKey(dt.key), new IvParameterSpec(dt.nonce));

            LakeKeyakCipher lkDecryptingCipher = new LakeKeyakCipher();
            lkDecryptingCipher.init(Cipher.DECRYPT_MODE, new LakeKeyakKey(dt.key), new IvParameterSpec(dt.nonce));

            LakeKeyakCipher lkDecryptingFailing = new LakeKeyakCipher();
            lkDecryptingFailing.init(Cipher.DECRYPT_MODE, new LakeKeyakKey(dt.key), new IvParameterSpec(dt.nonce));

            for (TestCommand tc : dt.commands) {
                if (tc instanceof ForgetCommand) {
                    System.out.println("forget");
                    lkEncryptingCipher.forget();
                    lkDecryptingCipher.forget();
                } else if (tc instanceof PairCommand) {
                    PairCommand pc = (PairCommand) tc;
                    System.out.println("associated data: " + toHex(pc.ad));
                    System.out.println("plaintext: " + toHex(pc.plaintext));
                    System.out.println("ciphertext: " + toHex(pc.ciphertext));
                    System.out.println("tag: " + toHex(pc.tag));

                    byte[] wrapOut = new byte[pc.plaintext.length];
                    byte[] tagOut = new byte[pc.tag.length];

                    lkEncryptingCipher.updateAAD(pc.ad);
                    byte[] encrypted = lkEncryptingCipher.doFinal(pc.plaintext);
                    Assert.assertTrue(encrypted.length == pc.plaintext.length + 16);

                    System.arraycopy(encrypted, 0, wrapOut, 0, pc.plaintext.length);
                    System.arraycopy(encrypted, encrypted.length - 16, tagOut, 0, 16);

                    System.out.println("got ciphertext: " + toHex(wrapOut));
                    System.out.println("got tag: " + toHex(tagOut));

                    Assert.assertArrayEquals(wrapOut, pc.ciphertext);
                    Assert.assertArrayEquals(tagOut, pc.tag);

                    lkDecryptingCipher.updateAAD(pc.ad);
                    byte[] decrypted = lkDecryptingCipher.doFinal(encrypted);
                    Assert.assertArrayEquals(decrypted, pc.plaintext);

                    lkDecryptingFailing.updateAAD(pc.ad);
                    AEADBadTagException expected = null;
                    try {
                        byte[] decryptedFailing = lkDecryptingFailing.doFinal(new byte[16]);
                    } catch (AEADBadTagException ex) {
                        expected = ex;
                    }
                    Assert.assertNotNull(expected);

                    lkDecryptingFailing = new LakeKeyakCipher();
                    lkDecryptingFailing.init(Cipher.DECRYPT_MODE, new LakeKeyakKey(dt.key),
                            new IvParameterSpec(dt.nonce));

                }
                System.out.println();
            }

        }
    }
}