A small tool for storing passwords locally with git sync
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

96 lines
3.3 KiB

3 months ago
use aes_gcm::{
aead::{Aead, AeadCore, KeyInit, OsRng},
Aes256Gcm, Key, Nonce
};
3 months ago
use std::io;
3 months ago
static PASSWORD_TEST: &str = "MyPasswordStorage"; // will be added with nonce for storing each time
3 months ago
pub struct Encoder {
3 months ago
// will be stored with padding 32 bytes
3 months ago
passphrase: String
}
impl Encoder {
3 months ago
pub fn from(passphrase: &String) -> Encoder {
// TODO: throw error if password longer that 32 bytes
let padded_passphrase = Encoder::get_passhrase_with_padding(passphrase);
Encoder { passphrase: padded_passphrase }
}
fn get_passhrase_with_padding(passphrase: &String) -> String {
let mut result = passphrase.clone();
while result.len() < 32 {
// use '-' for padding, can be anything else
result.push('-');
}
result
3 months ago
}
3 months ago
// TODO: error type
3 months ago
pub fn encrypt(&self, plain_text: &String) -> io::Result<String> {
3 months ago
let key = Key::<Aes256Gcm>::from_slice(self.passphrase.as_bytes());
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
let cipher = Aes256Gcm::new(key);
// TODO: mar error inted of expect
let ciphered_data = cipher.encrypt(&nonce, plain_text.as_bytes())
3 months ago
.map_err(|_| io::Error::new(
io::ErrorKind::Other,
"Failed to encrypt"
))?;
3 months ago
// combining nonce and encrypted data together
// for storage purpose
let mut encrypted_data: Vec<u8> = nonce.to_vec();
encrypted_data.extend_from_slice(&ciphered_data);
3 months ago
Ok(hex::encode(encrypted_data))
3 months ago
3 months ago
}
// TODO: review error type
3 months ago
pub fn decrypt(&self, encrypted_data: String) -> io::Result<String> {
3 months ago
let encrypted_data = hex::decode(encrypted_data)
3 months ago
.map_err(|_| io::Error::new(
io::ErrorKind::Other,
"failed to decode hex string into vec"
))?;
3 months ago
let key = Key::<Aes256Gcm>::from_slice(self.passphrase.as_bytes());
let (nonce_arr, ciphered_data) = encrypted_data.split_at(12);
let nonce = Nonce::from_slice(nonce_arr);
let cipher = Aes256Gcm::new(key);
let plaintext = cipher.decrypt(nonce, ciphered_data)
3 months ago
.map_err(|_| io::Error::new(
io::ErrorKind::InvalidData,
"failed to decrypt data"
))?;
3 months ago
let result = String::from_utf8(plaintext)
3 months ago
.map_err(|_| io::Error::new(
io::ErrorKind::InvalidData,
"failed to convert vector of bytes to string"
))?;
3 months ago
Ok(result)
3 months ago
}
3 months ago
pub fn test_encoded_passphrase(&self, passphrase_encrypted: String) -> io::Result<bool> {
3 months ago
// TODO: better way to check error
let decrypted = match self.decrypt(passphrase_encrypted) {
Ok(decrypted) => decrypted,
Err(_) => return Ok(false)
};
3 months ago
Ok(PASSWORD_TEST == decrypted)
3 months ago
}
3 months ago
pub fn get_encoded_test_passphrase(&self) -> io::Result<String> {
3 months ago
self.encrypt(&PASSWORD_TEST.to_string())
3 months ago
}
}