Skip to content

Commit

Permalink
Merge pull request #85 from demarches-simplifiees/can_add_a_key
Browse files Browse the repository at this point in the history
Can add a key to keyring
  • Loading branch information
LeSim authored Mar 2, 2023
2 parents ef6c69c + 5b107c1 commit 83ea369
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 15 deletions.
2 changes: 2 additions & 0 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Usage:
ds_proxy decrypt <input-file> <output-file> [--password-file=<password-file>] [--hash-file=<hash-file>] [--salt=<salt>] [--chunk-size=<chunk-size>] [--keyring-file=<keyring-file>]
ds_proxy proxy [--address=<address>] [--password-file=<password-file>] [--hash-file=<hash-file>] [--salt=<salt>] [--chunk-size=<chunk-size>] [--upstream-url=<upstream-url>] [--max-connections=<max-connections>] [--local-encryption-directory=<local-encryption-directory>] [--noop] [--keyring-file=<keyring-file>]
ds_proxy bootstrap-keyring [--password-file=<password-file>] [--hash-file=<hash-file>] [--salt=<salt>]
ds_proxy add-key [--password-file=<password-file>] [--hash-file=<hash-file>] [--salt=<salt>] [--keyring-file=<keyring-file>]
ds_proxy (-h | --help)
ds_proxy --version
Expand All @@ -34,4 +35,5 @@ pub struct Args {
pub cmd_decrypt: bool,
pub cmd_proxy: bool,
pub cmd_bootstrap_keyring: bool,
pub cmd_add_key: bool,
}
5 changes: 4 additions & 1 deletion src/bin/ds_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ extern crate sodiumoxide;
use docopt::Docopt;
use ds_proxy::args::{Args, USAGE};
use ds_proxy::config::{Config, Config::*};
use ds_proxy::keyring_utils::bootstrap_and_save_keyring;
use ds_proxy::keyring_utils::{add_random_key_to_keyring, bootstrap_and_save_keyring};
use ds_proxy::{file, http};
use log::info;
use std::env;
Expand Down Expand Up @@ -35,6 +35,9 @@ fn main() {
BootstrapKeyring(config) => {
bootstrap_and_save_keyring(&config.keyring_file, config.password, config.salt)
}
AddKeyConfig(config) => {
add_random_key_to_keyring(&config.keyring_file, config.password, config.salt)
}
Http(config) => {
if args.flag_noop {
info!("proxy in dry mode")
Expand Down
16 changes: 16 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub enum Config {
Encrypt(EncryptConfig),
Http(HttpConfig),
BootstrapKeyring(BootstrapKeyring),
AddKeyConfig(AddKeyConfig),
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -52,6 +53,13 @@ pub struct BootstrapKeyring {
pub keyring_file: String,
}

#[derive(Debug, Clone)]
pub struct AddKeyConfig {
pub password: String,
pub salt: String,
pub keyring_file: String,
}

impl Config {
pub fn create_config(args: &args::Args) -> Config {
let password = match &args.flag_password_file {
Expand Down Expand Up @@ -89,6 +97,14 @@ impl Config {
});
}

if args.cmd_add_key {
return Config::AddKeyConfig(AddKeyConfig {
password,
salt,
keyring_file,
});
}

let chunk_size = match &args.flag_chunk_size {
Some(chunk_size) => *chunk_size,
None => match env::var("DS_CHUNK_SIZE") {
Expand Down
71 changes: 57 additions & 14 deletions src/keyring_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,7 @@ use std::collections::HashMap;
use std::convert::TryInto;

pub fn load_keyring(keyring_file: &str, master_password: String, salt: String) -> Keyring {
let mut raw_master_password = [0u8; KEYBYTES];

let typed_salt = Salt::from_slice(salt.as_bytes()).unwrap();

pwhash::derive_key(
&mut raw_master_password,
master_password.as_bytes(),
&typed_salt,
pwhash::OPSLIMIT_INTERACTIVE,
pwhash::MEMLIMIT_INTERACTIVE,
)
.unwrap();

let master_key = secretbox::Key::from_slice(&raw_master_password.clone()).unwrap();
let master_key = build_master_key(master_password, salt);

let hash_map = load_secrets(keyring_file)
.cipher_keyring
Expand All @@ -34,6 +21,29 @@ pub fn load_keyring(keyring_file: &str, master_password: String, salt: String) -
Keyring::new(hash_map)
}

pub fn add_random_key_to_keyring(keyring_file: &str, master_password: String, salt: String) {
let new_key = random_key();
let master_key = build_master_key(master_password, salt);
add_key(keyring_file, &master_key, new_key);
}

fn add_key(keyring_file: &str, master_key: &secretbox::Key, key: [u8; 32]) {
let new_base64_cipher = base64_cipher(master_key, key);

let mut secrets = load_secrets(keyring_file);
secrets
.cipher_keyring
.insert(next_id(&secrets), new_base64_cipher);

save_secrets(keyring_file, &secrets)
}

fn random_key() -> [u8; 32] {
sodiumoxide::randombytes::randombytes(KEYBYTES)
.try_into()
.unwrap()
}

fn to_u64(id: &str) -> u64 {
id.parse::<u64>().unwrap()
}
Expand Down Expand Up @@ -62,6 +72,39 @@ fn decrypt(master_key: &secretbox::Key, nonce_cipher: Vec<u8>) -> [u8; KEYBYTES]
.unwrap()
}

fn build_master_key(master_password: String, salt: String) -> secretbox::Key {
let mut key = [0u8; KEYBYTES];

let typed_salt = Salt::from_slice(salt.as_bytes()).unwrap();

pwhash::derive_key(
&mut key,
master_password.as_bytes(),
&typed_salt,
pwhash::OPSLIMIT_INTERACTIVE,
pwhash::MEMLIMIT_INTERACTIVE,
)
.unwrap();

secretbox::Key::from_slice(&key).unwrap()
}

fn next_id(secrets: &Secrets) -> String {
if let Some(max) = last_id(secrets) {
(max + 1).to_string()
} else {
"0".to_string()
}
}

fn last_id(secrets: &Secrets) -> Option<u64> {
secrets
.cipher_keyring
.keys()
.max()
.map(|x| x.parse::<u64>().unwrap())
}

pub fn bootstrap_and_save_keyring(keyring_file: &str, master_password: String, salt: String) {
let mut key = [0u8; KEYBYTES];

Expand Down

0 comments on commit 83ea369

Please sign in to comment.