7 releases (4 breaking)
0.5.0 | Jun 13, 2020 |
---|---|
0.4.1 | Mar 17, 2020 |
0.4.0 | Dec 1, 2019 |
0.3.0 | Sep 9, 2019 |
0.1.0 | Aug 19, 2019 |
#2696 in Cryptography
100 downloads per month
47KB
789 lines
aes-ccm
A pure-Rust, #![no_std]
, zero-allocation AES-CCM implementation ported
from TinyCrypt using RustCrypto's AES (with support for optionally
swapping in hardware-backed implementations).
It implements the aead::AeadInPlace
trait, so it can be used
effortlessly together with other implementations.
Overview
CCM (for "Counter with CBC-MAC") mode is a NIST approved mode of operation defined in SP 800-38C.
This implementation accepts:
- Both non-empty payload and associated data (it encrypts and authenticates the payload and also authenticates the associated data).
- Non-empty payload and empty associated data (it encrypts and authenticates the payload).
- Non-empty associated data and empty payload (it degenerates to an authentication mode on the associated data).
The implementation accepts payloads of any length between 0 and 2^16 bytes and associated data of any length between 0 and (2^16 - 2^8) bytes.
Usage
use aes_ccm::{
aead::{consts::U8, Aead, NewAead, Payload},
Aes128Ccm,
};
let key = [
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA,
0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
];
// `U8` represents the tag size as a `typenum` unsigned (8-bytes here)
let ccm = Aes128Ccm::<U8>::new(&key.into());
let nonce = [
0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xA0, 0xA1, 0xA2, 0xA3,
0xA4, 0xA5,
];
let msg = [
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
0x1E,
];
let associated_data = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
let ciphertext = ccm
.encrypt(
&nonce.into(),
Payload {
aad: &associated_data,
msg: &msg,
},
)
.unwrap();
let plaintext = ccm
.decrypt(
&nonce.into(),
Payload {
aad: &associated_data,
msg: &ciphertext,
},
)
.unwrap();
assert_eq!(&msg[..], plaintext.as_slice());
In-place Usage (eliminates alloc
requirement)
This crate has an optional alloc
feature which can be disabled in e.g.
microcontroller environments that don't have a heap.
The AeadInPlace::encrypt_in_place
and AeadInPlace::decrypt_in_place
methods accept any type that impls the aead::Buffer
trait which
contains the plaintext for encryption or ciphertext for decryption.
Note that if you enable the heapless
feature of this crate,
you will receive an impl of aead::Buffer
for heapless::Vec
(re-exported from the aead
crate as aead::heapless::Vec
),
which can then be passed as the buffer
parameter to the in-place encrypt
and decrypt methods:
use aes_ccm::{
aead::{
consts::{U128, U8},
heapless::Vec,
AeadInPlace, NewAead,
},
Aes128Ccm,
};
let key = [
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA,
0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
];
// `U8` represents the tag size as a `typenum` unsigned (8-bytes here)
let ccm = Aes128Ccm::<U8>::new(&key.into());
let nonce = [
0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xA0, 0xA1, 0xA2, 0xA3,
0xA4, 0xA5,
];
let associated_data = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
let plaintext = [
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
0x1E,
];
let mut buffer: Vec<u8, U128> = Vec::new();
buffer.extend_from_slice(&plaintext).unwrap();
// Encrypt `buffer` in-place, replacing the plaintext contents with
// ciphertext
ccm.encrypt_in_place(&nonce.into(), &associated_data, &mut buffer)
.unwrap();
// `buffer` now contains the message ciphertext
assert_ne!(&buffer, &plaintext);
// Decrypt `buffer` in-place, replacing its ciphertext contents with the
// original plaintext
ccm.decrypt_in_place(&nonce.into(), &associated_data, &mut buffer)
.unwrap();
assert_eq!(&buffer, &plaintext);
Security
I'm not a cryptographer and this hasn't been audited in any way. It is however a careful port of TinyCrypt, so if it's sound, then this should be too.
The MAC length parameter is an important parameter to estimate the security against collision attacks (that aim at finding different messages that produce the same authentication tag). The implementation accepts any even integer between 4 and 16, as suggested in SP 800-38C.
RFC 3610, which also specifies CCM, presents a few relevant security suggestions, such as:
- It is recommended that most applications use a MAC length greater than 8.
- The usage of the same nonce for two different messages which are encrypted with the same key destroys the security of CCM mode.
License
Licensed under either of
at your option.
This is a port of TinyCrypt's CCM mode, its license file is in LICENSE-3RD-PARTY.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Dependencies
~595KB
~13K SLoC