2 Commits

Author SHA1 Message Date
c260e37e78 cryptography notes 2023-05-19 10:04:48 -07:00
7501253970 add separate binary for Windows CLI 2023-05-15 13:09:26 -07:00
10 changed files with 143 additions and 52 deletions

9
doc/cryptography.md Normal file
View File

@ -0,0 +1,9 @@
My original plan was to use [libsodium](https://doc.libsodium.org/) to handle encryption. However, the Rust bindings for libsodium are no longer actively maintained, which left me uncomfortable with using it. Instead, I switched to the [RustCrypto](https://github.com/RustCrypto) implementations of the same (or nearly the same) cryptographic primitives provided by libsodium.
Creddy makes use of two cryptographic primitives: A key-derivation function, which is currently `argon2id`, and a symmetric encryption algorithm, currently `XChaCha20Poly1305`.
* I chose `argon2id` because it's what libsodium uses, and because its difficulty parameters admit of very granular tuning.
* I chose `XChaCha20Poly1305` because it's _almost_ what libsodium uses - libsodium uses `XSalsa20Poly1305`, and it's my undersatnding that `XChaCha20Poly1305` is an evolution of the former. In both cases I use the eXtended variants, which make use of longer (24-byte) nonces than the non-X variants. This appealed to me because I wanted to be able to randomly generate a nonce every time I needed one, and I have seen [recommendations](https://latacora.micro.blog/2018/04/03/cryptographic-right-answers.html) that the 12-byte nonces used by the non-X variants are _juuust_ a touch small for that to be truly worry-free. The RustCrypto implementation of `XChaCha20Poly1305` has also been subject to a security audit, which is nice.
I tuned the `argon2id` parameters so that key-derivation would take ~800ms on my Ryzen 1600X. This is probably overkill, but I don't intend for key-derivation to be a frequent occurrence - no more than once a day, under normal circumstances. Taking in the neighborhood of 1 second seemed about the longest I could reasonably go.
**DISCLAIMER**: I am not a professional cryptographer, merely an interested amateur. While I've tried to be as careful as possible with selecting and making use of the cryptographic building blocks I've chosen here, there is always the possibility that I've screwed something up. If anyone would like to sponsor an _actual_ security review of Creddy by people who _actually_ know what they're doing instead of just what they've read on the internet, please let me know.

View File

@ -1,6 +1,6 @@
{
"name": "creddy",
"version": "0.2.1",
"version": "0.2.2",
"scripts": {
"dev": "vite",
"build": "vite build",

60
src-tauri/Cargo.lock generated
View File

@ -68,36 +68,6 @@ version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
[[package]]
name = "app"
version = "0.2.1"
dependencies = [
"argon2",
"auto-launch",
"aws-config",
"aws-sdk-sts",
"aws-smithy-types",
"aws-types",
"chacha20poly1305",
"clap",
"dirs 5.0.1",
"is-terminal",
"netstat2",
"once_cell",
"serde",
"serde_json",
"sodiumoxide",
"sqlx",
"strum",
"strum_macros",
"sysinfo",
"tauri",
"tauri-build",
"tauri-plugin-single-instance",
"thiserror",
"tokio",
]
[[package]]
name = "argon2"
version = "0.5.0"
@ -975,6 +945,36 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "creddy"
version = "0.2.2"
dependencies = [
"argon2",
"auto-launch",
"aws-config",
"aws-sdk-sts",
"aws-smithy-types",
"aws-types",
"chacha20poly1305",
"clap",
"dirs 5.0.1",
"is-terminal",
"netstat2",
"once_cell",
"serde",
"serde_json",
"sodiumoxide",
"sqlx",
"strum",
"strum_macros",
"sysinfo",
"tauri",
"tauri-build",
"tauri-plugin-single-instance",
"thiserror",
"tokio",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.8"

View File

@ -1,14 +1,22 @@
[package]
name = "app"
version = "0.2.1"
description = "A Tauri App"
authors = ["you"]
name = "creddy"
version = "0.2.2"
description = "A friendly AWS credentials manager"
authors = ["Joseph Montanaro"]
license = ""
repository = ""
default-run = "app"
default-run = "creddy"
edition = "2021"
rust-version = "1.57"
[[bin]]
name = "creddy_cli"
path = "src/bin/creddy_cli.rs"
[[bin]]
name = "creddy"
path = "src/main.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]

22
src-tauri/conf/cli.wxs Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<DirectoryRef Id="INSTALLDIR">
<!-- Create a subdirectory for the console binary so that we can add it to PATH -->
<Directory Id="BinDir" Name="bin">
<Component Id="CliBinary" Guid="b6358c8e-504f-41fd-b14b-38af821dcd04">
<!-- Same name as the main executable, so that it can be invoked as just "creddy" -->
<File Id="Bin_Cli" Source="..\..\creddy_cli.exe" Name="creddy.exe" KeyPath="yes"/>
</Component>
</Directory>
</DirectoryRef>
<DirectoryRef Id="TARGETDIR">
<Component Id="AddToPath" Guid="b5fdaf7e-94f2-4aad-9144-aa3a8edfa675">
<Environment Id="CreddyInstallDir" Action="set" Name="PATH" Part="last" Permanent="no" Value="[BinDir]" />
</Component>
</DirectoryRef>
</Fragment>
</Wix>

View File

@ -0,0 +1,45 @@
// Windows isn't really amenable to having a single executable work as both a CLI and GUI app,
// so we just have a second binary for CLI usage
use creddy::{
cli,
errors::CliError,
};
use std::{
env,
process::{self, Command},
};
fn main() {
let args = cli::parser().get_matches();
if let Some(true) = args.get_one::<bool>("help") {
cli::parser().print_help().unwrap(); // if we can't print help we can't print an error
process::exit(0);
}
let res = match args.subcommand() {
None | Some(("run", _)) => launch_gui(),
Some(("show", m)) => cli::show(m),
Some(("exec", m)) => cli::exec(m),
_ => unreachable!(),
};
if let Err(e) = res {
eprintln!("Error: {e}");
}
}
fn launch_gui() -> Result<(), CliError> {
let mut path = env::current_exe()?;
path.pop(); // bin dir
// binaries are colocated in dev, but not in production
#[cfg(not(debug_assertions))]
path.pop(); // install dir
path.push("creddy.exe"); // exe in main install dir (aka gui exe)
Command::new(path).spawn()?;
Ok(())
}

View File

@ -228,6 +228,8 @@ pub enum CliError {
Request(#[from] RequestError),
#[error(transparent)]
Exec(#[from] ExecError),
#[error(transparent)]
Io(#[from] std::io::Error),
}

10
src-tauri/src/lib.rs Normal file
View File

@ -0,0 +1,10 @@
pub mod app;
pub mod cli;
mod config;
mod credentials;
pub mod errors;
mod clientinfo;
mod ipc;
mod state;
mod server;
mod tray;

View File

@ -3,20 +3,11 @@
windows_subsystem = "windows"
)]
mod app;
mod cli;
mod config;
mod credentials;
mod errors;
mod clientinfo;
mod ipc;
mod state;
mod server;
mod tray;
use crate::errors::ErrorPopup;
use creddy::{
app,
cli,
errors::ErrorPopup,
};
fn main() {

View File

@ -8,7 +8,7 @@
},
"package": {
"productName": "creddy",
"version": "0.2.1"
"version": "0.2.2"
},
"tauri": {
"allowlist": {
@ -44,7 +44,11 @@
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": ""
"timestampUrl": "",
"wix": {
"fragmentPaths": ["conf/cli.wxs"],
"componentRefs": ["CliBinary", "AddToPath"]
}
}
},
"security": {