RustCrypto / block-modes

Collection of generic block mode algorithms written in pure Rust
61 stars 12 forks source link

How should I use AES-256-CBC to decrypt? #37

Closed baby195lxl closed 1 year ago

baby195lxl commented 1 year ago

I am trying to decrypt a string using AES-256-CBC, but I am getting an error message 'thread 'main' panicked at 'called Result::unwrap() on an Err value: UnpadError'. Did I miss any steps?

use base64::{Engine as _, alphabet, engine::{GeneralPurposeConfig, self}};
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, KeyIvInit};

type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;

fn main() {
    let config = GeneralPurposeConfig::new().with_decode_allow_trailing_bits(true);
    let s = String::from("no7AfO7XatdfEGhh1bLIU5wT4U5X2712vyWJbmQAbyK=");
    println!("{}", s);

    let key = engine::GeneralPurpose::new(&alphabet::STANDARD, config).decode(s).unwrap();
    let key_output: [u8; 32] = key.clone().try_into().unwrap();
    println!("{:?}", key_output.len());

    let iv = &key[..16];
    let iv_output: [u8; 16] = iv.try_into().unwrap();
    println!("{:?}", iv_output.len());

    let encrypt = "yWgEEgiU97Bd/cX4ezT+Rk/78oJbABb9gr/N73FbBCvgPd3po2JyHYMsSmiyNgEXI+6f2kXxqBdxm/bfTs909UhYvW2PzXzMx4FiDiEAmnogBHNtw7W3kjUZVCDfuU3V1eRRM+QEI+rRXlgMcSKlaLXuEOIKn+AQuD53yXPsXzMdbb+5/Zs8zXddJjN1AtOmI0D8ZJOW6yBjJARk4dFn62Ks/SZai5ec9zg13LZOx8dt1DeI5eF/gqpJZorn5nGhWEX3pR3/XDTwn7u1hdbUeu7Eyu/mmmUQiwlWjVLxIOONHQQRuOSWfy+OePcbvsQSPt4E4Ec6THrW+y5WcWKIEEFSh/GFwC+7ueElNLNErAha6mflewBivoXplC4PRLGB/1uHfV1O1gBxPBtzH2x8X8NlFWptjjGjUSb4jzBj07hmdhPul7bNw0tha7FVibQCUKWqOmiufDY7Y3CDjPyvpA==";
    let encrypted = engine::GeneralPurpose::new(&alphabet::STANDARD, config).decode(encrypt).unwrap();
    println!("{:?}", encrypted.len());

    let mut buf = [0u8; 1024];
    let pt = Aes256CbcDec::new(&key_output.into(), &iv_output.into())
        .decrypt_padded_b2b_mut::<Pkcs7>(&encrypted, &mut buf)
        .unwrap();
    println!("{:?}", pt);

}

This is the Python code that I want to implement using Rust.

a = "no7AfO7XatdfEGhh1bLIU5wT4U5X2712vyWJbmQAbyK="
key = base64.b64decode(s)
cryptor = AES.new(key,  AES.MODE_CBC, key[:16])
text = "yWgEEgiU97Bd/cX4ezT+Rk/78oJbABb9gr/N73FbBCvgPd3po2JyHYMsSmiyNgEXI+6f2kXxqBdxm/bfTs909UhYvW2PzXzMx4FiDiEAmnogBHNtw7W3kjUZVCDfuU3V1eRRM+QEI+rRXlgMcSKlaLXuEOIKn+AQuD53yXPsXzMdbb+5/Zs8zXddJjN1AtOmI0D8ZJOW6yBjJARk4dFn62Ks/SZai5ec9zg13LZOx8dt1DeI5eF/gqpJZorn5nGhWEX3pR3/XDTwn7u1hdbUeu7Eyu/mmmUQiwlWjVLxIOONHQQRuOSWfy+OePcbvsQSPt4E4Ec6THrW+y5WcWKIEEFSh/GFwC+7ueElNLNErAha6mflewBivoXplC4PRLGB/1uHfV1O1gBxPBtzH2x8X8NlFWptjjGjUSb4jzBj07hmdhPul7bNw0tha7FVibQCUKWqOmiufDY7Y3CDjPyvpA=="
plain_text = cryptor.decrypt(base64.b64decode(text))

Thank you for your help, I appreciate any response

newpavlov commented 1 year ago

Are you sure that your message uses PKCS7 padding and not something else? I suggest inspecting message decrypted with NoPadding, you also will be able to see whether the decrypted text makes sense.

P.S.: I suggest using URLO for such questions since it has a much bigger audience than our issue tracker.

baby195lxl commented 1 year ago

@newpavlov Thank you for your reply, but I am certain that this message was padded using PKCS7, as I am using an enterprise API. Perhaps implementing decryption in Rust may be a bit challenging for a non-professional enthusiast like me compared to Python, but I still want to do it. Thank you again for your reply. And If there are more suggestions, I would be grateful.

newpavlov commented 1 year ago

By decrypting with NoPadding and inspecting the resulting bytes, you could see that your message ends with a bunch of bytes equal to 27, which is bigger than block size of AES. It looks like your message uses a peculiar variant of PKCS7 which goes against the description in RFC 5652. So your best option is to decrypt with NoPadding and remove padding bytes manually (do not forget to validate padding).

tarcieri commented 1 year ago

Is there a discrepancy with the Python implementation, or is Python permitting invalid padding?

newpavlov commented 1 year ago

I think the Python implementation allows paddings bigger than block size, but I am not sure which exact package is used by OP.

newpavlov commented 1 year ago

FYI in block-padding v0.3.3 was added support for padding with block size variable at runtime, see the RawPadding trait.

baby195lxl commented 1 year ago

FYI in block-padding v0.3.3 was added support for padding with block size variable at runtime, see the RawPadding trait.

Thank you very much for your response to my question and your contribution to this repository. I hope this project can continue to be maintained and updated, and become a popular crate