switch crypto implementation and add spinner

This commit is contained in:
2023-05-08 22:11:58 -07:00
parent 663bbfa2f3
commit d650909ac7
9 changed files with 181 additions and 26 deletions

View File

@ -1,7 +1,7 @@
use std::fmt::{self, Formatter};
use std::time::{SystemTime, UNIX_EPOCH};
use aws_smithy_types::date_time::{DateTime, Format};
use aws_smithy_types::date_time::{DateTime, Format};
use argon2::{
Argon2,
Algorithm,
@ -15,7 +15,6 @@ use chacha20poly1305::{
aead::{
Aead,
AeadCore,
Key,
KeyInit,
Error as AeadError,
generic_array::GenericArray,
@ -54,18 +53,17 @@ impl Session {
None => {return Ok(Session::Empty);}
};
let salt_buf: [u8; 32] = row.salt
.try_into()
.map_err(|_e| SetupError::InvalidRecord)?;
let nonce_buf: [u8; 24] = row.nonce
let salt: [u8; 32] = row.salt
.try_into()
.map_err(|_e| SetupError::InvalidRecord)?;
let nonce = XNonce::from_exact_iter(row.nonce.into_iter())
.ok_or(SetupError::InvalidRecord)?;
let creds = LockedCredentials {
access_key_id: row.access_key_id,
secret_key_enc: row.secret_key_enc,
salt: Salt(salt_buf),
nonce: Nonce(nonce_buf),
salt,
nonce,
};
Ok(Session::Locked(creds))
}
@ -102,8 +100,8 @@ impl LockedCredentials {
)
.bind(&self.access_key_id)
.bind(&self.secret_key_enc)
.bind(&self.salt.0[0..])
.bind(&self.nonce.0[0..])
.bind(&self.salt[..])
.bind(&self.nonce[..])
.execute(pool)
.await?;
@ -111,9 +109,10 @@ impl LockedCredentials {
}
pub fn decrypt(&self, passphrase: &str) -> Result<BaseCredentials, UnlockError> {
let crypto = Crypto::new(passphrase, &self.salt);
let crypto = Crypto::new(passphrase, &self.salt)
.map_err(|e| CryptoError::Argon2(e))?;
let decrypted = crypto.decrypt(&self.nonce, &self.secret_key_enc)
.map_err(|_| UnlockError::BadPassphrase)?;
.map_err(|e| CryptoError::Aead(e))?;
let secret_access_key = String::from_utf8(decrypted)
.map_err(|_| UnlockError::InvalidUtf8)?;
@ -134,10 +133,10 @@ pub struct BaseCredentials {
}
impl BaseCredentials {
pub fn encrypt(&self, passphrase: &str) -> Result<CryptoError, LockedCredentials> {
pub fn encrypt(&self, passphrase: &str) -> Result<LockedCredentials, CryptoError> {
let salt = Crypto::salt();
let crypto = Crypto::new(passphrase, &salt)?;
let (nonce, secret_key_enc) = crypto.encrypt(self.secret_access_key.as_bytes());
let (nonce, secret_key_enc) = crypto.encrypt(self.secret_access_key.as_bytes())?;
let locked = LockedCredentials {
access_key_id: self.access_key_id.clone(),
@ -271,11 +270,24 @@ impl Crypto {
/// a key on my (somewhat older) CPU. This is probably overkill, but
/// given that it should only have to happen ~once a day for most
/// usage, it should be acceptable.
#[cfg(not(debug_assertions))]
const MEM_COST: u32 = 128 * 1024;
#[cfg(not(debug_assertions))]
const TIME_COST: u32 = 8;
/// But since this takes a million years in an unoptimized build,
/// we turn it way down in debug builds.
#[cfg(debug_assertions)]
const MEM_COST: u32 = 48 * 1024;
#[cfg(debug_assertions)]
const TIME_COST: u32 = 1;
fn new(passphrase: &str, salt: &[u8]) -> argon2::Result<Crypto> {
let params = ParamsBuilder::new()
.m_cost(128 * 1024)
.m_cost(Self::MEM_COST)
.p_cost(1)
.t_cost(8)
.t_cost(Self::TIME_COST)
.build()
.unwrap(); // only errors if the given params are invalid

View File

@ -164,8 +164,8 @@ pub enum UnlockError {
NotLocked,
#[error("No saved credentials were found")]
NoCredentials,
#[error("Invalid passphrase")]
BadPassphrase,
#[error(transparent)]
Crypto(#[from] CryptoError),
#[error("Data was found to be corrupt after decryption")]
InvalidUtf8, // Somehow we got invalid utf-8 even though decryption succeeded
#[error("Database error: {0}")]
@ -175,6 +175,15 @@ pub enum UnlockError {
}
#[derive(Debug, ThisError, AsRefStr)]
pub enum CryptoError {
#[error(transparent)]
Argon2(#[from] argon2::Error),
#[error("Invalid passphrase")] // I think this is the only way decryption fails
Aead(#[from] chacha20poly1305::aead::Error),
}
// Errors encountered while trying to figure out who's on the other end of a request
#[derive(Debug, ThisError, AsRefStr)]
pub enum ClientInfoError {

View File

@ -48,7 +48,7 @@ impl AppState {
}
pub async fn new_creds(&self, base_creds: BaseCredentials, passphrase: &str) -> Result<(), UnlockError> {
let locked = base_creds.encrypt(passphrase);
let locked = base_creds.encrypt(passphrase)?;
// do this first so that if it fails we don't save bad credentials
self.new_session(base_creds).await?;
locked.save(&self.pool).await?;