1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//! 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:
//! 1. Both non-empty payload and associated data (it encrypts and
//!    authenticates the payload and also authenticates the associated data).
//! 2. Non-empty payload and empty associated data (it encrypts and
//!    authenticates the payload).
//! 3. 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
//! ```rust
//! # #[cfg(all(feature = "aes", feature = "alloc"))]
//! # {
//! 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:
//!
//! ```rust
//! # #[cfg(all(feature = "aes", feature = "heapless"))]
//! # {
//! 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.
//!
//! [TinyCrypt]: https://github.com/intel/tinycrypt
//! [RustCrypto's AES]: https://github.com/RustCrypto/block-ciphers
//! [`aead::AeadInPlace`]: aead::AeadInPlace
//! [SP 800-38C]: https://csrc.nist.gov/publications/detail/sp/800-38c/final
//! [RFC 3610]: https://tools.ietf.org/html/rfc3610
//! [`AeadInPlace::encrypt_in_place`]: aead::AeadInPlace::encrypt_in_place
//! [`AeadInPlace::decrypt_in_place`]: aead::AeadInPlace::decrypt_in_place
//! [`aead::Buffer`]: aead::Buffer
//! [`heapless::Vec`]: https://docs.rs/heapless/latest/heapless/struct.Vec.html
//! [`aead`]: aead

#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]

mod ccm;

pub use aead::{self, Error};
pub use ccm::{AesCcm, CcmTagSize};

#[cfg(feature = "aes")]
pub use ccm::{Aes128Ccm, Aes256Ccm};