crypt-config 0.2.2

A crypt module that encrypt/decrypt json data based on the configuration. This might be used as a layer before saving data in Mongo DB or after fetching the data from the DB in order to decrypt them.
Documentation
extern crate base64;
extern crate serde;
extern crate serde_json;

use std::collections::HashMap;

use serde::{Deserialize, Serialize};

use crate::cipher::aes::{CBCCipher, CFB1Cipher, ECBCipher};
use crate::cipher::{generate_salt, ICipher};
use crate::error::{CryptError, CryptResult};

#[derive(Serialize, Deserialize)]
pub struct CipherConfig {
  algorithm: String,
  secret:    Vec<u8>
}

#[allow(dead_code)]
pub struct CipherData {
  configurations: HashMap<String, Box<CipherConfig>>,
  latest_version: String
}

impl CipherConfig {
  #[allow(dead_code)]
  pub fn new(algorithm: String, secret: Vec<u8>) -> CipherConfig {
    CipherConfig { algorithm: algorithm, secret: secret }
  }
}

impl CipherData {
  #[allow(dead_code)]
  pub fn new() -> CipherData {
    CipherData { configurations: HashMap::new(), latest_version: "0".to_string() }
  }

  pub fn contains_configuration(&self, version: &str) -> bool {
    self.configurations.contains_key(version)
  }

  pub fn insert_configuration(&mut self, version: &str, cfg: Box<CipherConfig>) {
    self.configurations.insert(version.to_string(), cfg);
    self.update_version(version);
  }

  pub fn get_latest_version(&self) -> &str {
    self.latest_version.as_str()
  }

  pub fn get_config<'a>(&'a self, version: &str) -> Option<&'a Box<CipherConfig>> {
    self.configurations.get(version)
  }

  fn update_version(&mut self, version: &str) {
    if self.latest_version.as_str() < version {
      self.latest_version = version.to_string()
    }
  }
}

#[allow(dead_code)]
pub fn generate_cipher_from_config(cfg: &CipherConfig) -> CryptResult<Box<dyn ICipher>> {
  let salt = generate_salt();

  match cfg.algorithm.as_ref() {
    "aes_cbc" => Ok(Box::new(CBCCipher::new(&cfg.secret, &salt))),
    "aes_cfb1" => Ok(Box::new(CFB1Cipher::new(&cfg.secret, &salt))),
    "aes_ecb" => Ok(Box::new(ECBCipher::new(&cfg.secret, &salt))),
    _ => Err(CryptError::CipherNotFound(cfg.algorithm.clone()))
  }
}

#[cfg(test)]
mod tests {
  use super::generate_cipher_from_config;
  use super::CipherConfig;
  #[test]
  fn aes_cbc_algorithm() {
    let secret = [11u8, 16].to_vec();
    let cfg = CipherConfig { algorithm: "aes_cbc".to_string(), secret: secret };

    let cipher = generate_cipher_from_config(&cfg).unwrap();
    let data = "very secured data";
    let crypted = cipher.encrypt(data).unwrap();

    assert_eq!(data, cipher.decrypt(&crypted).unwrap());
  }
  #[test]
  fn aes_cfb1_algorithm() {
    let secret = [11u8, 16].to_vec();
    let cfg = CipherConfig { algorithm: "aes_cfb1".to_string(), secret: secret };

    let cipher = generate_cipher_from_config(&cfg).unwrap();
    let data = "very secured data";
    let crypted = cipher.encrypt(data).unwrap();

    assert_eq!(data, cipher.decrypt(&crypted).unwrap());
  }
  #[test]
  fn aes_ecb_algorithm() {
    let secret = [11u8, 16].to_vec();
    let cfg = CipherConfig { algorithm: "aes_ecb".to_string(), secret: secret };

    let cipher = generate_cipher_from_config(&cfg).unwrap();
    let data = "very secured data";
    let crypted = cipher.encrypt(data).unwrap();

    assert_eq!(data, cipher.decrypt(&crypted).unwrap());
  }
  #[test]
  fn unknown_algorithm() {
    let secret = [11u8, 16].to_vec();
    let cfg = CipherConfig { algorithm: "unknown".to_string(), secret: secret };

    assert!(generate_cipher_from_config(&cfg).is_err());
  }
}