DaGenix / rust-crypto

A (mostly) pure-Rust implementation of various cryptographic algorithms.
Apache License 2.0
1.39k stars 297 forks source link

AES-CBC does not encrypt blank input #410

Open hwchen opened 7 years ago

hwchen commented 7 years ago

AES-CBC does not encrypt blank input. Basically, the result of input [] is []. I'm not a crypto expert, but from what I've read the encryptor should add PKCS7 padding to the input (even an empty block) and then encrypt (this might be called finalize in another lib). At least, for my secret-service library, I'm unable to use a blank input to create items in the vault because of incorrect encryption.

I may not be understanding the architecture of the blockmodes.rs architecture, but it looks like an empty input results in exiting the encrypting function with BlockEngineState::FastMode https://github.com/DaGenix/rust-crypto/blob/master/src/blockmodes.rs#L164

I think this means that in the state machine, https://github.com/DaGenix/rust-crypto/blob/master/src/blockmodes.rs#L246, an empty input will never be able to reach BlockEngineState::LastInput, which would be required to pad an empty block and encrypt it. Non-empty non-full blocks seem to be padded and processed fine.

As a quick example, running https://github.com/DaGenix/rust-crypto/blob/master/examples/symmetriccipher.rs with a println! after encrypting the data and blank message

let message = "";
.
.
.
let encrypted_data = encrypt(message.as_bytes(), &key, &iv).ok().unwrap();

println!("{:?}", encrypted_data);

while switching the state machine transition at https://github.com/DaGenix/rust-crypto/blob/master/src/blockmodes.rs#L164 from

 return BlockEngineState::FastMode;

to

 return BlockEngineState::LastInput;

results in the following output:

mochi:rust-crypto (master|✚2) > cargo run --example symmetriccipher
   Compiling rust-crypto v0.2.36 (file:///home/hwchen/projects/rust/secret-service/rust-crypto)
    Finished dev [unoptimized + debuginfo] target(s) in 8.14 secs
     Running `target/debug/examples/symmetriccipher`
[]
mochi:rust-crypto (master|✚2) > cargo run --example symmetriccipher
   Compiling rust-crypto v0.2.36 (file:///home/hwchen/projects/rust/secret-service/rust-crypto)
    Finished dev [unoptimized + debuginfo] target(s) in 8.39 secs
     Running `target/debug/examples/symmetriccipher`
[98, 8, 226, 87, 130, 36, 3, 95, 121, 177, 74, 250, 126, 11, 199, 41]

Please let me know if I've understood this correctly.

19h commented 6 years ago

What exactly do you want to achieve?

There's exactly zero blocks to encrypt when there's zero data to begin with. Allowing encryption of empty data can possibly help execute known-plaintext attacks.

You shouldn't ever encrypt empty data.

hwchen commented 6 years ago

I use rust-crypto in a library that interfaces with the vault in Linux, and that library is used in a keyring library that allows for cross-platform interface with vaults. I'm not a crypto expert and have been trying to figure out for some time the correct course of action here. My issue is that osx and and windows vaults both handle blank input. I had assumed that they encrypted that input, and wanted to be able to do the same in Linux.