hctr2 0.2.0

An implementation of the length-preserving encryption HCTR2 algorithm.
Documentation
use aes::{Aes128, Aes192, Aes256};
use cipher::{generic_array::GenericArray, KeyInit};
use hctr2::Cipher;
use serde::{Deserialize, Serialize};
use std::{fs, path::PathBuf};

#[derive(Serialize, Deserialize, Debug)]
pub struct TestVector {
    cipher: TestVectorCipher,
    description: String,
    input: TestVectorInput,
    ciphertext_hex: String,
    plaintext_hex: String,
    hash_hex: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct TestVectorCipher {
    blockcipher: TestVectorBlockCipher,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct TestVectorBlockCipher {
    cipher: String,
    lengths: TestVectorBlockCipherLengths,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct TestVectorBlockCipherLengths {
    block: usize,
    key: usize,
    nonce: Option<usize>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct TestVectorInput {
    key_hex: String,
    tweak_hex: String,
    nonce_hex: Option<String>,
}

static MFST_DIR: &str = env!("CARGO_MANIFEST_DIR");

macro_rules! hctr2_test {
    ($name:ident, $C:ident, $fname:expr) => {
        #[test]
        fn $name() {
            let mut path = PathBuf::from(MFST_DIR);
            path.push("tests");
            path.push("testdata");
            path.push($fname);
            let data = fs::read(path).unwrap();

            let vecs: Vec<TestVector> =
                serde_json::from_slice(&data[..]).unwrap();
            for v in &vecs {
                let key = &hex::decode(&v.input.key_hex).unwrap();
                let mut c =
                    Cipher::<$C>::new(GenericArray::from_slice(&key[..]));
                let tweak = hex::decode(&v.input.tweak_hex).unwrap();
                let plaintext = hex::decode(&v.plaintext_hex).unwrap();
                let ciphertext = hex::decode(&v.ciphertext_hex).unwrap();

                let mut got = &mut vec![0u8; plaintext.len()][..];

                c.encrypt(&mut got, &plaintext, &tweak);
                assert_eq!(got, ciphertext);

                c.decrypt(&mut got, &ciphertext, &tweak);
                assert_eq!(got, plaintext);

                c.encrypt_in_place(&mut got, &tweak);
                assert_eq!(got, ciphertext);

                c.decrypt_in_place(&mut got, &tweak);
                assert_eq!(got, plaintext);
            }
        }
    };
}
hctr2_test!(test_hctr2_aes256, Aes256, "HCTR2_AES256.json");
hctr2_test!(test_hctr2_aes192, Aes192, "HCTR2_AES192.json");
hctr2_test!(test_hctr2_aes128, Aes128, "HCTR2_AES128.json");