This project contains known security vulnerabilities. Find detailed information at the bottom.

Crate snow

Dependencies

(14 total, 6 outdated, 2 insecure)

CrateRequiredLatestStatus
 arrayref^0.30.3.9up to date
 blake2-rfc^0.20.2.18up to date
 byteorder^1.21.5.0up to date
 chacha20-poly1305-aead^0.10.1.2up to date
 failure^0.10.1.8up to date
 failure_derive^0.10.1.8up to date
 hacl-star^0.0.130.1.0out of date
 rand^0.60.10.2out of date
 rand_core^0.40.10.1out of date
 ring ⚠️^0.14.00.17.14insecure
 rust-crypto ⚠️^0.20.2.36insecure
 smallvec^0.6.31.16.1out of date
 static_slice^0.0.30.0.3up to date
 x25519-dalek^0.43.0.0out of date

Dev dependencies

(7 total, 3 outdated)

CrateRequiredLatestStatus
 clap^24.6.7out of date
 criterion^0.20.8.2out of date
 hex^0.30.4.3out of date
 lazy_static^1.21.5.0up to date
 serde^1.01.0.229up to date
 serde_derive^1.01.0.229up to date
 serde_json^1.01.0.151up to date

Security Vulnerabilities

rust-crypto: Miscomputation when performing AES encryption in rust-crypto

RUSTSEC-2022-0011

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.

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:

     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.

ring: Some AES functions may panic when overflow checking is enabled.

RUSTSEC-2025-0009

ring::aead::quic::HeaderProtectionKey::new_mask() may panic when overflow checking is enabled. In the QUIC protocol, an attacker can induce this panic by sending a specially-crafted packet. Even unintentionally it is likely to occur in 1 out of every 2**32 packets sent and/or received.

On 64-bit targets operations using ring::aead::{AES_128_GCM, AES_256_GCM} may panic when overflow checking is enabled, when encrypting/decrypting approximately 68,719,476,700 bytes (about 64 gigabytes) of data in a single chunk. Protocols like TLS and SSH are not affected by this because those protocols break large amounts of data into small chunks. Similarly, most applications will not attempt to encrypt/decrypt 64GB of data in one chunk.

Overflow checking is not enabled in release mode by default, but RUSTFLAGS="-C overflow-checks" or overflow-checks = true in the Cargo.toml profile can override this. Overflow checking is usually enabled by default in debug mode.