Use seperate nonces for thumbnails and full images

Prevents vulnerability via nonce re-use
This commit is contained in:
Emi Simpson 2022-11-09 15:53:35 -05:00
parent 69f6830c3e
commit dd2748cbe0
Signed by: Emi
GPG key ID: A12F2C2FFDC3D847
2 changed files with 14 additions and 8 deletions

View file

@ -5,14 +5,18 @@ use crypto::ciphers::{
};
use crypto::utils::rand;
const NONCE: [u8; 12] = [0xd0, 0xc3, 0x75, 0x56, 0x58, 0xc1, 0x7e, 0x5f, 0xd6, 0xcc, 0xb6, 0x76];
/// A nonce used for encrypting the gallery's index, as well as all full images
pub const NONCE_A: [u8; 12] = [0xd0, 0xc3, 0x75, 0x56, 0x58, 0xc1, 0x7e, 0x5f, 0xd6, 0xcc, 0xb6, 0x76];
pub fn encrypt(key: &[u8; 32], plaintext: &[u8]) -> Vec<u8> {
/// A nonce used for encrypting all thumbnails
pub const NONCE_B: [u8; 12] = [0x77, 0xe7, 0xf7, 0x64, 0x33, 0x80, 0x25, 0x49, 0xec, 0xef, 0x57, 0x3f];
pub fn encrypt(key: &[u8; 32], nonce: &[u8; 12], plaintext: &[u8]) -> Vec<u8> {
let mut result = vec![0; plaintext.len() + 16];
let (cyphertext, tag) = result.split_at_mut(plaintext.len());
Aes256Gcm::try_encrypt(
key,
&NONCE,
nonce,
&[],
plaintext,
cyphertext,
@ -20,12 +24,12 @@ pub fn encrypt(key: &[u8; 32], plaintext: &[u8]) -> Vec<u8> {
result
}
pub fn decrypt<'p>(key: &[u8; 32], encrypted: &[u8], plaintext_dest: &'p mut Vec<u8>) -> Option<&'p mut Vec<u8>> {
pub fn decrypt<'p>(key: &[u8; 32], nonce: &[u8; 12], encrypted: &[u8], plaintext_dest: &'p mut Vec<u8>) -> Option<&'p mut Vec<u8>> {
let (cyphertext, tag) = encrypted.split_at(encrypted.len() - 16);
plaintext_dest.resize(cyphertext.len(), 0);
let e = Aes256Gcm::try_decrypt(
key,
&NONCE,
nonce,
&[],
plaintext_dest,
cyphertext,

View file

@ -106,8 +106,8 @@ fn create(server: &str, args: CreateArgs) {
let key = crypto::make_key();
(
key,
crypto::encrypt(&key, &raw_dat),
crypto::encrypt(&key, &thumbnail),
crypto::encrypt(&key, &crypto::NONCE_A, &raw_dat),
crypto::encrypt(&key, &crypto::NONCE_B, &thumbnail),
blurhash,
format
)
@ -148,6 +148,7 @@ fn create(server: &str, args: CreateArgs) {
let index_key = crypto::make_key();
let encrypted_index = crypto::encrypt(
&index_key,
&crypto::NONCE_A,
&index.write_to_bytes()
.expect("Error serializing protocol buffers")
);
@ -196,7 +197,7 @@ fn download(server: &str, args: DownloadArgs) -> Result<(), AviaryDownloadError>
print!("Downloading index... ");
let encrypted_index = upload::get_data(&download_agent, &index_url, 500_000, &mut download_buffer)
.map_err(AviaryDownloadError::from_download_error(true))?;
let serialized_index = crypto::decrypt(&key, &encrypted_index, &mut decrypt_buffer)
let serialized_index = crypto::decrypt(&key, &crypto::NONCE_A, &encrypted_index, &mut decrypt_buffer)
.ok_or(AviaryDownloadError::KeyMismatch)?;
let index = protobuf::index::Index::parse_from_bytes(&serialized_index)
.map_err(|_| AviaryDownloadError::CorruptIndex("Index was not a valid protobuf structure"))?;
@ -281,6 +282,7 @@ fn download(server: &str, args: DownloadArgs) -> Result<(), AviaryDownloadError>
stdout().flush().unwrap();
let decrypted_thumb = crypto::decrypt(
&key,
&crypto::NONCE_B,
encrypted_thumbnail,
&mut decrypt_buffer
).ok_or(AviaryDownloadError::ExpiredImage)?;