use std::io::{Read, Write, Seek};
use std::collections::HashSet;
use std::rc::Rc;
pub const PW_KEY_SIZE: usize = 64;
pub const IV_SIZE: usize = 16;
use std::clone::Clone;
pub type PwKeyArray = [u8; PW_KEY_SIZE];
pub type IvArray = [u8; IV_SIZE];
#[derive(Clone)]
pub enum Mode {
Unknown,
Encrypt,
Decrypt,
}
pub trait SeekRead: Seek + Read {}
impl<T> SeekRead for T where T: Seek + Read
{}
pub trait SeekWrite: Seek + Write {}
impl<T> SeekWrite for T where T: Seek + Write
{}
#[derive(PartialEq,Eq,Hash)]
#[derive(Clone)]
pub enum OutputOption {
AllowOverwrite,
IncludeKeyMetadata,
}
#[derive(Clone)]
pub enum InputStream {
Unknown,
File(String),
}
#[derive(Clone)]
pub enum OutputStream {
Unknown,
File(String),
}
#[derive(Clone)]
pub enum OutputFormat {
EncryptFile,
}
#[derive(Clone)]
pub enum RngMode {
Os,
OsIssac,
OsRandIssac,
Func(Rc<Box<Fn() -> u8>>),
}
#[derive(Clone)]
pub enum InitializationVector {
Unknown,
GenerateFromRng,
Func(Rc<Box<Fn() -> IvArray>>),
}
#[derive(Clone)]
pub enum EncryptionMethod {
AesCbc256,
}
#[derive(Clone)]
pub struct ScryptLogN(pub u8);
#[derive(Clone)]
pub struct ScryptR(pub u32);
#[derive(Clone)]
pub struct ScryptP(pub u32);
#[derive(Clone)]
pub enum PasswordKeyGenMethod {
Scrypt(ScryptLogN, ScryptR, ScryptP),
ReadFromFile,
}
#[derive(Clone)]
pub enum PasswordType {
Unknown,
Text(String, PasswordKeyGenMethod),
Func(Rc<Box<Fn() -> PwKeyArray>>),
}
#[derive(Debug,Clone)]
pub enum ValidateError {
ModeNotSet,
InvalidInputStream,
InvalidOutputStream,
PasswordTypeIsUnknown,
PasswordIsEmpty,
BufferTooSmall,
}
struct DerivedKeyStruct {
key: PwKeyArray
}
impl Clone for DerivedKeyStruct {
fn clone(&self) -> Self {
let ckey = self.key;
DerivedKeyStruct {
key: ckey
}
}
}
#[derive(Clone)]
pub struct Config {
mode: Mode,
input_stream: InputStream,
output_stream: OutputStream,
output_format: OutputFormat,
output_options: HashSet<OutputOption>,
rng_mode: RngMode,
initialization_vector: InitializationVector,
password: PasswordType,
salt: String,
encryption_method: EncryptionMethod,
buffer_size: usize,
derived_key: Option<DerivedKeyStruct>
}
pub fn slice_is_zeroed(d: &[u8]) -> bool {
d.iter().find(|b| **b != 0).is_none()
}
#[cfg(not(test))]
pub fn scrypt_defaults() -> PasswordKeyGenMethod {
PasswordKeyGenMethod::Scrypt(ScryptLogN(16), ScryptR(8), ScryptP(1))
}
#[cfg(any(test,doc))]
pub fn scrypt_defaults() -> PasswordKeyGenMethod {
PasswordKeyGenMethod::Scrypt(ScryptLogN(4), ScryptR(1), ScryptP(1))
}
#[allow(dead_code)]
pub fn scrypt_params_encrypt1() -> PasswordKeyGenMethod {
PasswordKeyGenMethod::Scrypt(ScryptLogN(20), ScryptR(8), ScryptP(1))
}
impl Config {
pub fn new() -> Self {
let mut def_opts = HashSet::new();
def_opts.insert(OutputOption::IncludeKeyMetadata);
Config {
mode: Mode::Unknown,
input_stream: InputStream::Unknown,
output_stream: OutputStream::Unknown,
output_format: OutputFormat::EncryptFile,
output_options: def_opts,
rng_mode: RngMode::OsIssac,
initialization_vector: InitializationVector::GenerateFromRng,
password: PasswordType::Unknown,
salt: "DefaultSalt".to_owned(),
encryption_method: EncryptionMethod::AesCbc256,
buffer_size: 65536,
derived_key: None
}
}
pub fn decrypt(&mut self) -> &mut Self {
self.mode = Mode::Decrypt;
self
}
pub fn encrypt(&mut self) -> &mut Self {
self.mode = Mode::Encrypt;
self
}
pub fn input_stream(&mut self, is: InputStream) -> &mut Self {
self.input_stream = is;
self
}
pub fn output_stream(&mut self, os: OutputStream) -> &mut Self {
self.output_stream = os;
self
}
pub fn output_options(&mut self, opts: HashSet<OutputOption>) -> &mut Self {
self.output_options = opts;
self
}
pub fn add_output_option(&mut self, opt: OutputOption) -> &mut Self {
self.output_options.insert(opt);
self
}
pub fn remove_output_option(&mut self, opt: OutputOption) -> &mut Self {
self.output_options.remove(&opt);
self
}
pub fn rng_mode(&mut self, rng_mode: RngMode) -> &mut Self {
self.rng_mode = rng_mode;
self
}
pub fn initialization_vector(&mut self,
initialization_vector: InitializationVector)
-> &mut Self {
self.initialization_vector = initialization_vector;
self
}
pub fn password(&mut self, password: PasswordType) -> &mut Self {
self.password = password;
self.derived_key = None;
self
}
pub fn salt(&mut self, salt: &str) -> &mut Self {
self.salt = salt.to_owned();
self
}
pub fn encryption_method(&mut self, encryption_method: EncryptionMethod) -> &mut Self {
self.encryption_method = encryption_method;
self
}
pub fn buffer_size(&mut self, buffer_size: usize) -> &mut Self {
self.buffer_size = buffer_size;
self
}
pub fn derive_key(&mut self) -> Result<PwKeyArray, super::EncryptError>{
super::get_pw_key(self)
.map(|key| {
self.derived_key = Some(DerivedKeyStruct {
key: key
});
key
})
}
pub fn validate(&self) -> Result<(), ValidateError> {
if let Mode::Unknown = self.mode {
return Err(ValidateError::ModeNotSet);
}
if let InputStream::Unknown = self.input_stream {
return Err(ValidateError::InvalidInputStream);
}
if let OutputStream::Unknown = self.output_stream {
return Err(ValidateError::InvalidOutputStream);
}
match self.password {
PasswordType::Unknown => return Err(ValidateError::PasswordTypeIsUnknown),
PasswordType::Text(ref s, _) if s.is_empty() => {
return Err(ValidateError::PasswordIsEmpty)
}
PasswordType::Func(_) |
PasswordType::Text(_, _) => (),
}
if self.buffer_size < 4096 {
return Err(ValidateError::BufferTooSmall);
}
Ok(())
}
pub fn get_mode(&self) -> &Mode {
return &self.mode;
}
pub fn get_input_stream(&self) -> &InputStream {
return &self.input_stream;
}
pub fn get_output_stream(&self) -> &OutputStream {
return &self.output_stream;
}
pub fn get_output_format(&self) -> &OutputFormat {
return &self.output_format;
}
pub fn get_output_options(&self) -> &HashSet<OutputOption> {
return &self.output_options;
}
pub fn get_rng_mode(&self) -> &RngMode {
return &self.rng_mode;
}
pub fn get_initialization_vector(&self) -> &InitializationVector {
return &self.initialization_vector;
}
pub fn get_password(&self) -> &PasswordType {
return &self.password;
}
pub fn get_salt(&self) -> &str {
return &self.salt;
}
pub fn get_encryption_method(&self) -> &EncryptionMethod {
return &self.encryption_method;
}
pub fn get_buffer_size(&self) -> usize {
return self.buffer_size;
}
pub fn get_derived_key(&self) -> Option<PwKeyArray> {
match &self.derived_key {
&None => None,
&Some(ref ks) => {
Some(ks.clone().key)
}
}
}
}
#[test]
fn validate() {
macro_rules! check {
( $c:expr, $case:path ) => {
match $c.validate() {
Err( $case ) => (),
x => panic!("Unexpected validate error: {:?}", x)
}
}
}
macro_rules! check_ok {
( $c:expr ) => {
match $c.validate() {
Ok(_) => (),
x => panic!("Unexpected validate error: {:?}", x)
}
}
}
let mut c = Config::new();
check!(c, ValidateError::ModeNotSet);
c.decrypt();
check!(c, ValidateError::InvalidInputStream);
c.input_stream(InputStream::File("/foo".to_owned()));
check!(c, ValidateError::InvalidOutputStream);
c.output_stream(OutputStream::File("/foo.out".to_owned()));
check!(c, ValidateError::PasswordTypeIsUnknown);
c.password(PasswordType::Text("".to_owned(), scrypt_defaults()));
check!(c, ValidateError::PasswordIsEmpty);
c.password(PasswordType::Text(" ".to_owned(), scrypt_defaults()));
check_ok!(c);
let mut pd: [u8; PW_KEY_SIZE] = [0; PW_KEY_SIZE];
pd[0] = 1;
c.password(PasswordType::Func(Rc::new(Box::new(move || pd))));
check_ok!(c);
c.buffer_size(0);
check!(c, ValidateError::BufferTooSmall);
c.buffer_size(4096);
check_ok!(c);
}
#[test]
fn derived_key() {
fn are_eq(a:&[u8], b:&[u8]) -> bool {
a == b
}
let mut c = Config::new();
c.password(PasswordType::Text("Foo".to_owned(), scrypt_defaults()));
assert!(c.get_derived_key().is_none());
let key = c.derive_key().map_err(|e| panic!("Unexpected error: {:?}", e)).unwrap();
let keyx = c.get_derived_key().unwrap();
assert!(are_eq(&key,&keyx));
c.password(PasswordType::Text("Bar".to_owned(), scrypt_defaults()));
assert!(c.get_derived_key().is_none());
let key2 = c.derive_key().map_err(|e| panic!("Unexpected error: {:?}", e)).unwrap();
let key2x = c.get_derived_key().unwrap();
assert!(are_eq(&key2,&key2x));
assert!(!are_eq(&key,&key2));
}