GHSA-jp3w-3q88-34cf: Rust crypto Miscomputation When Performing AES Encryption Vulnerability

CRITICAL
Published
Advisory Summary

GHSA-jp3w-3q88-34cf is a CRITICAL miscomputation when performing aes encryption vulnerability (General Security Weakness) affecting Rust crypto libraries in the crates.io ecosystem. The issue involves miscomputation when performing aes encryption in rust-crypto. Remediation is available in the latest vendor maintenance releases.

GHSA-jp3w-3q88-34cf at a Glance

CVE Identifier N/A
GHSA Identifier GHSA-jp3w-3q88-34cf
Severity CRITICAL
CVSS v3.1 Base Score N/A
CWE Classification General Security Weakness
Affected Product Rust crypto
Package Ecosystem crates.io
Published Date
Last Updated

How to Fix GHSA-jp3w-3q88-34cf

To remediate this vulnerability, upgrade all affected Rust crypto dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

rust-crypto fixed: Latest secure release
Upgrade rust-crypto to Latest secure release
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for rust-crypto

How to Check if You Are Affected

To determine whether your application is affected by GHSA-jp3w-3q88-34cf, inspect your project dependencies for Rust crypto:

inspect dependencies for rust-crypto

Analyze the terminal output to locate any version of Rust crypto in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than the patched release), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under General Security Weakness. In Rust crypto, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

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.

GHSA-jp3w-3q88-34cf Affected Rust crypto Versions

1 component(s)
Product / Package Ecosystem Affected Versions Fixed Version
rust-crypto
crates.io
≤ 0.2.36

References

Frequently Asked Questions

What is GHSA-jp3w-3q88-34cf?
GHSA-jp3w-3q88-34cf is a security vulnerability in Rust crypto involving Miscomputation when performing AES encryption in rust-crypto under General Security Weakness.
Which Rust crypto versions are affected?
Affected versions include releases prior to current release patches across affected packages: rust-crypto.
What version fixes GHSA-jp3w-3q88-34cf?
Upgrading to current release patches (or the latest patched release for your respective branch) resolves the vulnerability.
Is rust-crypto affected?
Yes, rust-crypto is affected in releases prior to Latest secure release. Upgrade your dependency to Latest secure release or later.
What CWE is associated with GHSA-jp3w-3q88-34cf?
GHSA-jp3w-3q88-34cf is classified under General Security Weakness.
How can I check crates.io dependencies for GHSA-jp3w-3q88-34cf?
Run the dependency tree command: 'inspect dependencies for rust-crypto'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-jp3w-3q88-34cf",
  "modified" : "2022-06-17T00:17:08Z",
  "published" : "2022-06-17T00:17:08Z",
  "aliases" : [ ],
  "summary" : "Miscomputation when performing AES encryption in rust-crypto",
  "details" : "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.\n\nFor 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.\n\n```rust\nuse crypto::{\n    aes, blockmodes, buffer,\n    buffer::{BufferResult, ReadBuffer, WriteBuffer},\n    symmetriccipher,\n};\n\nfn encrypt(\n    key: &[u8],\n    iv: &[u8],\n    data: &str,\n) -> Result<String, symmetriccipher::SymmetricCipherError> {\n    let mut encryptor =\n        aes::cbc_encryptor(aes::KeySize::KeySize256, key, iv, blockmodes::PkcsPadding);\n\n    let mut encrypted_data = Vec::<u8>::new();\n    let mut read_buffer = buffer::RefReadBuffer::new(data.as_bytes());\n    let mut buffer = [0; 4096];\n    let mut write_buffer = buffer::RefWriteBuffer::new(&mut buffer);\n\n    loop {\n        let result = encryptor.encrypt(&mut read_buffer, &mut write_buffer, true)?;\n\n        encrypted_data.extend(\n            write_buffer\n                .take_read_buffer()\n                .take_remaining()\n                .iter()\n                .copied(),\n        );\n\n        match result {\n            BufferResult::BufferUnderflow => break,\n            BufferResult::BufferOverflow => {}\n        }\n    }\n\n    Ok(hex::encode(encrypted_data))\n}\n\nfn working() {\n    let data = \"data\";\n    let iv = [\n        0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE,\n        0xFF,\n    ];\n    let key = [\n        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,\n        0x0F,\n    ];\n    // The copy here makes the code work.\n    let key_copy = key;\n    let key2: Vec<u8> = key_copy.iter().cycle().take(32).copied().collect();\n    println!(\"key1:{} key2: {}\", hex::encode(&key), hex::encode(&key2));\n\n    let x1 = encrypt(&key, &iv, data).unwrap();\n    println!(\"X1: {}\", x1);\n\n    let x2 = encrypt(&key2, &iv, data).unwrap();\n    println!(\"X2: {}\", x2);\n\n    assert_eq!(x1, x2);\n}\n\nfn broken() {\n    let data = \"data\";\n    let iv = [\n        0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE,\n        0xFF,\n    ];\n    let key = [\n        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,\n        0x0F,\n    ];\n    // This operation shouldn't affect the contents of key at all.\n    let key2: Vec<u8> = key.iter().cycle().take(32).copied().collect();\n    println!(\"key1:{} key2: {}\", hex::encode(&key), hex::encode(&key2));\n\n    let x1 = encrypt(&key, &iv, data).unwrap();\n    println!(\"X1: {}\", x1);\n\n    let x2 = encrypt(&key2, &iv, data).unwrap();\n    println!(\"X2: {}\", x2);\n\n    assert_eq!(x1, x2);\n}\n\nfn main() {\n    working();\n    broken();\n}\n```\n\nThe output from this program:\n\n```shell\n     Running `target/host/debug/rust-crypto-test`\nkey1:000102030405060708090a0b0c0d0e0f key2: 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f\nX1: 90462bbe32965c8e7ea0addbbed4cddb\nX2: 90462bbe32965c8e7ea0addbbed4cddb\nkey1:000102030405060708090a0b0c0d0e0f key2: 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f\nX1: 26e847e5e7df1947bf82a650548a7d5b\nX2: 90462bbe32965c8e7ea0addbbed4cddb\nthread 'main' panicked at 'assertion failed: `(left == right)`\n  left: `\"26e847e5e7df1947bf82a650548a7d5b\"`,\n right: `\"90462bbe32965c8e7ea0addbbed4cddb\"`', src/main.rs:83:5\n```\n\nNotably, the X1 key in the `broken()` test changes every time after rerunning the program.\n\n",
  "severity" : [ ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "crates.io",
      "name" : "rust-crypto"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "last_affected" : "0.2.36"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/DaGenix/rust-crypto/issues/476"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/DaGenix/rust-crypto"
  }, {
    "type" : "WEB",
    "url" : "https://rustsec.org/advisories/RUSTSEC-2022-0011.html"
  } ],
  "database_specific" : {
    "cwe_ids" : [ ],
    "severity" : "CRITICAL",
    "github_reviewed" : true,
    "github_reviewed_at" : "2022-06-17T00:17:08Z",
    "nvd_published_at" : null
  }
}