org.cryptonode.jncryptor.TestVectorReader.java Source code

Java tutorial

Introduction

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

Source

/*    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 java.io.EOFException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.bind.DatatypeConverter;

import org.apache.commons.io.FileUtils;

/**
 * Reads test vectors supplied by Rob Napier.
 */
class TestVectorReader {

    private static final String COMMENT_CHAR = "#";
    private static final String TITLE_FIELD = "title";
    private static final String VERSION_FIELD = "version";
    private static final String PASSWORD_FIELD = "password";
    private static final String SALT_FIELD = "salt_hex";
    private static final String KEY_FIELD = "key_hex";
    private static final String ENCRYPTION_KEY_FIELD = "enc_key_hex";
    private static final String HMAC_KEY_FIELD = "hmac_key_hex";
    private static final String IV_KEY_FIELD = "iv_hex";
    private static final String PLAINTEXT_FIELD = "plaintext_hex";
    private static final String CIPHERTEXT_FIELD = "ciphertext_hex";
    private static final String ENCRYPTION_SALT_FIELD = "enc_salt_hex";
    private static final String HMAC_SALT_FIELD = "hmac_salt_hex";

    public static void main(String[] args) throws Exception {
        List<KeyTestVector> readKeyVectors = readKeyVectors();
        for (KeyTestVector keyTestVector : readKeyVectors) {
            System.out.println(keyTestVector);
        }
    }

    static List<KDFTestVector> readKDFVectors() throws IOException {
        List<String> lines = readLinesFromTestResource("/kdf-v3");

        final Iterator<String> iterator = lines.iterator();

        List<KDFTestVector> result = new ArrayList<KDFTestVector>();

        while (true) {
            String titleValue = readNextValue(iterator, TITLE_FIELD, false);
            if (titleValue == null) {
                // we are done
                break;
            }

            int versionValue = Integer.parseInt(readNextValue(iterator, VERSION_FIELD, true));

            String passwordValue = readNextValue(iterator, PASSWORD_FIELD, true);
            byte[] saltValue = DatatypeConverter
                    .parseHexBinary(readNextValue(iterator, SALT_FIELD, true).replace(" ", ""));
            byte[] keyValue = DatatypeConverter
                    .parseHexBinary(readNextValue(iterator, KEY_FIELD, true).replace(" ", ""));

            result.add(new KDFTestVector(titleValue, versionValue, passwordValue, saltValue, keyValue));
        }

        return result;
    }

    static List<KeyTestVector> readKeyVectors() throws IOException {
        List<String> lines = readLinesFromTestResource("/key-v3");

        final Iterator<String> iterator = lines.iterator();

        List<KeyTestVector> result = new ArrayList<KeyTestVector>();

        while (true) {
            String titleValue = readNextValue(iterator, TITLE_FIELD, false);
            if (titleValue == null) {
                // we are done
                break;
            }

            int versionValue = Integer.parseInt(readNextValue(iterator, VERSION_FIELD, true));

            byte[] encryptionKey = DatatypeConverter
                    .parseHexBinary(readNextValue(iterator, ENCRYPTION_KEY_FIELD, true).replace(" ", ""));
            byte[] hmacKey = DatatypeConverter
                    .parseHexBinary(readNextValue(iterator, HMAC_KEY_FIELD, true).replace(" ", ""));
            byte[] iv = DatatypeConverter
                    .parseHexBinary(readNextValue(iterator, IV_KEY_FIELD, true).replace(" ", ""));
            byte[] plaintext = DatatypeConverter
                    .parseHexBinary(readNextValue(iterator, PLAINTEXT_FIELD, true).replace(" ", ""));
            byte[] ciphertext = DatatypeConverter
                    .parseHexBinary(readNextValue(iterator, CIPHERTEXT_FIELD, true).replace(" ", ""));

            result.add(
                    new KeyTestVector(titleValue, versionValue, encryptionKey, hmacKey, iv, plaintext, ciphertext));
        }

        return result;
    }

    static List<PasswordTestVector> readPasswordVectors() throws IOException {
        List<String> lines = readLinesFromTestResource("/password-v3");

        final Iterator<String> iterator = lines.iterator();

        List<PasswordTestVector> result = new ArrayList<PasswordTestVector>();

        while (true) {
            String titleValue = readNextValue(iterator, TITLE_FIELD, false);
            if (titleValue == null) {
                // we are done
                break;
            }

            int versionValue = Integer.parseInt(readNextValue(iterator, VERSION_FIELD, true));
            String password = readNextValue(iterator, PASSWORD_FIELD, false);

            byte[] encryptionSalt = DatatypeConverter
                    .parseHexBinary(readNextValue(iterator, ENCRYPTION_SALT_FIELD, true).replace(" ", ""));
            byte[] hmacSalt = DatatypeConverter
                    .parseHexBinary(readNextValue(iterator, HMAC_SALT_FIELD, true).replace(" ", ""));
            byte[] iv = DatatypeConverter
                    .parseHexBinary(readNextValue(iterator, IV_KEY_FIELD, true).replace(" ", ""));
            byte[] plaintext = DatatypeConverter
                    .parseHexBinary(readNextValue(iterator, PLAINTEXT_FIELD, true).replace(" ", ""));
            byte[] ciphertext = DatatypeConverter
                    .parseHexBinary(readNextValue(iterator, CIPHERTEXT_FIELD, true).replace(" ", ""));

            result.add(new PasswordTestVector(titleValue, versionValue, password, encryptionSalt, hmacSalt, iv,
                    plaintext, ciphertext));
        }

        return result;
    }

    private static String readNextValue(Iterator<String> iterator, String expectedLabel,
            boolean throwExceptionIfMissing) throws IOException {
        String line = readNextNonCommentLine(iterator, throwExceptionIfMissing);

        if (line == null) {
            if (throwExceptionIfMissing) {
                throw new IOException("Unexpected null return value.");
            } else {
                return null;
            }
        }

        int colonIndex = line.indexOf(":");
        if (colonIndex == -1) {
            throw new IOException("No colon found in line.");
        }

        String label = line.substring(0, colonIndex).trim();
        String value = line.substring(colonIndex + 1).trim();

        if (label.equals(expectedLabel)) {
            return value;
        } else {
            throw new IOException(String.format("Bad label. Expected '%s' but got '%s'.", expectedLabel, label));
        }
    }

    /**
     * Returns a trimmed version of the next non-blank line that doesn't begin
     * with a comment character.
     * 
     * @param iterator
     * @param throwExceptionIfMissing
     *          TODO
     * @return the next string, or <code>null</code> if there is none
     */
    private static String readNextNonCommentLine(Iterator<String> iterator, boolean throwExceptionIfMissing)
            throws IOException {
        while (iterator.hasNext()) {
            String trimmed = iterator.next().trim();

            if (trimmed.isEmpty()) {
                continue;
            }

            if (!trimmed.startsWith(COMMENT_CHAR)) {
                return trimmed;
            }
        }

        if (throwExceptionIfMissing) {
            throw new EOFException("Failed to read next non-comment line.");
        }

        return null;
    }

    private static List<String> readLinesFromTestResource(String resource) throws IOException {
        URL url = TestVectorReader.class.getResource(resource);

        if (url == null) {
            throw new FileNotFoundException(resource);
        }

        try {
            URI uri = new URI(url.toString());
            return FileUtils.readLines(new File(uri), "UTF-8");
        } catch (URISyntaxException e) {
            throw new IOException(e);
        }
    }
}