Skip to content

serpent: mismatch between KeySizeUser impl and dynamically determined key size #495

@bleichenbacher-daniel

Description

@bleichenbacher-daniel

I'm currently testing various ciphers with different encryption modes. I've been unsuccessful in using CBC (and CFB) together with
Serpent with 192-bit and 256-bit keys. I'm unsure if or how this could be achieved.

The crate serpent does support other key sizes. E.g. using Serpent as a block cipher to encrypt single blocks works find with all key sizes
(128 bit, 160 bit, 192 bit, 224 bit and 256 bit). Also the encryption mode XTS works with multiple key sizes.

Other ciphers have variants such as aes::{Aes128, Aes192, Aes256} to specify the expected key size. I have not found an equivalent for
Serpent.

pub fn encrypt(alg: &str, key: &[u8], iv: &[u8], inp: &[u8]) -> Vec<u8> {
  match alg {
    // Serpent with 128-bit keys is OK.
    "serpentcbc128_pkcs7" => {
        type Serpent128CbcEnc = cbc::Encryptor<serpent::Serpent>;
        let key_bytes: &[u8; 16] = key.try_into().unwrap();
        let iv_bytes: &[u8; 16] = iv.try_into().unwrap();
        let res = Serpent128CbcEnc::new(key_bytes.into(), iv_bytes.into())
            .encrypt_padded_vec_mut::<Pkcs7>(&inp);
        return res.to_vec();
    },
    // This does not compile since the compiler expects 128 bit keys.
    "serpentcbc192_pkcs7" => {
        type Serpent192CbcEnc = cbc::Encryptor<serpent::Serpent>;
        let key_bytes: &[u8; 24] = key.try_into().unwrap();
        let iv_bytes: &[u8; 16] = iv.try_into().unwrap();
        let res = Serpent192CbcEnc::new(key_bytes.into(), iv_bytes.into())
            .encrypt_padded_vec_mut::<Pkcs7>(&inp);
        return res.to_vec();
    }, 
    // This does not compile either since the compiler expects 128 bit keys.
    "serpentcbc256_pkcs7" => {
        type Serpent256CbcEnc = cbc::Encryptor<serpent::Serpent>;
        let key_bytes: &[u8; 32] = key.try_into().unwrap();
        let iv_bytes: &[u8; 16] = iv.try_into().unwrap();
        let res = Serpent256CbcEnc::new(key_bytes.into(), iv_bytes.into())
            .encrypt_padded_vec_mut::<Pkcs7>(&inp);
        return res.to_vec();
    }, 
    // This works.
    "serpentcfb128_128" => {
        type Serpent128CfbEnc = cfb_mode::Encryptor<serpent::Serpent>;
        let key_bytes: &[u8; 16] = key.try_into().unwrap();
        let iv_bytes: &[u8; 16] = iv.try_into().unwrap();
        let mut buf = inp.to_vec();
        Serpent128CfbEnc::new(key_bytes.into(), iv_bytes.into()).encrypt(&mut buf);
        return buf;
    },
    // This does not compile, since the expected key size is 128-bit.
    "serpentcfb128_192" => {
        type Serpent192CfbEnc = cfb_mode::Encryptor<serpent::Serpent>;
        let key_bytes: &[u8; 24] = key.try_into().unwrap();
        let iv_bytes: &[u8; 16] = iv.try_into().unwrap();
        let mut buf = inp.to_vec();
        Serpent192CfbEnc::new(key_bytes.into(), iv_bytes.into()).encrypt(&mut buf);
        return buf;
    },
    // XTS with two 128-bit keys works.
    "serpentxts_256"  => {
        let cipher_1 = serpent::Serpent::new_from_slice(&key[..16]).unwrap();
        let cipher_2 = serpent::Serpent::new_from_slice(&key[16..]).unwrap();
        let xts_cipher = xts_mode::Xts128::<serpent::Serpent>::new(cipher_1, cipher_2);
        let iv_bytes: &[u8; 16] = iv.try_into().unwrap();
        let mut buf = inp.to_vec();
        xts_cipher.encrypt_sector(&mut buf, *iv_bytes);
        return buf;
    },
    // XTS with two 256-bit keys works too (and also gives the correct result).
    "serpentxts_512"  => {
        let cipher_1 = serpent::Serpent::new_from_slice(&key[..32]).unwrap();
        let cipher_2 = serpent::Serpent::new_from_slice(&key[32..]).unwrap();
        let xts_cipher = xts_mode::Xts128::<serpent::Serpent>::new(cipher_1, cipher_2);
        let iv_bytes: &[u8; 16] = iv.try_into().unwrap();
        let mut buf = inp.to_vec();
        xts_cipher.encrypt_sector(&mut buf, *iv_bytes);
        return buf;
    },
    // ...
    _ => {panic!("Unsupported algorithm:{}", alg);}
  }
}

The versions I'm using are:

cbc = { version = "0.1.2", features = ["block-padding", "alloc"] }
cfb-mode = { version = "0.8.2", features = ["block-padding", "alloc"] }
chacha20poly1305 = "0.10.1"
cipher = { version = "0.4.4", features = ["alloc", "block-padding"] }
serpent = "0.5.1"
xts-mode = "0.5.1"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions