logo

GHSA-jp3w-3q88-34cf rust-crypto

Package

Manager: cargo
Name: rust-crypto
Vulnerable Version: >=0 <=0.2.36

Severity

Level: Critical

CVSS v3.1: CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N/E:U/RL:O/RC:C

CVSS v4.0: CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N

EPSS: N/A pctlN/A

Details

Miscomputation when performing AES encryption in rust-crypto The following Rust program demonstrates some strangeness in AES encryption - if you have an immutable key slice and then operate on that slice, you get different encryption output than if you operate on a copy of that key. For these functions, we expect that extending a 16 byte key to a 32 byte key by repeating it gives the same encrypted data, because the underlying rust-crypto functions repeat key data up to the necessary key size for the cipher. ```rust use crypto::{ aes, blockmodes, buffer, buffer::{BufferResult, ReadBuffer, WriteBuffer}, symmetriccipher, }; fn encrypt( key: &[u8], iv: &[u8], data: &str, ) -> Result<String, symmetriccipher::SymmetricCipherError> { let mut encryptor = aes::cbc_encryptor(aes::KeySize::KeySize256, key, iv, blockmodes::PkcsPadding); let mut encrypted_data = Vec::<u8>::new(); let mut read_buffer = buffer::RefReadBuffer::new(data.as_bytes()); let mut buffer = [0; 4096]; let mut write_buffer = buffer::RefWriteBuffer::new(&mut buffer); loop { let result = encryptor.encrypt(&mut read_buffer, &mut write_buffer, true)?; encrypted_data.extend( write_buffer .take_read_buffer() .take_remaining() .iter() .copied(), ); match result { BufferResult::BufferUnderflow => break, BufferResult::BufferOverflow => {} } } Ok(hex::encode(encrypted_data)) } fn working() { let data = "data"; let iv = [ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, ]; let key = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ]; // The copy here makes the code work. let key_copy = key; let key2: Vec<u8> = key_copy.iter().cycle().take(32).copied().collect(); println!("key1:{} key2: {}", hex::encode(&key), hex::encode(&key2)); let x1 = encrypt(&key, &iv, data).unwrap(); println!("X1: {}", x1); let x2 = encrypt(&key2, &iv, data).unwrap(); println!("X2: {}", x2); assert_eq!(x1, x2); } fn broken() { let data = "data"; let iv = [ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, ]; let key = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ]; // This operation shouldn't affect the contents of key at all. let key2: Vec<u8> = key.iter().cycle().take(32).copied().collect(); println!("key1:{} key2: {}", hex::encode(&key), hex::encode(&key2)); let x1 = encrypt(&key, &iv, data).unwrap(); println!("X1: {}", x1); let x2 = encrypt(&key2, &iv, data).unwrap(); println!("X2: {}", x2); assert_eq!(x1, x2); } fn main() { working(); broken(); } ``` The output from this program: ```shell Running `target/host/debug/rust-crypto-test` key1:000102030405060708090a0b0c0d0e0f key2: 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f X1: 90462bbe32965c8e7ea0addbbed4cddb X2: 90462bbe32965c8e7ea0addbbed4cddb key1:000102030405060708090a0b0c0d0e0f key2: 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f X1: 26e847e5e7df1947bf82a650548a7d5b X2: 90462bbe32965c8e7ea0addbbed4cddb thread 'main' panicked at 'assertion failed: `(left == right)` left: `"26e847e5e7df1947bf82a650548a7d5b"`, right: `"90462bbe32965c8e7ea0addbbed4cddb"`', src/main.rs:83:5 ``` Notably, the X1 key in the `broken()` test changes every time after rerunning the program.

Metadata

Created: 2022-06-17T00:17:08Z
Modified: 2022-06-17T00:17:08Z
Source: https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2022/06/GHSA-jp3w-3q88-34cf/GHSA-jp3w-3q88-34cf.json
CWE IDs: []
Alternative ID: N/A
Finding: F113
Auto approve: 1