diff --git a/.github/workflows/aes-siv.yml b/.github/workflows/aes-siv.yml index 5cf6c479..ce48d0f0 100644 --- a/.github/workflows/aes-siv.yml +++ b/.github/workflows/aes-siv.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: rust: - - 1.51.0 # MSRV + - 1.56.0 # MSRV - stable target: - armv7a-none-eabi @@ -43,7 +43,7 @@ jobs: strategy: matrix: rust: - - 1.51.0 # MSRV + - 1.56.0 # MSRV - stable steps: - uses: actions/checkout@v1 diff --git a/Cargo.lock b/Cargo.lock index 3f0d1cec..57ccce5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,16 +67,16 @@ dependencies = [ [[package]] name = "aes-siv" -version = "0.6.2" +version = "0.7.0-pre" dependencies = [ "aead", - "aes 0.7.5", + "aes 0.8.1", "blobby", - "cipher 0.3.0", - "cmac", - "crypto-mac", - "ctr 0.8.0", + "cipher 0.4.3", + "cmac 0.7.1", + "ctr 0.9.1", "dbl", + "digest", "hex-literal 0.3.4", "pmac", "zeroize", @@ -139,6 +139,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "847495c209977a90e8aad588b959d0ca9f5dc228096d29a6bd3defd53f35eaec" +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + [[package]] name = "byteorder" version = "1.4.3" @@ -147,7 +156,7 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "ccm" -version = "0.4.4" +version = "0.5.0-pre" dependencies = [ "aead", "aes 0.8.1", @@ -215,6 +224,17 @@ dependencies = [ "dbl", ] +[[package]] +name = "cmac" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "606383658416244b8dc4b36f864ec1f86cb922b95c41a908fd07aeb01cad06fa" +dependencies = [ + "cipher 0.4.3", + "dbl", + "digest", +] + [[package]] name = "cortex-m" version = "0.7.5" @@ -307,6 +327,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "eax" version = "0.4.1" @@ -314,7 +345,7 @@ dependencies = [ "aead", "aes 0.7.5", "cipher 0.3.0", - "cmac", + "cmac 0.6.0", "ctr 0.8.0", "subtle", ] @@ -500,12 +531,13 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "pmac" -version = "0.6.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d8c6aafab3b7131a8be27ae259e545c20c067163c39897419686684de0e013" +checksum = "fa22f777eff0306a722b57833475f6ade9a8307f069358e8e808b2655d6de407" dependencies = [ - "crypto-mac", + "cipher 0.4.3", "dbl", + "digest", ] [[package]] diff --git a/aes-siv/Cargo.toml b/aes-siv/Cargo.toml index 26e03697..0eba5928 100644 --- a/aes-siv/Cargo.toml +++ b/aes-siv/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aes-siv" -version = "0.6.2" +version = "0.7.0-pre" description = """ Pure Rust implementation of the AES-SIV Misuse-Resistant Authenticated Encryption Cipher (RFC 5297) with optional architecture-specific @@ -17,15 +17,17 @@ categories = ["cryptography", "no-std"] [dependencies] aead = "0.4" -aes = "0.7" -cipher = "0.3" -cmac = "0.6" -crypto-mac = "0.11" -ctr = "0.8" +aes = "0.8" +cipher = "0.4" +cmac = "0.7" +ctr = "0.9" dbl = "0.3" -pmac = { version = "0.6", optional = true } +digest = { version = "0.10", features = ["mac"] } zeroize = { version = "1", default-features = false } +# optional dependencies +pmac = { version = "0.7", optional = true } + [dev-dependencies] blobby = "0.3" hex-literal = "0.3" diff --git a/aes-siv/README.md b/aes-siv/README.md index b853abbf..34139e68 100644 --- a/aes-siv/README.md +++ b/aes-siv/README.md @@ -43,7 +43,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/aes-siv/badge.svg [docs-link]: https://docs.rs/aes-siv/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.49+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [codecov-image]: https://codecov.io/gh/RustCrypto/AEADs/branch/master/graph/badge.svg [codecov-link]: https://codecov.io/gh/RustCrypto/AEADs [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg diff --git a/aes-siv/src/lib.rs b/aes-siv/src/lib.rs index 76ee3a23..5ae39ed5 100644 --- a/aes-siv/src/lib.rs +++ b/aes-siv/src/lib.rs @@ -93,17 +93,16 @@ use aead::{ AeadCore, AeadInPlace, Buffer, Error, NewAead, }; use aes::{Aes128, Aes256}; -use cipher::{NewCipher, StreamCipher}; +use cipher::{BlockCipher, BlockEncryptMut, KeyInit, KeySizeUser}; use cmac::Cmac; use core::{marker::PhantomData, ops::Add}; -use crypto_mac::{Mac, NewMac}; -use ctr::Ctr128BE; +use digest::{FixedOutputReset, Mac}; #[cfg(feature = "pmac")] use pmac::Pmac; /// Size of an AES-SIV key given a particular cipher -pub type KeySize = <::KeySize as Add>::Output; +pub type KeySize = <::KeySize as Add>::Output; /// AES-SIV keys pub type Key = GenericArray; @@ -119,9 +118,9 @@ pub type Tag = GenericArray; /// which accepts a key, nonce, and associated data when encrypting/decrypting. pub struct SivAead where - C: NewCipher + StreamCipher, - M: Mac, - ::KeySize: Add, + C: BlockCipher + BlockEncryptMut + KeyInit + KeySizeUser, + M: Mac + FixedOutputReset + KeyInit, + ::KeySize: Add, KeySize: ArrayLength, { key: GenericArray>, @@ -129,12 +128,12 @@ where } /// SIV AEAD modes based on CMAC -pub type CmacSivAead = SivAead, Cmac>; +pub type CmacSivAead = SivAead>; /// SIV AEAD modes based on PMAC #[cfg(feature = "pmac")] #[cfg_attr(docsrs, doc(cfg(feature = "pmac")))] -pub type PmacSivAead = SivAead, Pmac>; +pub type PmacSivAead = SivAead>; /// AES-CMAC-SIV in AEAD mode with 256-bit key size (128-bit security) pub type Aes128SivAead = CmacSivAead; @@ -152,9 +151,9 @@ pub type Aes128PmacSivAead = PmacSivAead; #[cfg_attr(docsrs, doc(cfg(feature = "pmac")))] pub type Aes256PmacSivAead = PmacSivAead; -impl NewAead for SivAead, M> +impl NewAead for SivAead where - M: Mac, + M: Mac + FixedOutputReset + KeyInit, { type KeySize = U32; @@ -166,9 +165,9 @@ where } } -impl NewAead for SivAead, M> +impl NewAead for SivAead where - M: Mac, + M: Mac + FixedOutputReset + KeyInit, { type KeySize = U64; @@ -182,9 +181,9 @@ where impl AeadCore for SivAead where - C: NewCipher + StreamCipher, - M: Mac + NewMac, - ::KeySize: Add, + C: BlockCipher + BlockEncryptMut + KeyInit + KeySizeUser, + M: Mac + FixedOutputReset + KeyInit, + ::KeySize: Add, KeySize: ArrayLength, { // "If the nonce is random, it SHOULD be at least 128 bits in length" @@ -197,9 +196,9 @@ where impl AeadInPlace for SivAead where - C: NewCipher + StreamCipher, - M: Mac + NewMac, - ::KeySize: Add, + C: BlockCipher + BlockEncryptMut + KeyInit + KeySizeUser, + M: Mac + FixedOutputReset + KeyInit, + ::KeySize: Add, KeySize: ArrayLength, { fn encrypt_in_place( diff --git a/aes-siv/src/siv.rs b/aes-siv/src/siv.rs index 567e52db..616e7753 100644 --- a/aes-siv/src/siv.rs +++ b/aes-siv/src/siv.rs @@ -10,12 +10,13 @@ use aead::generic_array::{ }; use aead::{Buffer, Error}; use aes::{Aes128, Aes256}; -use cipher::{NewCipher, StreamCipher}; +use cipher::{ + BlockCipher, BlockEncryptMut, InnerIvInit, Key, KeyInit, KeySizeUser, StreamCipherCore, +}; use cmac::Cmac; use core::ops::Add; -use crypto_mac::{Mac, NewMac}; -use ctr::Ctr128BE; use dbl::Dbl; +use digest::{CtOutput, FixedOutputReset, Mac}; use zeroize::Zeroize; #[cfg(feature = "alloc")] @@ -30,24 +31,27 @@ pub const IV_SIZE: usize = 16; /// Maximum number of header items on the encrypted message pub const MAX_HEADERS: usize = 126; +/// Counter mode with a 128-bit big endian counter. +type Ctr128BE = ctr::CtrCore; + /// Synthetic Initialization Vector (SIV) mode, providing misuse-resistant /// authenticated encryption (MRAE). pub struct Siv where - C: NewCipher + StreamCipher, + C: BlockCipher + BlockEncryptMut + KeyInit + KeySizeUser, M: Mac, { - encryption_key: GenericArray::KeySize>, + encryption_key: Key, mac: M, } /// SIV modes based on CMAC -pub type CmacSiv = Siv, Cmac>; +pub type CmacSiv = Siv>; /// SIV modes based on PMAC #[cfg(feature = "pmac")] #[cfg_attr(docsrs, doc(cfg(feature = "pmac")))] -pub type PmacSiv = Siv, Pmac>; +pub type PmacSiv = Siv>; /// AES-CMAC-SIV with a 128-bit key pub type Aes128Siv = CmacSiv; @@ -67,18 +71,18 @@ pub type Aes256PmacSiv = PmacSiv; impl Siv where - C: NewCipher + StreamCipher, - M: Mac + NewMac, - ::KeySize: Add, + C: BlockCipher + BlockEncryptMut + KeyInit + KeySizeUser, + M: Mac + FixedOutputReset + KeyInit, + ::KeySize: Add, KeySize: ArrayLength, { /// Create a new AES-SIV instance pub fn new(key: GenericArray>) -> Self { // Use the first half of the key as the encryption key - let encryption_key = GenericArray::clone_from_slice(&key[M::KeySize::to_usize()..]); + let encryption_key = GenericArray::clone_from_slice(&key[M::key_size()..]); // Use the second half of the key as the MAC key - let mac = M::new(GenericArray::from_slice(&key[..M::KeySize::to_usize()])); + let mac = ::new(GenericArray::from_slice(&key[..M::KeySize::to_usize()])); Self { encryption_key, @@ -89,8 +93,8 @@ where impl Siv where - C: NewCipher + StreamCipher, - M: Mac + NewMac, + C: BlockCipher + BlockEncryptMut + KeyInit + KeySizeUser, + M: Mac + FixedOutputReset + KeyInit, { /// Encrypt the given plaintext, allocating and returning a `Vec` for /// the ciphertext. @@ -220,8 +224,8 @@ where self.xor_with_keystream(*siv_tag, ciphertext); let computed_siv_tag = s2v(&mut self.mac, headers, ciphertext)?; - // Note: constant-time comparison of `crypto_mac::Output` values - if crypto_mac::Output::::new(computed_siv_tag) == crypto_mac::Output::new(*siv_tag) { + // Note: `CtOutput` provides constant-time equality + if CtOutput::::new(computed_siv_tag) == CtOutput::new(*siv_tag) { Ok(()) } else { // Re-encrypt the decrypted plaintext to avoid revealing it @@ -238,13 +242,14 @@ where iv[8] &= 0x7f; iv[12] &= 0x7f; - C::new(GenericArray::from_slice(&self.encryption_key), &iv).apply_keystream(msg); + Ctr128BE::::inner_iv_init(C::new(&self.encryption_key), &iv) + .apply_keystream_partial(msg.into()); } } impl Drop for Siv where - C: NewCipher + StreamCipher, + C: BlockCipher + BlockEncryptMut + KeyInit + KeySizeUser, M: Mac, { fn drop(&mut self) { @@ -263,11 +268,11 @@ where /// initialization vector (for AES-CTR encryption) and MAC. fn s2v(mac: &mut M, headers: I, message: &[u8]) -> Result where - M: Mac, + M: Mac + FixedOutputReset, I: IntoIterator, T: AsRef<[u8]>, { - mac.update(&Tag::default()); + Mac::update(mac, &Tag::default()); let mut state = mac.finalize_reset().into_bytes(); for (i, header) in headers.into_iter().enumerate() { @@ -276,7 +281,7 @@ where } state = state.dbl(); - mac.update(header.as_ref()); + Mac::update(mac, header.as_ref()); let code = mac.finalize_reset().into_bytes(); xor_in_place(&mut state, &code); } @@ -284,7 +289,7 @@ where if message.len() >= IV_SIZE { let n = message.len().checked_sub(IV_SIZE).unwrap(); - mac.update(&message[..n]); + Mac::update(mac, &message[..n]); xor_in_place(&mut state, &message[n..]); } else { state = state.dbl(); @@ -292,7 +297,7 @@ where state[message.len()] ^= 0x80; }; - mac.update(state.as_ref()); + Mac::update(mac, state.as_ref()); Ok(mac.finalize_reset().into_bytes()) }