From 89f706d07dc2f032f695b9b147046ebe3551c468 Mon Sep 17 00:00:00 2001 From: Avril Date: Sat, 20 Mar 2021 01:44:02 +0000 Subject: [PATCH] encrypt and decrypt example tests work --- Cargo.lock | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 1 + src/cha.rs | 78 +-------------------------- src/ext.rs | 116 ++++++++++++++++++++++++++++++++++++++++ src/key.rs | 98 ++++++++++++++++++++++++++++++++++ src/main.rs | 30 +++++++---- 6 files changed, 385 insertions(+), 88 deletions(-) create mode 100644 src/ext.rs create mode 100644 src/key.rs diff --git a/Cargo.lock b/Cargo.lock index a661d3a..959d337 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,15 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "cc" version = "1.0.67" @@ -37,11 +46,27 @@ name = "chachaex" version = "0.1.0" dependencies = [ "base64", - "getrandom", - "hex-literal", + "getrandom 0.2.2", + "hex-literal 0.3.1", + "khash", "openssl", ] +[[package]] +name = "cpuid-bool" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "foreign-types" version = "0.3.2" @@ -57,6 +82,27 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.2" @@ -65,7 +111,17 @@ checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "hex-literal" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" +dependencies = [ + "hex-literal-impl", + "proc-macro-hack", ] [[package]] @@ -74,6 +130,27 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5af1f635ef1bc545d78392b136bfe1c9809e029023c84a3638a864a10b8819c8" +[[package]] +name = "hex-literal-impl" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "853f769599eb31de176303197b7ba4973299c38c7a7604a6bc88c3eef05b9b46" +dependencies = [ + "proc-macro-hack", +] + +[[package]] +name = "khash" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193f6499a7299fa3f470fac8c79bbd148370f6085b0c2fa4f32a03f517f7a6e7" +dependencies = [ + "getrandom 0.1.16", + "hex-literal 0.2.1", + "rustc_version", + "sha2", +] + [[package]] name = "libc" version = "0.2.90" @@ -86,6 +163,12 @@ version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "openssl" version = "0.10.33" @@ -119,12 +202,73 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "sha2" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" +dependencies = [ + "block-buffer", + "cfg-if", + "cpuid-bool", + "digest", + "opaque-debug", +] + +[[package]] +name = "typenum" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" + [[package]] name = "vcpkg" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 685f9df..ebfd2aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,5 @@ edition = "2018" base64 = "0.13.0" getrandom = "0.2.2" hex-literal = "0.3.1" +khash = {version = "2.0.3", default-features=false} openssl = "0.10.32" diff --git a/src/cha.rs b/src/cha.rs index 3bf7f9a..9395f10 100644 --- a/src/cha.rs +++ b/src/cha.rs @@ -1,25 +1,17 @@ -use getrandom::getrandom; use openssl::{ symm::{ Cipher, Crypter, Mode, }, error::ErrorStack, }; +use crate::key::{Key, IV}; pub const KEY_SIZE: usize = 32; pub const IV_SIZE: usize = 12; static NEW_CIPHER: fn() -> Cipher = Cipher::chacha20_poly1305; -#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] -#[repr(transparent)] -pub struct Key([u8; KEY_SIZE]); - -#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] -#[repr(transparent)] -pub struct IV([u8; IV_SIZE]); - #[inline] pub fn decrypter(key: impl AsRef, iv: impl AsRef) -> Result { Crypter::new( @@ -39,74 +31,8 @@ pub struct IV([u8; IV_SIZE]); ) } -impl Key -{ - pub fn new() -> Self - { - let mut output = [0u8; KEY_SIZE]; - getrandom(&mut output[..]).expect("rng fatal"); - Self(output) - } -} - -impl IV -{ - pub fn new() -> Self - { - let mut output = [0u8; IV_SIZE]; - getrandom(&mut output[..]).expect("rng fatal"); - Self(output) - } -} - -impl AsRef<[u8]> for Key -{ - fn as_ref(&self) -> &[u8] - { - &self.0[..] - } -} -impl AsRef<[u8]> for IV -{ - fn as_ref(&self) -> &[u8] - { - &self.0[..] - } -} - -impl AsMut<[u8]> for Key -{ - fn as_mut(&mut self) -> &mut [u8] - { - &mut self.0[..] - } -} - -impl AsMut<[u8]> for IV -{ - fn as_mut(&mut self) -> &mut [u8] - { - &mut self.0[..] - } -} - +/// Generate a random key and IV. #[inline(always)] pub fn keygen() -> (Key, IV) { (Key::new(), IV::new()) } - -impl AsRef for Key -{ - #[inline] fn as_ref(&self) -> &Key - { - self - } -} -impl AsRef for IV -{ - #[inline] fn as_ref(&self) -> &IV - { - self - } -} - diff --git a/src/ext.rs b/src/ext.rs new file mode 100644 index 0000000..10e127c --- /dev/null +++ b/src/ext.rs @@ -0,0 +1,116 @@ +use std::{ + mem, + iter::{ + self, + ExactSizeIterator, + FusedIterator, + }, + slice, + fmt, +}; +#[derive(Debug, Clone)] +pub struct HexStringIter(I, [u8; 2]); + +impl> HexStringIter +{ + /// Write this hex string iterator to a formattable buffer + pub fn consume(self, f: &mut F) -> fmt::Result + where F: std::fmt::Write + { + if self.1[0] != 0 { + write!(f, "{}", self.1[0] as char)?; + } + if self.1[1] != 0 { + write!(f, "{}", self.1[1] as char)?; + } + + for x in self.0 { + write!(f, "{:02x}", x)?; + } + + Ok(()) + } + + /// Consume into a string + pub fn into_string(self) -> String + { + let mut output = match self.size_hint() { + (0, None) => String::new(), + (_, Some(x)) | + (x, None) => String::with_capacity(x), + }; + self.consume(&mut output).unwrap(); + output + } +} + +pub trait HexStringIterExt: Sized +{ + fn into_hex(self) -> HexStringIter; +} + +pub type HexStringSliceIter<'a> = HexStringIter>>; + +pub trait HexStringSliceIterExt +{ + fn hex(&self) -> HexStringSliceIter<'_>; +} + +impl HexStringSliceIterExt for S + where S: AsRef<[u8]> +{ + fn hex(&self) -> HexStringSliceIter<'_> + { + self.as_ref().iter().copied().into_hex() + } +} + +impl> HexStringIterExt for I +{ + #[inline] fn into_hex(self) -> HexStringIter { + HexStringIter(self.into_iter(), [0u8; 2]) + } +} + +impl> Iterator for HexStringIter +{ + type Item = char; + fn next(&mut self) -> Option + { + match self.1 { + [_, 0] => { + use std::io::Write; + write!(&mut self.1[..], "{:02x}", self.0.next()?).unwrap(); + + Some(mem::replace(&mut self.1[0], 0) as char) + }, + [0, _] => Some(mem::replace(&mut self.1[1], 0) as char), + _ => unreachable!(), + } + } + + fn size_hint(&self) -> (usize, Option) { + let (l, h) = self.0.size_hint(); + + (l * 2, h.map(|x| x*2)) + } +} + +impl + ExactSizeIterator> ExactSizeIterator for HexStringIter{} +impl + FusedIterator> FusedIterator for HexStringIter{} + +impl> From> for String +{ + fn from(from: HexStringIter) -> Self + { + from.into_string() + } +} + +impl + Clone> fmt::Display for HexStringIter +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + self.clone().consume(f) + } +} diff --git a/src/key.rs b/src/key.rs new file mode 100644 index 0000000..0074eca --- /dev/null +++ b/src/key.rs @@ -0,0 +1,98 @@ +use getrandom::getrandom; +use std::fmt; +use crate::cha::{ + KEY_SIZE, + IV_SIZE, +}; +use crate::ext::*; + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] +#[repr(transparent)] +pub struct Key([u8; KEY_SIZE]); + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] +#[repr(transparent)] +pub struct IV([u8; IV_SIZE]); + + +impl Key +{ + pub fn new() -> Self + { + let mut output = [0u8; KEY_SIZE]; + getrandom(&mut output[..]).expect("rng fatal"); + Self(output) + } +} + +impl IV +{ + pub fn new() -> Self + { + let mut output = [0u8; IV_SIZE]; + getrandom(&mut output[..]).expect("rng fatal"); + Self(output) + } +} + +impl AsRef<[u8]> for Key +{ + fn as_ref(&self) -> &[u8] + { + &self.0[..] + } +} +impl AsRef<[u8]> for IV +{ + fn as_ref(&self) -> &[u8] + { + &self.0[..] + } +} + +impl AsMut<[u8]> for Key +{ + fn as_mut(&mut self) -> &mut [u8] + { + &mut self.0[..] + } +} + +impl AsMut<[u8]> for IV +{ + fn as_mut(&mut self) -> &mut [u8] + { + &mut self.0[..] + } +} + +impl AsRef for Key +{ + #[inline] fn as_ref(&self) -> &Key + { + self + } +} +impl AsRef for IV +{ + #[inline] fn as_ref(&self) -> &IV + { + self + } +} + +impl fmt::Display for Key +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "Key({})", self.0.iter().copied().into_hex()) + } +} + +impl fmt::Display for IV +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "Key({})", self.0.iter().copied().into_hex()) + } +} diff --git a/src/main.rs b/src/main.rs index abc9b91..5c58c12 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,19 @@ #[macro_use] extern crate hex_literal; +mod ext; use ext::*; + +mod key; mod cha; -use cha::{Key, IV}; +use key::{Key, IV}; -fn encrypt((key, iv): &(Key, IV), input: impl Into>) -> Result +fn encrypt((key, iv): &(Key, IV), input: impl AsRef<[u8]>) -> Result { - let input = input.into();//.into(); + let input = input.as_ref(); let mut output = vec![0u8; input.len()]; - eprintln!("(enc) Key: {:?}, IV: {:?}, Input: ({}, {:?})", key, iv, input.len(), input); + eprintln!("(enc) Key: {}, IV: {}, Input: ({}, {})", key, iv, input.len(), input.hex()); let mut enc = cha::encrypter(key, iv)?; @@ -21,12 +24,12 @@ fn encrypt((key, iv): &(Key, IV), input: impl Into>) -> Result) -> Result, openssl::error::ErrorStack> +fn decrypt((key, iv): &(Key, IV), input: impl AsRef) -> Result, openssl::error::ErrorStack> { - let input = base64::decode(input.into()).expect("invalid base64"); + let input = base64::decode(input.as_ref()).expect("invalid base64"); let mut output = vec![0u8; input.len()]; - eprintln!("(dec) Key: {:?}, IV: {:?}, Input: ({}, {:?})", key, iv, input.len(), input); + eprintln!("(dec) Key: {}, IV: {}, Input: ({}, {})", key, iv, input.len(), input.hex()); let mut dec = cha::decrypter(key, iv)?; @@ -39,10 +42,19 @@ fn decrypt((key, iv): &(Key, IV), input: impl Into) -> Result, o } fn main() { + let input = std::env::args().nth(1).unwrap_or({ + let mut input = [0u8; 16]; + getrandom::getrandom(&mut input[..]).expect("rng fatal"); + khash::generate(&Default::default(), input).expect("kana-hash fatal") + //input.hex().into() + }); + let key = cha::keygen(); - let enc = encrypt(&key, std::env::args().nth(1).unwrap()).expect("encrypt"); + let enc = encrypt(&key, &input).expect("encrypt"); println!("{}", enc); let dec = decrypt(&key, enc).expect("decrypt"); - println!("{:?}", std::str::from_utf8(&dec[..]).unwrap()); + let output = std::str::from_utf8(&dec[..]).unwrap(); + println!("{:?}", output); + assert_eq!(output, &input[..]); }