Module capsules_core::virtualizers::virtual_aes_ccm

source ·
Expand description

Implements and virtualizes AES-CCM* encryption/decryption/authentication using an underlying AES-CBC and AES-CTR implementation.

IEEE 802.15.4-2015: Appendix B.4.1, CCM* transformations. CCM* is defined so that both encryption and decryption can be done by preparing two fields: the AuthData and either the PlaintextData or the CiphertextData. Then, two passes of AES are performed with one block of overlap.

crypt_buf: [ -------- AuthData -------- | -------- PData/CData -------- ]
aes_cbc:    \__________________________/
aes_ctr:                        \ 1 blk | _____________________________/

The overlapping block is then the encrypted authentication tag U. For encryption, we append U to the data as a message integrity code (MIC). For decryption, we compare U with the provided MIC. This is true only if data confidentiality is not needed. If it is, then the AuthData includes the PlaintextData. At encryption, we perform CBC over both fields, then copy the last block to just before the PData. Then, CTR mode is performed over the same overlapping region, forming the encrypted authentication tag U.

crypt_buf: [ -------- AuthData -------- | -------- PData/CData -------- ]
aes_cbc:    \__________________________________________________________/
aes_ctr:                        \ 1 blk | _____________________________/

At decryption, there is no choice but the reverse the order of operations. First, we zero out the overlapping block and perform ctr over it and the PlaintextData. This produces Enc(Key, A_i), which we save in saved_tag. Then, we restore the previous value of the last block of AuthData and re-pad PlaintextData before running CBC over both fields. The last step is to combine saved_tag and the unencrypted tag to form the encrypted tag and verify its correctness.

§Usage

type AESCCMMUX = virtual_aes_ccm::MuxAES128CCM<'static, Aes<'static>>;
type AESCCMCLIENT = virtual_aes_ccm::VirtualAES128CCM<'static, AESCCMMUX>;
// mux
let ccm_mux = static_init!(AESCCMMUX, virtual_aes_ccm::MuxAES128CCM::new(&AES));
ccm_mux.register();
AES.set_client(ccm_mux);
const CRYPT_SIZE: usize = 7 * AES128_BLOCK_SIZE;
let crypt_buf1 = static_init!([u8; CRYPT_SIZE], [0x00; CRYPT_SIZE]);
let ccm_client1 = static_init!(
    AESCCMCLIENT,
    virtual_aes_ccm::VirtualAES128CCM::new(ccm_mux, crypt_buf1)
);
ccm_client1.setup();
let data1 = static_init!([u8; 4 * AES128_BLOCK_SIZE], [0x00; 4 * AES128_BLOCK_SIZE]);
let t1 = static_init!(Test<'static, AESCCMCLIENT>, Test::new(ccm_client1, data1));
ccm_client1.set_client(t1);
let crypt_buf2 = static_init!([u8; CRYPT_SIZE], [0x00; CRYPT_SIZE]);
let ccm_client2 = static_init!(
    AESCCMCLIENT,
    virtual_aes_ccm::VirtualAES128CCM::new(ccm_mux, crypt_buf2)
);
ccm_client2.setup();
let data2 = static_init!([u8; 4 * AES128_BLOCK_SIZE], [0x00; 4 * AES128_BLOCK_SIZE]);
let t2 = static_init!(Test<'static, AESCCMCLIENT>, Test::new(ccm_client2, data2));
ccm_client2.set_client(t2);
t1.run();
t2.run();

Structs§