Problem using AES encryption/decryption methods in Webassembly

I am going to use AES encryption/decryption methods written in Webassembly which is a library.
There are 5 types of padding, 3 different length values, 3 modes and 2 method for each algorithm (encrypt/decrypt) which leads to 90 different methods.

First approach is to use match expression to differentiate between all these cases, which leads to huge number of methods and performance issues.

Another approach is using generics:

use aes::block_cipher::{BlockCipher, NewBlockCipher};
use block_modes::block_padding::Padding;
use block_modes::BlockMode;
use std::error::Error;
use std::marker::PhantomData;

pub use aes::{Aes128, Aes192, Aes256};
pub use block_modes::{
    block_padding::{AnsiX923, Iso7816, NoPadding, Pkcs7, ZeroPadding},
    Cbc, Ecb, Pcbc,
};

// #[cfg(target_arch = "wasm32")]
// use wasm_bindgen::prelude::wasm_bindgen;

pub struct Aes<M, C, P> {
    _p: PhantomData<(M, C, P)>,
}

impl<M, C, P> Aes<M, C, P>
where
    M: BlockMode<C, P>,
    C: BlockCipher + NewBlockCipher,
    P: Padding,
{
    
    pub fn encrypt(
        key: Vec<u8>,
        iv: Vec<u8>,
        plaintext: Vec<u8>,
    ) -> Result<Vec<u8>, Box<dyn Error>> {
        Ok(M::new_var(&key, &iv)?.encrypt_vec(&plaintext))
    }

    pub fn decrypt(
        key: Vec<u8>,
        iv: Vec<u8>,
        ciphertext: Vec<u8>,
    ) -> Result<Vec<u8>, Box<dyn Error>> {
        Ok(M::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
    }

}

But the problem is we can't use them like this inside JS:

let ciphertext = Aes::<Cbc<_, _>, Aes128, Pkcs7>::encrypt(key, iv, pt);

Any solution?

1 Like

I don't know if its possible to call rust functions from js with generic parameters.
I would probably create a macro that takes a all the possible generic parameters and creates all allowed function combinations.

1 Like

'Having a function for each case' increases the program size and causes performance issues.

The Compiler should only generate code for the functions used.
If you only need a subset from your 90 methods possible, you should write wrapping functions for only those. If you want your js code to be able to call all 90 method variants you will need 90 methods (or use a enum to disambiguate).

Unfortunately I need all 90 variants in js.

Did you actually measure that the existence of the 90 functions impacts your performance? I don't have much experience regarding wasm, how much of a size difference does it make?

Having a single generic function with parameter for each case also generates a function for each value of this parameter.

Probably, the following code might work in the webasm, could you please provide the usage of the macros for this one?

use aes::{Aes128, Aes192, Aes256};
use block_modes::block_padding::{AnsiX923, Iso7816, NoPadding, Pkcs7, ZeroPadding};
use block_modes::{BlockMode, Cbc, Ecb, Pcbc};
use std::error::Error;
// #[cfg(target_arch = "wasm32")]
// use wasm_bindgen::prelude::wasm_bindgen;

pub enum Pad {
    AnsiX923,
    Iso7816,
    NoPadding,
    Pkcs7,
    ZeroPadding,
}

pub enum Mode {
    Ecb,
    Cbc,
    Pcbc,
}
pub enum Len {
    Aes128,
    Aes192,
    Aes256,
}

pub struct Aes {
    len: Len,
    mode: Mode,
    pad: Pad,
}
impl Aes {
    pub fn new(len: Len, mode: Mode, pad: Pad) -> Self {
        Self { len, mode, pad }
    }
    pub fn encrypt(
        &self,
        key: Vec<u8>,
        iv: Vec<u8>,
        plaintext: Vec<u8>,
    ) -> Result<Vec<u8>, Box<dyn Error>> {
        match (&self.len, &self.mode, &self.pad) {
            (Len::Aes128, Mode::Cbc, Pad::Pkcs7) => {
                Ok(Cbc::<Aes128, Pkcs7>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Cbc, Pad::ZeroPadding) => {
                Ok(Cbc::<Aes128, ZeroPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Cbc, Pad::NoPadding) => {
                Ok(Cbc::<Aes128, NoPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Cbc, Pad::Iso7816) => {
                Ok(Cbc::<Aes128, Iso7816>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Cbc, Pad::AnsiX923) => {
                Ok(Cbc::<Aes128, AnsiX923>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Ecb, Pad::Pkcs7) => {
                Ok(Ecb::<Aes128, Pkcs7>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Ecb, Pad::ZeroPadding) => {
                Ok(Ecb::<Aes128, ZeroPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Ecb, Pad::NoPadding) => {
                Ok(Ecb::<Aes128, NoPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Ecb, Pad::Iso7816) => {
                Ok(Ecb::<Aes128, Iso7816>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Ecb, Pad::AnsiX923) => {
                Ok(Ecb::<Aes128, AnsiX923>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Pcbc, Pad::Pkcs7) => {
                Ok(Pcbc::<Aes128, Pkcs7>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Pcbc, Pad::ZeroPadding) => {
                Ok(Pcbc::<Aes128, ZeroPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Pcbc, Pad::NoPadding) => {
                Ok(Pcbc::<Aes128, NoPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Pcbc, Pad::Iso7816) => {
                Ok(Pcbc::<Aes128, Iso7816>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes128, Mode::Pcbc, Pad::AnsiX923) => {
                Ok(Pcbc::<Aes128, AnsiX923>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Cbc, Pad::Pkcs7) => {
                Ok(Cbc::<Aes192, Pkcs7>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Cbc, Pad::ZeroPadding) => {
                Ok(Cbc::<Aes192, ZeroPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Cbc, Pad::NoPadding) => {
                Ok(Cbc::<Aes192, NoPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Cbc, Pad::Iso7816) => {
                Ok(Cbc::<Aes192, Iso7816>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Cbc, Pad::AnsiX923) => {
                Ok(Cbc::<Aes192, AnsiX923>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Ecb, Pad::Pkcs7) => {
                Ok(Ecb::<Aes192, Pkcs7>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Ecb, Pad::ZeroPadding) => {
                Ok(Ecb::<Aes192, ZeroPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Ecb, Pad::NoPadding) => {
                Ok(Ecb::<Aes192, NoPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Ecb, Pad::Iso7816) => {
                Ok(Ecb::<Aes192, Iso7816>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Ecb, Pad::AnsiX923) => {
                Ok(Ecb::<Aes192, AnsiX923>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Pcbc, Pad::Pkcs7) => {
                Ok(Pcbc::<Aes192, Pkcs7>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Pcbc, Pad::ZeroPadding) => {
                Ok(Pcbc::<Aes192, ZeroPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Pcbc, Pad::NoPadding) => {
                Ok(Pcbc::<Aes192, NoPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Pcbc, Pad::Iso7816) => {
                Ok(Pcbc::<Aes192, Iso7816>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes192, Mode::Pcbc, Pad::AnsiX923) => {
                Ok(Pcbc::<Aes192, AnsiX923>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Cbc, Pad::Pkcs7) => {
                Ok(Cbc::<Aes256, Pkcs7>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Cbc, Pad::ZeroPadding) => {
                Ok(Cbc::<Aes256, ZeroPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Cbc, Pad::NoPadding) => {
                Ok(Cbc::<Aes256, NoPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Cbc, Pad::Iso7816) => {
                Ok(Cbc::<Aes256, Iso7816>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Cbc, Pad::AnsiX923) => {
                Ok(Cbc::<Aes256, AnsiX923>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Ecb, Pad::Pkcs7) => {
                Ok(Ecb::<Aes256, Pkcs7>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Ecb, Pad::ZeroPadding) => {
                Ok(Ecb::<Aes256, ZeroPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Ecb, Pad::NoPadding) => {
                Ok(Ecb::<Aes256, NoPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Ecb, Pad::Iso7816) => {
                Ok(Ecb::<Aes256, Iso7816>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Ecb, Pad::AnsiX923) => {
                Ok(Ecb::<Aes256, AnsiX923>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Pcbc, Pad::Pkcs7) => {
                Ok(Pcbc::<Aes256, Pkcs7>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Pcbc, Pad::ZeroPadding) => {
                Ok(Pcbc::<Aes256, ZeroPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Pcbc, Pad::NoPadding) => {
                Ok(Pcbc::<Aes256, NoPadding>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Pcbc, Pad::Iso7816) => {
                Ok(Pcbc::<Aes256, Iso7816>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
            (Len::Aes256, Mode::Pcbc, Pad::AnsiX923) => {
                Ok(Pcbc::<Aes256, AnsiX923>::new_var(&key, &iv)?.encrypt_vec(&plaintext))
            }
        }
    }
    pub fn decrypt(
        &self,
        key: Vec<u8>,
        iv: Vec<u8>,
        ciphertext: Vec<u8>,
    ) -> Result<Vec<u8>, Box<dyn Error>> {
        match (&self.len, &self.mode, &self.pad) {
            (Len::Aes128, Mode::Cbc, Pad::Pkcs7) => {
                Ok(Cbc::<Aes128, Pkcs7>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Cbc, Pad::ZeroPadding) => {
                Ok(Cbc::<Aes128, ZeroPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Cbc, Pad::NoPadding) => {
                Ok(Cbc::<Aes128, NoPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Cbc, Pad::Iso7816) => {
                Ok(Cbc::<Aes128, Iso7816>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Cbc, Pad::AnsiX923) => {
                Ok(Cbc::<Aes128, AnsiX923>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Ecb, Pad::Pkcs7) => {
                Ok(Ecb::<Aes128, Pkcs7>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Ecb, Pad::ZeroPadding) => {
                Ok(Ecb::<Aes128, ZeroPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Ecb, Pad::NoPadding) => {
                Ok(Ecb::<Aes128, NoPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Ecb, Pad::Iso7816) => {
                Ok(Ecb::<Aes128, Iso7816>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Ecb, Pad::AnsiX923) => {
                Ok(Ecb::<Aes128, AnsiX923>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Pcbc, Pad::Pkcs7) => {
                Ok(Pcbc::<Aes128, Pkcs7>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Pcbc, Pad::ZeroPadding) => {
                Ok(Pcbc::<Aes128, ZeroPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Pcbc, Pad::NoPadding) => {
                Ok(Pcbc::<Aes128, NoPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Pcbc, Pad::Iso7816) => {
                Ok(Pcbc::<Aes128, Iso7816>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes128, Mode::Pcbc, Pad::AnsiX923) => {
                Ok(Pcbc::<Aes128, AnsiX923>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Ecb, Pad::Pkcs7) => {
                Ok(Ecb::<Aes192, Pkcs7>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Ecb, Pad::ZeroPadding) => {
                Ok(Ecb::<Aes192, ZeroPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Ecb, Pad::NoPadding) => {
                Ok(Ecb::<Aes192, NoPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Ecb, Pad::Iso7816) => {
                Ok(Ecb::<Aes192, Iso7816>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Ecb, Pad::AnsiX923) => {
                Ok(Ecb::<Aes192, AnsiX923>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Cbc, Pad::Pkcs7) => {
                Ok(Cbc::<Aes192, Pkcs7>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Cbc, Pad::ZeroPadding) => {
                Ok(Cbc::<Aes192, ZeroPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Cbc, Pad::NoPadding) => {
                Ok(Cbc::<Aes192, NoPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Cbc, Pad::Iso7816) => {
                Ok(Cbc::<Aes192, Iso7816>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Cbc, Pad::AnsiX923) => {
                Ok(Cbc::<Aes192, AnsiX923>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Pcbc, Pad::Pkcs7) => {
                Ok(Pcbc::<Aes192, Pkcs7>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Pcbc, Pad::ZeroPadding) => {
                Ok(Pcbc::<Aes192, ZeroPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Pcbc, Pad::NoPadding) => {
                Ok(Pcbc::<Aes192, NoPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Pcbc, Pad::Iso7816) => {
                Ok(Pcbc::<Aes192, Iso7816>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes192, Mode::Pcbc, Pad::AnsiX923) => {
                Ok(Pcbc::<Aes192, AnsiX923>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Cbc, Pad::Pkcs7) => {
                Ok(Cbc::<Aes256, Pkcs7>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Cbc, Pad::ZeroPadding) => {
                Ok(Cbc::<Aes256, ZeroPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Cbc, Pad::NoPadding) => {
                Ok(Cbc::<Aes256, NoPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Cbc, Pad::Iso7816) => {
                Ok(Cbc::<Aes256, Iso7816>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Cbc, Pad::AnsiX923) => {
                Ok(Cbc::<Aes256, AnsiX923>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Ecb, Pad::Pkcs7) => {
                Ok(Ecb::<Aes256, Pkcs7>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Ecb, Pad::ZeroPadding) => {
                Ok(Ecb::<Aes256, ZeroPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Ecb, Pad::NoPadding) => {
                Ok(Ecb::<Aes256, NoPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Ecb, Pad::Iso7816) => {
                Ok(Ecb::<Aes256, Iso7816>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Ecb, Pad::AnsiX923) => {
                Ok(Ecb::<Aes256, AnsiX923>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Pcbc, Pad::Pkcs7) => {
                Ok(Pcbc::<Aes256, Pkcs7>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Pcbc, Pad::ZeroPadding) => {
                Ok(Pcbc::<Aes256, ZeroPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Pcbc, Pad::NoPadding) => {
                Ok(Pcbc::<Aes256, NoPadding>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Pcbc, Pad::Iso7816) => {
                Ok(Pcbc::<Aes256, Iso7816>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
            (Len::Aes256, Mode::Pcbc, Pad::AnsiX923) => {
                Ok(Pcbc::<Aes256, AnsiX923>::new_var(&key, &iv)?.decrypt_vec(&ciphertext)?)
            }
        }
    }
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.