Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 37 additions & 38 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ utoipa-swagger-ui = { version = "9", features = ["axum"] }
# aead::OsRng convenience API used in orch8-types/src/encryption.rs. No
# advisory forces the move, so we don't take on a crypto-code migration for a
# version-number bump alone. Revisit together, deliberately, if ever needed.
aes-gcm = "0.10"
aes-gcm = "0.11"
base64 = "0.23"

# HTTP client
Expand Down
53 changes: 29 additions & 24 deletions orch8-types/src/encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};

use aes_gcm::aead::{Aead, KeyInit, OsRng, Payload};
use aes_gcm::{AeadCore, Aes256Gcm, Nonce};
use aes_gcm::Aes256Gcm;
use aes_gcm::aead::{Aead, Generate, KeyInit, Nonce, Payload};
use base64::Engine;
use base64::engine::general_purpose::STANDARD as B64;
use zeroize::Zeroize;
Expand Down Expand Up @@ -89,8 +89,8 @@ impl FieldEncryptor {
key_bytes.zeroize();
return Err(EncryptionError::InvalidKeyLength(len));
}
let key = aes_gcm::Key::<Aes256Gcm>::from_slice(&key_bytes);
let cipher = Aes256Gcm::new(key);
let cipher = Aes256Gcm::new_from_slice(&key_bytes)
.map_err(|_| EncryptionError::InvalidKeyLength(len))?;
key_bytes.zeroize();
Ok(Self {
cipher,
Expand All @@ -104,9 +104,8 @@ impl FieldEncryptor {
/// Create an encryptor from raw 32 bytes.
#[must_use]
pub fn from_bytes(key: &[u8; 32]) -> Self {
let key = aes_gcm::Key::<Aes256Gcm>::from_slice(key);
Self {
cipher: Aes256Gcm::new(key),
cipher: Aes256Gcm::new(key.into()),
old_cipher: None,
encrypt_count: Arc::new(AtomicU64::new(0)),
budget_warned: Arc::new(AtomicBool::new(false)),
Expand Down Expand Up @@ -165,8 +164,10 @@ impl FieldEncryptor {
key_bytes.zeroize();
return Err(EncryptionError::InvalidKeyLength(len));
}
let key = aes_gcm::Key::<Aes256Gcm>::from_slice(&key_bytes);
self.old_cipher = Some(Aes256Gcm::new(key));
self.old_cipher = Some(
Aes256Gcm::new_from_slice(&key_bytes)
.map_err(|_| EncryptionError::InvalidKeyLength(len))?,
);
key_bytes.zeroize();
Ok(self)
}
Expand All @@ -177,7 +178,7 @@ impl FieldEncryptor {
value: &serde_json::Value,
) -> Result<serde_json::Value, EncryptionError> {
let plaintext = serde_json::to_vec(value)?;
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
let nonce = Nonce::<Aes256Gcm>::generate();
let ciphertext = self
.cipher
.encrypt(&nonce, plaintext.as_slice())
Expand Down Expand Up @@ -222,18 +223,19 @@ impl FieldEncryptor {
return Err(EncryptionError::InvalidCiphertext);
}
let (nonce_bytes, ciphertext) = payload.split_at(12);
let nonce = Nonce::from_slice(nonce_bytes);
let nonce = Nonce::<Aes256Gcm>::try_from(nonce_bytes)
.map_err(|_| EncryptionError::InvalidCiphertext)?;

// Try primary key first.
if let Ok(plaintext) = self.cipher.decrypt(nonce, ciphertext) {
if let Ok(plaintext) = self.cipher.decrypt(&nonce, ciphertext) {
let value = serde_json::from_slice(&plaintext)?;
return Ok(value);
}

// Fall back to old key if present.
if let Some(ref old) = self.old_cipher {
let plaintext = old
.decrypt(nonce, ciphertext)
.decrypt(&nonce, ciphertext)
.map_err(|_| EncryptionError::DecryptFailed)?;
let value = serde_json::from_slice(&plaintext)?;
return Ok(value);
Expand Down Expand Up @@ -277,7 +279,7 @@ impl FieldEncryptor {
aad: &[u8],
) -> Result<serde_json::Value, EncryptionError> {
let plaintext = serde_json::to_vec(value)?;
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
let nonce = Nonce::<Aes256Gcm>::generate();
let ciphertext = self
.cipher
.encrypt(
Expand Down Expand Up @@ -323,10 +325,11 @@ impl FieldEncryptor {
return Err(EncryptionError::InvalidCiphertext);
}
let (nonce_bytes, ciphertext) = payload.split_at(12);
let nonce = Nonce::from_slice(nonce_bytes);
let nonce = Nonce::<Aes256Gcm>::try_from(nonce_bytes)
.map_err(|_| EncryptionError::InvalidCiphertext)?;

if let Ok(plaintext) = self.cipher.decrypt(
nonce,
&nonce,
Payload {
msg: ciphertext,
aad,
Expand All @@ -337,7 +340,7 @@ impl FieldEncryptor {
if let Some(ref old) = self.old_cipher {
let plaintext = old
.decrypt(
nonce,
&nonce,
Payload {
msg: ciphertext,
aad,
Expand All @@ -361,7 +364,7 @@ impl FieldEncryptor {
/// # Errors
/// Returns [`EncryptionError::EncryptFailed`] if the AEAD seal fails.
pub fn encrypt_bytes(&self, plaintext: &[u8]) -> Result<Vec<u8>, EncryptionError> {
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
let nonce = Nonce::<Aes256Gcm>::generate();
let ciphertext = self
.cipher
.encrypt(&nonce, plaintext)
Expand All @@ -381,7 +384,7 @@ impl FieldEncryptor {
plaintext: &[u8],
aad: &[u8],
) -> Result<Vec<u8>, EncryptionError> {
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
let nonce = Nonce::<Aes256Gcm>::generate();
let ciphertext = self
.cipher
.encrypt(
Expand Down Expand Up @@ -410,13 +413,14 @@ impl FieldEncryptor {
return Err(EncryptionError::InvalidCiphertext);
}
let (nonce_bytes, ciphertext) = sealed.split_at(12);
let nonce = Nonce::from_slice(nonce_bytes);
if let Ok(plain) = self.cipher.decrypt(nonce, ciphertext) {
let nonce = Nonce::<Aes256Gcm>::try_from(nonce_bytes)
.map_err(|_| EncryptionError::InvalidCiphertext)?;
if let Ok(plain) = self.cipher.decrypt(&nonce, ciphertext) {
return Ok(plain);
}
if let Some(ref old) = self.old_cipher {
return old
.decrypt(nonce, ciphertext)
.decrypt(&nonce, ciphertext)
.map_err(|_| EncryptionError::DecryptFailed);
}
Err(EncryptionError::DecryptFailed)
Expand All @@ -433,18 +437,19 @@ impl FieldEncryptor {
return Err(EncryptionError::InvalidCiphertext);
}
let (nonce_bytes, ciphertext) = sealed.split_at(12);
let nonce = Nonce::from_slice(nonce_bytes);
let nonce = Nonce::<Aes256Gcm>::try_from(nonce_bytes)
.map_err(|_| EncryptionError::InvalidCiphertext)?;
let payload = Payload {
msg: ciphertext,
aad,
};
if let Ok(plain) = self.cipher.decrypt(nonce, payload) {
if let Ok(plain) = self.cipher.decrypt(&nonce, payload) {
return Ok(plain);
}
if let Some(ref old) = self.old_cipher {
return old
.decrypt(
nonce,
&nonce,
Payload {
msg: ciphertext,
aad,
Expand Down
Loading