diff --git a/.github/lucid.yml b/.github/lucid.yml index f05d775..cee14ae 100644 --- a/.github/lucid.yml +++ b/.github/lucid.yml @@ -3,7 +3,7 @@ general: bind_address: 127.0.0.1 port: 7020 port_ssl: 7021 - use_ssl: true + use_ssl: false ssl_certificate: "tls/cert.pem" ssl_certificate_key: "tls/key.rsa" show_banner: false @@ -15,8 +15,9 @@ persistence: enabled: false location: "" encryption: - enabled: false - private_key: "" + enabled: true + private_key: "123456789012345678901234123456789012345678901234" + iv: "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" webui: enabled: true store: diff --git a/Cargo.lock b/Cargo.lock index 9baf7f7..4dff9fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,6 +93,15 @@ dependencies = [ "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "block-modes" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "block-padding" version = "0.1.4" @@ -381,21 +390,9 @@ dependencies = [ ] [[package]] -name = "hex-literal" -version = "0.2.1" +name = "hex" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hex-literal-impl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hex-literal-impl" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "http" @@ -565,12 +562,13 @@ name = "lucid" version = "0.1.2" dependencies = [ "app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "chashmap 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "fern 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonwebtoken 7.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -904,16 +902,6 @@ name = "ppv-lite86" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "proc-macro-hack" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "proc-macro2" version = "1.0.6" @@ -1779,6 +1767,7 @@ dependencies = [ "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" +"checksum block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" "checksum buf_redux 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" "checksum bumpalo 3.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb8038c1ddc0a5f73787b130f4cc75151e96ed33e417fde765eb5a81e3532f4" @@ -1816,8 +1805,7 @@ dependencies = [ "checksum headers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c9836ffd533e1fb207cfdb2e357079addbd17ef5c68eea5afe2eece40555b905" "checksum headers-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" -"checksum hex-literal-impl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9d4c5c844e2fee0bf673d54c2c177f1713b3d2af2ff6e666b49cb7572e6cf42d" +"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "d7e06e336150b178206af098a055e3621e8336027e2b4d126bda0bc64824baaf" "checksum http 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b708cc7f06493459026f53b9a61a7a121a5d1ec6238dee58ea4941132b30156b" "checksum http-body 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" @@ -1874,7 +1862,6 @@ dependencies = [ "checksum pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae" "checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" diff --git a/Cargo.toml b/Cargo.toml index 44c3860..ffbd452 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,9 +37,10 @@ tree_magic = "0.2.1" snafu = "0.6.2" bytes = "0.5.3" fern = "0.5.9" -hex-literal = "0.2.1" +hex = "0.3.1" clap = { version = "2.33.0", features = ["yaml"] } warp = { version = "0.2.0", features = ["tls"] } log = { version = "0.4.8", features = ["serde"] } tokio = { version = "0.2.9", features = ["full"] } -serpent = { git = "https://github.com/RustCrypto/block-ciphers" } \ No newline at end of file +serpent = { git = "https://github.com/RustCrypto/block-ciphers" } +block-modes = "0.3.3" diff --git a/src/configuration.rs b/src/configuration.rs index 4de5ffb..5cf127e 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -49,6 +49,7 @@ impl Default for Configuration { encryption: Encryption { enabled: false, private_key: String::new(), + iv: String::new(), }, webui: WebUI { enabled: false }, store: Store { max_limit: 7340032 }, @@ -89,6 +90,7 @@ pub struct Persistence { pub struct Encryption { pub enabled: bool, pub private_key: String, + pub iv: String, } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/src/kvstore.rs b/src/kvstore.rs index 094a46d..d57f077 100644 --- a/src/kvstore.rs +++ b/src/kvstore.rs @@ -1,6 +1,12 @@ +use block_modes::block_padding::ZeroPadding; +use block_modes::{BlockMode, Cbc}; use chashmap::CHashMap; use chrono::{DateTime, Utc}; +use serpent::Serpent; + +type SerpentCbc = Cbc; + #[derive(Debug, Clone)] pub struct KvElement { pub data: Vec, @@ -9,34 +15,53 @@ pub struct KvElement { pub updated_at: DateTime, pub expire_at: DateTime, pub update_count: i32, - pub locked: bool + pub locked: bool, } pub struct KvStore { - container: CHashMap + container: CHashMap, + cipher: Option, +} + +pub struct Cipher { + priv_key: [u8; 24], + iv: [u8; 16], } -impl KvStore -{ - pub fn new() -> KvStore - { +impl KvStore { + pub fn new(cipher: Option<[&str; 2]>) -> KvStore { // TODO: prepare looped persistence - KvStore { - container: CHashMap::new() + let mut kv = KvStore { + container: CHashMap::new(), + cipher: None, + }; + + if let Some(c) = cipher { + let (mut priv_key, mut iv) = ([0u8; 24], [0u8; 16]); + priv_key[..24].copy_from_slice(&hex::decode(c[0]).unwrap()); + iv[..16].copy_from_slice(&hex::decode(c[1]).unwrap()); + kv.cipher = Some(Cipher { priv_key, iv }); } + + kv } - pub fn set(&self, key: String, value: Vec) -> Option { + pub fn set(&self, key: String, mut value: Vec) -> Option { // TODO: prepare iterative persistence let mime_type = tree_magic::from_u8(value.as_ref()); + + if let Some(c) = &self.cipher { + let cipher = SerpentCbc::new_var(&c.priv_key, &c.iv).unwrap(); + value = cipher.encrypt_vec(&value); + } match &mut self.container.get_mut(&key) { Some(kv_element) => { kv_element.data = value; kv_element.mime_type = mime_type; kv_element.updated_at = Utc::now(); - kv_element.update_count = kv_element.update_count + 1; + kv_element.update_count = kv_element.update_count + 1; Some(kv_element.to_owned()) - }, + } None => { let kv_element = KvElement { data: value, @@ -54,8 +79,16 @@ impl KvStore pub fn get(&self, key: String) -> Option { match self.container.get(&key) { - Some(value) => Some(value.clone()), - None => None + Some(value) => { + let mut cloned_value = value.clone(); + + if let Some(c) = &self.cipher { + let cipher = SerpentCbc::new_var(&c.priv_key, &c.iv).unwrap(); + cloned_value.data = cipher.decrypt_vec(&value.data).unwrap(); + } + Some(cloned_value) + } + None => None, } } @@ -64,8 +97,8 @@ impl KvStore Some(kv_element) => { kv_element.locked = to_lock; true - }, - None => false + } + None => false, } } @@ -74,4 +107,4 @@ impl KvStore pub fn drop(&self, key: String) { self.container.remove(&key); } -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index 5060ca5..90c5100 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,10 @@ extern crate serde_derive; #[macro_use] extern crate log; +extern crate block_modes; +extern crate hex; +extern crate serpent; + mod configuration; mod kvstore; mod lucid; @@ -72,7 +76,11 @@ async fn main() -> Result<(), Error> { .expect("Couldn't start logger"); log::set_max_level(LevelFilter::Debug); - let long_version = format!("{}\n{}\n\nYou can send a tips here: 3BxEYn4RZ3iYETcFpN7nA6VqCY4Hz1tSUK", crate_version!(), CREDITS); + let long_version = format!( + "{}\n{}\n\nYou can send a tips here: 3BxEYn4RZ3iYETcFpN7nA6VqCY4Hz1tSUK", + crate_version!(), + CREDITS + ); let cli_yaml = load_yaml!("cli.yml"); let app = App::from_yaml(&cli_yaml) @@ -145,7 +153,11 @@ async fn main() -> Result<(), Error> { } if let Some(_) = matches.subcommand_matches("settings") { if config_path.exists() { - println!("Configuration location: {}\n\n{}", &config_path.to_str().unwrap(), fs::read_to_string(&config_path).context(OpenConfigFile)?); + println!( + "Configuration location: {}\n\n{}", + &config_path.to_str().unwrap(), + fs::read_to_string(&config_path).context(OpenConfigFile)? + ); } else { return Err(Error::ConfigurationNotFound); } diff --git a/src/server.rs b/src/server.rs index ff01250..0eb0a49 100644 --- a/src/server.rs +++ b/src/server.rs @@ -30,7 +30,16 @@ impl Server { } pub async fn run(&self) { - let store = Arc::new(KvStore::new()); + let configuration = self.configuration.read().unwrap(); + + let mut encryption_key = None; + if configuration.encryption.enabled { + encryption_key = Some([ + configuration.encryption.private_key.as_str(), + configuration.encryption.iv.as_str(), + ]); + } + let store = Arc::new(KvStore::new(encryption_key)); let store = warp::any().map(move || store.clone()); let config = self.configuration.clone(); @@ -43,8 +52,6 @@ impl Server { let webui_enabled = config.clone().and_then(check_webui).untuple_one(); - let configuration = self.configuration.read().unwrap(); - let api_kv_key_path = path!("api" / "kv" / String).and(path::end()); let api_kv_key = auth.and( warp::get()