Skip to content

Commit

Permalink
support changing auto_padding setting in CBC mode
Browse files Browse the repository at this point in the history
  • Loading branch information
keepsimple1 committed Oct 1, 2023
1 parent 8a7b17b commit b6c72f7
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 2 deletions.
35 changes: 33 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ const RD_KEY_MAX_SIZE: usize = 4 * (AES_MAX_ROUNDS + 1);
pub struct Cipher {
encrypt_key: AesKey,
decrypt_key: AesKey,

/// By default, this is true. It is only used in CBC mode now.
auto_padding: bool,
}

impl Cipher {
Expand Down Expand Up @@ -90,6 +93,7 @@ impl Cipher {
Cipher {
encrypt_key,
decrypt_key,
auto_padding: true,
}
}

Expand Down Expand Up @@ -122,6 +126,7 @@ impl Cipher {
Cipher {
encrypt_key,
decrypt_key,
auto_padding: true,
}
}

Expand Down Expand Up @@ -154,16 +159,33 @@ impl Cipher {
Cipher {
encrypt_key,
decrypt_key,
auto_padding: true,
}
}

/// Changes the `auto_padding` setting of the cipher. Used in CBC mode.
/// Note that `auto_padding` is ignored in CFB mode.
pub fn set_auto_padding(&mut self, auto_padding: bool) {
self.auto_padding = auto_padding;
}

/// Returns the `auto_padding` setting in this cipher. If true,
/// the padding is done in PKCS7.
pub fn auto_padding(&self) -> bool {
self.auto_padding
}

/// Encrypt in CBC mode.
///
/// The input data is not modified. The output is a new Vec. Padding (PKCS7) is included.
/// `iv` is a 16-byte slice. Panics if `iv` is less than 16 bytes.
///
/// This method works for all key sizes.
///
/// Note: auto padding is enabled by default. If the cipher disabled auto padding, this
/// method will not add padding. If the input data length is not multiple of AES_BLOCK_SIZE,
/// the output will be an empty Vec (i.e. error).
///
/// # Examples
///
/// ```
Expand All @@ -176,7 +198,14 @@ impl Cipher {
/// let encrypted = cipher.cbc_encrypt(iv, plaintext);
/// ```
pub fn cbc_encrypt(&self, iv: &[u8], data: &[u8]) -> Vec<u8> {
let mut padded = pad(data);
let mut padded = if self.auto_padding {
pad(data)
} else if data.len() % AES_BLOCK_SIZE == 0 {
data.to_vec()
} else {
return Vec::new();
};

let mut my_iv = iv;
let mut rest = &mut padded[..];
while rest.len() >= AES_BLOCK_SIZE {
Expand Down Expand Up @@ -228,7 +257,9 @@ impl Cipher {
xor_with_iv(block, my_iv);
my_iv = &data[i..i + AES_BLOCK_SIZE];
}
unpad(&mut new);
if self.auto_padding {
unpad(&mut new);
}
new
}

Expand Down
25 changes: 25 additions & 0 deletions tests/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,3 +321,28 @@ fn invalid_input_decrypt() {
let decrypted = cipher.cbc_decrypt(iv, &empty_ciphertext[..]);
assert!(decrypted.is_empty());
}

#[test]
fn cbc_without_auto_padding() {
let plaintext: &[u8; 16] = b"\x59\xf9\x62\x18\xd8\xec\xca\xb2\x77\xed\x47\x7a\x33\xdc\xb7\xf3";
let ciphertext: &[u8; 16] = b"\x9f\x27\x07\xbc\x98\xbb\x57\x81\xd4\xe7\xb4\x61\xbf\xfe\x62\x70";
let key: &[u8; 16] = b"\x64\xc5\xfd\x55\xdd\x3a\xd9\x88\x32\x5b\xaa\xec\x52\x43\xdb\x98";
let iv: &[u8; 16] = b"\x00\x04\x00\x8c\x00\x16\x58\x00\x00\x00\x00\x00\x00\x00\x00\x00";

// create a cipher and disable its auto_padding.
let mut aes: Cipher = Cipher::new_128(key);
aes.set_auto_padding(false);

// verify decrypt.
let decrypted = aes.cbc_decrypt(iv, ciphertext);
assert_eq!(&decrypted, plaintext);

// verify encrypt.
let encrypted = aes.cbc_encrypt(iv, plaintext);
assert_eq!(&encrypted, ciphertext);

// encrypt returns empty if the plaintext is not valid block-sized.
let invalidblock: &[u8; 10] = b"\x59\xf9\x62\x18\xd8\xec\xca\xb2\x77\xed";
let encrypted = aes.cbc_encrypt(iv, invalidblock);
assert!(encrypted.is_empty());
}

0 comments on commit b6c72f7

Please sign in to comment.