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.
95 lines
3.3 KiB
95 lines
3.3 KiB
use aes_gcm::{ |
|
aead::{Aead, AeadCore, KeyInit, OsRng}, |
|
Aes256Gcm, Key, Nonce |
|
}; |
|
|
|
use std::io; |
|
|
|
|
|
static PASSWORD_TEST: &str = "MyPasswordStorage"; // will be added with nonce for storing each time |
|
|
|
|
|
pub struct Encoder { |
|
// will be stored with padding 32 bytes |
|
passphrase: String |
|
} |
|
|
|
impl Encoder { |
|
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 |
|
} |
|
|
|
// TODO: error type |
|
pub fn encrypt(&self, plain_text: &String) -> io::Result<String> { |
|
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()) |
|
.map_err(|_| io::Error::new( |
|
io::ErrorKind::Other, |
|
"Failed to encrypt" |
|
))?; |
|
|
|
// 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); |
|
|
|
Ok(hex::encode(encrypted_data)) |
|
|
|
} |
|
|
|
// TODO: review error type |
|
pub fn decrypt(&self, encrypted_data: String) -> io::Result<String> { |
|
let encrypted_data = hex::decode(encrypted_data) |
|
.map_err(|_| io::Error::new( |
|
io::ErrorKind::Other, |
|
"failed to decode hex string into vec" |
|
))?; |
|
|
|
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) |
|
.map_err(|_| io::Error::new( |
|
io::ErrorKind::InvalidData, |
|
"failed to decrypt data" |
|
))?; |
|
|
|
let result = String::from_utf8(plaintext) |
|
.map_err(|_| io::Error::new( |
|
io::ErrorKind::InvalidData, |
|
"failed to convert vector of bytes to string" |
|
))?; |
|
Ok(result) |
|
} |
|
|
|
pub fn test_encoded_passphrase(&self, passphrase_encrypted: String) -> io::Result<bool> { |
|
// TODO: better way to check error |
|
let decrypted = match self.decrypt(passphrase_encrypted) { |
|
Ok(decrypted) => decrypted, |
|
Err(_) => return Ok(false) |
|
}; |
|
Ok(PASSWORD_TEST == decrypted) |
|
} |
|
|
|
pub fn get_encoded_test_passphrase(&self) -> io::Result<String> { |
|
self.encrypt(&PASSWORD_TEST.to_string()) |
|
} |
|
|
|
}
|
|
|