Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion aes-gcm-siv/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ zeroize = { version = "1", default-features = false }
aead = { version = "0.5", features = ["dev"], default-features = false }

[features]
default = ["aes", "alloc"]
default = ["aes", "alloc", "getrandom"]
std = ["aead/std", "alloc"]
alloc = ["aead/alloc"]
getrandom = ["aead/getrandom"]
Expand Down
102 changes: 48 additions & 54 deletions aes-gcm-siv/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,20 @@
//! [AES-GCM-SIV][1] ([RFC 8452][2]): high-performance
//! [AES-auth tag-SIV][1] ([RFC 8452][2]): high-performance
//! [Authenticated Encryption with Associated Data (AEAD)][3] cipher which also
//! provides [nonce reuse misuse resistance][4].
//!
//! Suitable as a general purpose symmetric encryption cipher, AES-GCM-SIV also
//! removes many of the "sharp edges" of AES-GCM, providing significantly better
//! Suitable as a general purpose symmetric encryption cipher, AES-auth tag-SIV also
//! removes many of the "sharp edges" of AES-auth tag, providing significantly better
//! security bounds while simultaneously eliminating the most catastrophic risks
//! of nonce reuse that exist in AES-GCM.
//! of nonce reuse that exist in AES-auth tag.
//!
//! Decryption performance is equivalent to AES-GCM.
//! Decryption performance is equivalent to AES-auth tag.
//! Encryption is marginally slower.
//!
//! See also:
//!
//! - [Adam Langley: AES-GCM-SIV][5]
//! - [Adam Langley: AES-auth tag-SIV][5]
//! - [Coda Hale: Towards A Safer Footgun][6]
//!
//! ## Performance Notes
//!
//! By default this crate will use software implementations of both AES and
//! the POLYVAL universal hash function.
//!
//! When targeting modern x86/x86_64 CPUs, use the following `RUSTFLAGS` to
//! take advantage of high performance AES-NI and CLMUL CPU intrinsics:
//!
//! ```text
//! RUSTFLAGS="-Ctarget-cpu=sandybridge -Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3"
//! ```
//!
//! ## Security Warning
//!
//! No security audits of this crate have ever been performed.
Expand All @@ -51,23 +39,22 @@
//!
//! Simple usage (allocating, no associated data):
//!
//! ```
//! use aes_gcm_siv::{Aes256GcmSiv, Key, Nonce}; // Or `Aes128GcmSiv`
//! use aes_gcm_siv::aead::{Aead, KeyInit};
//!
//! let key = Key::<Aes256GcmSiv>::from_slice(b"an example very very secret key.");
//! let cipher = Aes256GcmSiv::new(key);
#![cfg_attr(all(feature = "getrandom", feature = "std"), doc = "```")]
#![cfg_attr(not(all(feature = "getrandom", feature = "std")), doc = "```ignore")]
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use aes_gcm_siv::{
//! aead::{Aead, KeyInit, OsRng},
//! Aes256GcmSiv, Nonce // Or `Aes128GcmSiv`
//! };
//!
//! let key = Aes256GcmSiv::generate_key(&mut OsRng);
//! let cipher = Aes256GcmSiv::new(&key);
//! let nonce = Nonce::from_slice(b"unique nonce"); // 96-bits; unique per message
//!
//! let ciphertext = cipher.encrypt(nonce, b"plaintext message".as_ref())
//! .expect("encryption failure!"); // NOTE: handle this error to avoid panics!
//!
//!
//! let plaintext = cipher.decrypt(nonce, ciphertext.as_ref())
//! .expect("decryption failure!"); // NOTE: handle this error to avoid panics!
//!
//! let ciphertext = cipher.encrypt(nonce, b"plaintext message".as_ref())?;
//! let plaintext = cipher.decrypt(nonce, ciphertext.as_ref())?;
//! assert_eq!(&plaintext, b"plaintext message");
//! # Ok(())
//! # }
//! ```
//!
//! ## In-place Usage (eliminates `alloc` requirement)
Expand All @@ -85,34 +72,41 @@
//! which can then be passed as the `buffer` parameter to the in-place encrypt
//! and decrypt methods:
//!
//! ```
//! # #[cfg(feature = "heapless")]
//! # {
//! use aes_gcm_siv::{Aes256GcmSiv, Key, Nonce}; // Or `Aes128GcmSiv`
//! use aes_gcm_siv::aead::{AeadInPlace, KeyInit};
//! use aes_gcm_siv::aead::heapless::Vec;
//!
//! let key = Key::<Aes256GcmSiv>::from_slice(b"an example very very secret key.");
//! let cipher = Aes256GcmSiv::new(key);
//!
#![cfg_attr(
all(feature = "getrandom", feature = "heapless", feature = "std"),
doc = "```"
)]
#![cfg_attr(
not(all(feature = "getrandom", feature = "heapless", feature = "std")),
doc = "```ignore"
)]
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use aes_gcm_siv::{
//! aead::{AeadInPlace, KeyInit, OsRng, heapless::Vec},
//! Aes256GcmSiv, Nonce, // Or `Aes128GcmSiv`
//! };
//!
//! let key = Aes256GcmSiv::generate_key(&mut OsRng);
//! let cipher = Aes256GcmSiv::new(&key);
//! let nonce = Nonce::from_slice(b"unique nonce"); // 96-bits; unique per message
//!
//! let mut buffer: Vec<u8, 128> = Vec::new();
//! let mut buffer: Vec<u8, 128> = Vec::new(); // Note: buffer needs 16-bytes overhead for auth tag tag
//! buffer.extend_from_slice(b"plaintext message");
//!
//! // Encrypt `buffer` in-place, replacing the plaintext contents with ciphertext
//! cipher.encrypt_in_place(nonce, b"", &mut buffer).expect("encryption failure!");
//! cipher.encrypt_in_place(nonce, b"", &mut buffer)?;
//!
//! // `buffer` now contains the message ciphertext
//! assert_ne!(&buffer, b"plaintext message");
//!
//! // Decrypt `buffer` in-place, replacing its ciphertext context with the original plaintext
//! cipher.decrypt_in_place(nonce, b"", &mut buffer).expect("decryption failure!");
//! cipher.decrypt_in_place(nonce, b"", &mut buffer)?;
//! assert_eq!(&buffer, b"plaintext message");
//! # Ok(())
//! # }
//! ```
//!
//! [1]: https://en.wikipedia.org/wiki/AES-GCM-SIV
//! [1]: https://en.wikipedia.org/wiki/AES-auth tag-SIV
//! [2]: https://tools.ietf.org/html/rfc8452
//! [3]: https://en.wikipedia.org/wiki/Authenticated_encryption
//! [4]: https://github.com/miscreant/meta/wiki/Nonce-Reuse-Misuse-Resistance
Expand Down Expand Up @@ -150,27 +144,27 @@ pub const P_MAX: u64 = 1 << 36;
/// Maximum length of ciphertext (from RFC 8452 Section 6)
pub const C_MAX: u64 = (1 << 36) + 16;

/// AES-GCM-SIV nonces
/// AES-auth tag-SIV nonces
pub type Nonce = GenericArray<u8, U12>;

/// AES-GCM-SIV tags
/// AES-auth tag-SIV tags
pub type Tag = GenericArray<u8, U16>;

/// AES-GCM-SIV with a 128-bit key
/// AES-auth tag-SIV with a 128-bit key
#[cfg(feature = "aes")]
pub type Aes128GcmSiv = AesGcmSiv<Aes128>;

/// AES-GCM-SIV with a 256-bit key
/// AES-auth tag-SIV with a 256-bit key
#[cfg(feature = "aes")]
pub type Aes256GcmSiv = AesGcmSiv<Aes256>;

/// Counter mode with a 32-bit little endian counter.
type Ctr32LE<Aes> = ctr::CtrCore<Aes, ctr::flavors::Ctr32LE>;

/// AES-GCM-SIV: Misuse-Resistant Authenticated Encryption Cipher (RFC 8452)
/// AES-auth tag-SIV: Misuse-Resistant Authenticated Encryption Cipher (RFC 8452)
#[derive(Clone)]
pub struct AesGcmSiv<Aes> {
/// Key generating key used to derive AES-GCM-SIV subkeys
/// Key generating key used to derive AES-auth tag-SIV subkeys
key_generating_key: Aes,
}

Expand Down Expand Up @@ -239,7 +233,7 @@ where
}
}

/// AES-GCM-SIV: Misuse-Resistant Authenticated Encryption Cipher (RFC 8452)
/// AES-auth tag-SIV: Misuse-Resistant Authenticated Encryption Cipher (RFC 8452)
struct Cipher<Aes>
where
Aes: BlockCipher<BlockSize = U16> + BlockEncrypt,
Expand All @@ -258,7 +252,7 @@ impl<Aes> Cipher<Aes>
where
Aes: BlockCipher<BlockSize = U16> + BlockEncrypt + KeyInit,
{
/// Initialize AES-GCM-SIV, deriving per-nonce message-authentication and
/// Initialize AES-auth tag-SIV, deriving per-nonce message-authentication and
/// message-encryption keys.
pub(crate) fn new(key_generating_key: &Aes, nonce: &Nonce) -> Self {
let mut mac_key = polyval::Key::default();
Expand Down
4 changes: 2 additions & 2 deletions aes-gcm-siv/tests/aes128gcmsiv.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! AES-128-GCM-SIV tests
//! AES-128-auth tag-SIV tests

#[macro_use]
mod common;
Expand All @@ -7,7 +7,7 @@ use self::common::TestVector;
use aes_gcm_siv::aead::{generic_array::GenericArray, Aead, KeyInit, Payload};
use aes_gcm_siv::Aes128GcmSiv;

/// Test vectors from RFC8452 Appendix C.1: AEAD_AES_128_GCM_SIV
/// Test vectors from RFC8452 Appendix C.1: AEAD_AES_128_auth tag_SIV
/// <https://tools.ietf.org/html/rfc8452#appendix-C.1>
const TEST_VECTORS: &[TestVector<[u8; 16]>] = &[
TestVector {
Expand Down
4 changes: 2 additions & 2 deletions aes-gcm-siv/tests/aes256gcmsiv.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! AES-256-GCM-SIV tests
//! AES-256-auth tag-SIV tests

#[macro_use]
mod common;
Expand All @@ -7,7 +7,7 @@ use self::common::TestVector;
use aes_gcm_siv::aead::{generic_array::GenericArray, Aead, KeyInit, Payload};
use aes_gcm_siv::Aes256GcmSiv;

/// Test vectors from RFC8452 Appendix C.2. AEAD_AES_256_GCM_SIV
/// Test vectors from RFC8452 Appendix C.2. AEAD_AES_256_auth tag_SIV
/// <https://tools.ietf.org/html/rfc8452#appendix-C.2>
const TEST_VECTORS: &[TestVector<[u8; 32]>] = &[
TestVector {
Expand Down
2 changes: 1 addition & 1 deletion aes-gcm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ aead = { version = "0.5", features = ["dev"], default-features = false }
hex-literal = "0.3"

[features]
default = ["aes", "alloc"]
default = ["aes", "alloc", "getrandom"]
std = ["aead/std", "alloc"]
alloc = ["aead/alloc"]
getrandom = ["aead/getrandom"]
Expand Down
83 changes: 40 additions & 43 deletions aes-gcm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
//! AES-GCM: [Authenticated Encryption and Associated Data (AEAD)][1] cipher
//! AES-auth tag: [Authenticated Encryption and Associated Data (AEAD)][1] cipher
//! based on AES in [Galois/Counter Mode][2].
//!
//! ## Performance Notes
//!
//! By default this crate will use software implementations of both AES and
//! the POLYVAL universal hash function.
//!
//! When targeting modern x86/x86_64 CPUs, use the following `RUSTFLAGS` to
//! take advantage of high performance AES-NI and CLMUL CPU intrinsics:
//!
//! ```text
//! RUSTFLAGS="-Ctarget-cpu=sandybridge -Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3"
//! ```
//!
//! ## Security Notes
//!
//! This crate has received one [security audit by NCC Group][3], with no significant
Expand All @@ -31,22 +19,22 @@
//!
//! Simple usage (allocating, no associated data):
//!
//! ```
//! use aes_gcm::{Aes256Gcm, Key, Nonce}; // Or `Aes128Gcm`
//! use aes_gcm::aead::{Aead, KeyInit};
//!
//! let key = Key::<Aes256Gcm>::from_slice(b"an example very very secret key.");
//! let cipher = Aes256Gcm::new(key);
#![cfg_attr(all(feature = "getrandom", feature = "std"), doc = "```")]
#![cfg_attr(not(all(feature = "getrandom", feature = "std")), doc = "```ignore")]
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use aes_gcm::{
//! aead::{Aead, KeyInit, OsRng},
//! Aes256Gcm, Nonce // Or `Aes128Gcm`
//! };
//!
//! let key = Aes256Gcm::generate_key(&mut OsRng);
//! let cipher = Aes256Gcm::new(&key);
//! let nonce = Nonce::from_slice(b"unique nonce"); // 96-bits; unique per message
//!
//! let ciphertext = cipher.encrypt(nonce, b"plaintext message".as_ref())
//! .expect("encryption failure!"); // NOTE: handle this error to avoid panics!
//!
//! let plaintext = cipher.decrypt(nonce, ciphertext.as_ref())
//! .expect("decryption failure!"); // NOTE: handle this error to avoid panics!
//!
//! let ciphertext = cipher.encrypt(nonce, b"plaintext message".as_ref())?;
//! let plaintext = cipher.decrypt(nonce, ciphertext.as_ref())?;
//! assert_eq!(&plaintext, b"plaintext message");
//! # Ok(())
//! # }
//! ```
//!
//! ## In-place Usage (eliminates `alloc` requirement)
Expand All @@ -64,29 +52,38 @@
//! which can then be passed as the `buffer` parameter to the in-place encrypt
//! and decrypt methods:
//!
#![cfg_attr(feature = "heapless", doc = " ```")]
#![cfg_attr(not(feature = "heapless"), doc = " ```ignore")]
//! use aes_gcm::{Aes256Gcm, Key, Nonce}; // Or `Aes128Gcm`
//! use aes_gcm::aead::{AeadInPlace, KeyInit};
//! use aes_gcm::aead::heapless::Vec;
//!
//! let key = Key::<Aes256Gcm>::from_slice(b"an example very very secret key.");
//! let cipher = Aes256Gcm::new(key);
#![cfg_attr(
all(feature = "getrandom", feature = "heapless", feature = "std"),
doc = "```"
)]
#![cfg_attr(
not(all(feature = "getrandom", feature = "heapless", feature = "std")),
doc = "```ignore"
)]
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use aes_gcm::{
//! aead::{AeadInPlace, KeyInit, OsRng, heapless::Vec},
//! Aes256Gcm, Nonce, // Or `Aes128Gcm`
//! };
//!
//! let key = Aes256Gcm::generate_key(&mut OsRng);
//! let cipher = Aes256Gcm::new(&key);
//! let nonce = Nonce::from_slice(b"unique nonce"); // 96-bits; unique per message
//!
//! let mut buffer: Vec<u8, 128> = Vec::new(); // Buffer needs 16-bytes overhead for GCM tag
//! let mut buffer: Vec<u8, 128> = Vec::new(); // Note: buffer needs 16-bytes overhead for auth tag tag
//! buffer.extend_from_slice(b"plaintext message");
//!
//! // Encrypt `buffer` in-place, replacing the plaintext contents with ciphertext
//! cipher.encrypt_in_place(nonce, b"", &mut buffer).expect("encryption failure!");
//! cipher.encrypt_in_place(nonce, b"", &mut buffer)?;
//!
//! // `buffer` now contains the message ciphertext
//! assert_ne!(&buffer, b"plaintext message");
//!
//! // Decrypt `buffer` in-place, replacing its ciphertext context with the original plaintext
//! cipher.decrypt_in_place(nonce, b"", &mut buffer).expect("decryption failure!");
//! cipher.decrypt_in_place(nonce, b"", &mut buffer)?;
//! assert_eq!(&buffer, b"plaintext message");
//! # Ok(())
//! # }
//! ```
//!
//! [1]: https://en.wikipedia.org/wiki/Authenticated_encryption
Expand Down Expand Up @@ -131,18 +128,18 @@ pub const P_MAX: u64 = 1 << 36;
/// Maximum length of ciphertext
pub const C_MAX: u64 = (1 << 36) + 16;

/// AES-GCM nonces
/// AES-auth tag nonces
pub type Nonce<NonceSize> = GenericArray<u8, NonceSize>;

/// AES-GCM tags
/// AES-auth tag tags
pub type Tag = GenericArray<u8, U16>;

/// AES-GCM with a 128-bit key and 96-bit nonce
/// AES-auth tag with a 128-bit key and 96-bit nonce
#[cfg(feature = "aes")]
#[cfg_attr(docsrs, doc(cfg(feature = "aes")))]
pub type Aes128Gcm = AesGcm<Aes128, U12>;

/// AES-GCM with a 256-bit key and 96-bit nonce
/// AES-auth tag with a 256-bit key and 96-bit nonce
#[cfg(feature = "aes")]
#[cfg_attr(docsrs, doc(cfg(feature = "aes")))]
pub type Aes256Gcm = AesGcm<Aes256, U12>;
Expand All @@ -153,15 +150,15 @@ type Block = GenericArray<u8, U16>;
/// Counter mode with a 32-bit big endian counter.
type Ctr32BE<Aes> = ctr::CtrCore<Aes, ctr::flavors::Ctr32BE>;

/// AES-GCM: generic over an underlying AES implementation and nonce size.
/// AES-auth tag: generic over an underlying AES implementation and nonce size.
///
/// This type is generic to support substituting alternative AES implementations
/// (e.g. embedded hardware implementations)
///
/// It is NOT intended to be instantiated with any block cipher besides AES!
/// Doing so runs the risk of unintended cryptographic properties!
///
/// The `N` generic parameter can be used to instantiate AES-GCM with other
/// The `N` generic parameter can be used to instantiate AES-auth tag with other
/// nonce sizes, however it's recommended to use it with `typenum::U12`,
/// the default of 96-bits.
///
Expand Down
2 changes: 1 addition & 1 deletion aes-gcm/tests/aes128gcm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! AES-128-GCM tests
//! AES-128-auth tag tests

#[macro_use]
mod common;
Expand Down
2 changes: 1 addition & 1 deletion aes-gcm/tests/aes256gcm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! AES-256-GCM tests
//! AES-256-auth tag tests

#[macro_use]
mod common;
Expand Down
Loading