Implement proper key types
Signed-off-by: Lee Smet <lee.smet@hotmail.com>
This commit is contained in:
86
vault/src/key/symmetric.rs
Normal file
86
vault/src/key/symmetric.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
//! An implementation of symmetric keys for ChaCha20Poly1305 encryption.
|
||||
//!
|
||||
//! The ciphertext is authenticated.
|
||||
//! The 12-byte nonce is appended to the generated ciphertext.
|
||||
//! Keys are 32 bytes in size.
|
||||
|
||||
use chacha20poly1305::{ChaCha20Poly1305, KeyInit, Nonce, aead::Aead};
|
||||
|
||||
use crate::error::CryptoError;
|
||||
|
||||
pub struct SymmetricKey([u8; 32]);
|
||||
|
||||
/// Size of a nonce in ChaCha20Poly1305.
|
||||
const NONCE_SIZE: usize = 12;
|
||||
|
||||
impl SymmetricKey {
|
||||
/// Generate a new random SymmetricKey.
|
||||
pub fn new() -> Self {
|
||||
let mut key = [0u8; 32];
|
||||
rand::fill(&mut key);
|
||||
Self(key)
|
||||
}
|
||||
|
||||
/// Create a new key from existing bytes.
|
||||
pub(crate) fn from_bytes(bytes: &[u8]) -> Result<SymmetricKey, CryptoError> {
|
||||
if bytes.len() == 32 {
|
||||
let mut key = [0u8; 32];
|
||||
key.copy_from_slice(bytes);
|
||||
Ok(SymmetricKey(key))
|
||||
} else {
|
||||
Err(CryptoError::InvalidKeySize)
|
||||
}
|
||||
}
|
||||
|
||||
/// View the raw bytes of this key
|
||||
pub(crate) fn as_raw_bytes(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Encrypt a plaintext with the key. A nonce is generated and appended to the end of the
|
||||
/// message.
|
||||
pub fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>, CryptoError> {
|
||||
// Create cipher
|
||||
let cipher = ChaCha20Poly1305::new_from_slice(&self.0)
|
||||
.expect("Key is a fixed 32 byte array so size is always ok");
|
||||
|
||||
// Generate random nonce
|
||||
let mut nonce_bytes = [0u8; NONCE_SIZE];
|
||||
rand::fill(&mut nonce_bytes);
|
||||
let nonce = Nonce::from_slice(&nonce_bytes);
|
||||
|
||||
// Encrypt message
|
||||
let mut ciphertext = cipher
|
||||
.encrypt(nonce, plaintext)
|
||||
.map_err(|_| CryptoError::EncryptionFailed)?;
|
||||
|
||||
// Append nonce to ciphertext
|
||||
ciphertext.extend_from_slice(&nonce_bytes);
|
||||
|
||||
Ok(ciphertext)
|
||||
}
|
||||
|
||||
/// Decrypts a ciphertext with appended nonce.
|
||||
pub fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>, CryptoError> {
|
||||
// Check if ciphertext is long enough to contain a nonce
|
||||
if ciphertext.len() <= NONCE_SIZE {
|
||||
return Err(CryptoError::DecryptionFailed);
|
||||
}
|
||||
|
||||
// Extract nonce from the end of ciphertext
|
||||
let ciphertext_len = ciphertext.len() - NONCE_SIZE;
|
||||
let ciphertext = &ciphertext[0..ciphertext_len];
|
||||
let nonce_bytes = &ciphertext[ciphertext_len..];
|
||||
|
||||
// Create cipher
|
||||
let cipher = ChaCha20Poly1305::new_from_slice(&self.0)
|
||||
.expect("Key is a fixed 32 byte array so size is always ok");
|
||||
|
||||
let nonce = Nonce::from_slice(nonce_bytes);
|
||||
|
||||
// Decrypt message
|
||||
cipher
|
||||
.decrypt(nonce, ciphertext)
|
||||
.map_err(|_| CryptoError::DecryptionFailed)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user