switch crypto implementation and add spinner
This commit is contained in:
		@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -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?;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user