diff --git a/.github/workflows/hmac.yml b/.github/workflows/hmac.yml index 9a2dc56..d058bef 100644 --- a/.github/workflows/hmac.yml +++ b/.github/workflows/hmac.yml @@ -53,4 +53,5 @@ jobs: toolchain: ${{ matrix.rust }} override: true - run: cargo test --release --no-default-features + - run: cargo test --release --features reset - run: cargo test --release diff --git a/.github/workflows/pmac.yml b/.github/workflows/pmac.yml index 26c862f..d33a198 100644 --- a/.github/workflows/pmac.yml +++ b/.github/workflows/pmac.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.51.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -42,7 +42,7 @@ jobs: strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.51.0 # MSRV - stable steps: - uses: actions/checkout@v1 diff --git a/Cargo.lock b/Cargo.lock index 88497db..f59fa37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,15 +1,15 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +version = "0.8.0" +source = "git+https://github.com/RustCrypto/block-ciphers/?branch=cipher_v0.4#e048e5ac8512d7019e2226296bd774c50dc40ee3" dependencies = [ "cfg-if", "cipher", "cpufeatures", - "opaque-debug", ] [[package]] @@ -20,26 +20,12 @@ checksum = "fc52553543ecb104069b0ff9e0fcc5c739ad16202935528a112d974e8f1a4ee8" [[package]] name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +version = "0.10.0" +source = "git+https://github.com/RustCrypto/utils?branch=pad_error#24b145e4b2935911e139d70769c4ff1573845b88" dependencies = [ - "block-padding", "generic-array", ] -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "cfg-if" version = "1.0.0" @@ -48,20 +34,22 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +version = "0.4.0" +source = "git+https://github.com/RustCrypto/traits/?branch=new_traits#077c141b57f5284709756500209f432aa2d450a5" dependencies = [ + "crypto-common", "generic-array", + "inout", ] [[package]] name = "cmac" -version = "0.6.0" +version = "0.7.0" dependencies = [ "aes", - "crypto-mac", + "cipher", "dbl", + "digest", "hex-literal", "kuznyechik", "magma", @@ -69,31 +57,28 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cc47dfc37fe9455a291c6aef98ac51376b771fa9779aa7a2f9a86f0700a7a20" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" dependencies = [ "libc", ] [[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +name = "crypto-common" +version = "0.1.0" +source = "git+https://github.com/RustCrypto/traits/?branch=new_traits#077c141b57f5284709756500209f432aa2d450a5" dependencies = [ - "blobby", - "cipher", "generic-array", - "subtle", ] [[package]] name = "daa" -version = "0.5.0" +version = "0.6.0" dependencies = [ - "crypto-mac", "des", + "digest", + "hex-literal", ] [[package]] @@ -107,22 +92,22 @@ dependencies = [ [[package]] name = "des" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac41dd49fb554432020d52c875fc290e110113f864c6b1b525cd62c7e7747a5d" +version = "0.8.0" +source = "git+https://github.com/RustCrypto/block-ciphers/?branch=cipher_v0.4#e048e5ac8512d7019e2226296bd774c50dc40ee3" dependencies = [ - "byteorder", "cipher", - "opaque-debug", ] [[package]] name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +version = "0.10.0" +source = "git+https://github.com/RustCrypto/traits/?branch=new_traits#077c141b57f5284709756500209f432aa2d450a5" dependencies = [ + "blobby", + "block-buffer", + "crypto-common", "generic-array", + "subtle", ] [[package]] @@ -156,64 +141,62 @@ dependencies = [ [[package]] name = "hmac" -version = "0.11.0" +version = "0.12.0" dependencies = [ - "crypto-mac", "digest", "md-5", + "sha-1", "sha2", "streebog", ] +[[package]] +name = "inout" +version = "0.1.0" +source = "git+https://github.com/RustCrypto/utils?branch=pad_error#24b145e4b2935911e139d70769c4ff1573845b88" +dependencies = [ + "generic-array", +] + [[package]] name = "kuznyechik" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a4e0a85306cf7cdcd497111b9ecd8df4da5290bacd3cc2f426ce3fb2c0a327e" +version = "0.8.0" +source = "git+https://github.com/RustCrypto/block-ciphers/?branch=cipher_v0.4#e048e5ac8512d7019e2226296bd774c50dc40ee3" dependencies = [ "cipher", ] [[package]] name = "libc" -version = "0.2.101" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" +checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" [[package]] name = "magma" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53792c7fca348c3d880c5ab2b0a2378a28edca57d080feabc4b60b4633dff91b" +version = "0.8.0" +source = "git+https://github.com/RustCrypto/block-ciphers/?branch=cipher_v0.4#e048e5ac8512d7019e2226296bd774c50dc40ee3" dependencies = [ "cipher", - "opaque-debug", ] [[package]] name = "md-5" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" +version = "0.10.0" +source = "git+https://github.com/RustCrypto/hashes/?branch=digest/v0.10.0-pre#d89101dfbd930b6cd08d60f15e057592efc21b7c" dependencies = [ - "block-buffer", "digest", - "opaque-debug", ] -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - [[package]] name = "pmac" -version = "0.6.0" +version = "0.7.0" dependencies = [ "aes", - "crypto-mac", + "cipher", "dbl", + "digest", + "hex-literal", ] [[package]] @@ -222,41 +205,45 @@ version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" +[[package]] +name = "sha-1" +version = "0.10.0" +source = "git+https://github.com/RustCrypto/hashes/?branch=digest/v0.10.0-pre#d89101dfbd930b6cd08d60f15e057592efc21b7c" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +version = "0.10.0" +source = "git+https://github.com/RustCrypto/hashes/?branch=digest/v0.10.0-pre#d89101dfbd930b6cd08d60f15e057592efc21b7c" dependencies = [ - "block-buffer", "cfg-if", "cpufeatures", "digest", - "opaque-debug", ] [[package]] name = "streebog" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a21c1a3920381f27c666a81ad2481abc005900ac871a80b479e1869d54e753" +version = "0.10.0" +source = "git+https://github.com/RustCrypto/hashes/?branch=digest/v0.10.0-pre#d89101dfbd930b6cd08d60f15e057592efc21b7c" dependencies = [ - "block-buffer", "digest", - "opaque-debug", ] [[package]] name = "subtle" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "typenum" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] name = "version_check" diff --git a/Cargo.toml b/Cargo.toml index dab6e4b..4b7d7f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,17 @@ members = [ "hmac", "pmac", ] + +[patch.crates-io] +digest = { git = "https://github.com/RustCrypto/traits/", branch = "new_traits" } +cipher = { git = "https://github.com/RustCrypto/traits/", branch = "new_traits" } +block-buffer = { git = "https://github.com/RustCrypto/utils", branch = "pad_error" } +inout = { git = "https://github.com/RustCrypto/utils", branch = "pad_error" } +aes = { git = "https://github.com/RustCrypto/block-ciphers/", branch = "cipher_v0.4" } +kuznyechik = { git = "https://github.com/RustCrypto/block-ciphers/", branch = "cipher_v0.4" } +magma = { git = "https://github.com/RustCrypto/block-ciphers/", branch = "cipher_v0.4" } +des = { git = "https://github.com/RustCrypto/block-ciphers/", branch = "cipher_v0.4" } +md-5 = { git = "https://github.com/RustCrypto/hashes/", branch = "digest/v0.10.0-pre" } +sha-1 = { git = "https://github.com/RustCrypto/hashes/", branch = "digest/v0.10.0-pre" } +sha2 = { git = "https://github.com/RustCrypto/hashes/", branch = "digest/v0.10.0-pre" } +streebog = { git = "https://github.com/RustCrypto/hashes/", branch = "digest/v0.10.0-pre" } diff --git a/README.md b/README.md index d5ef9bd..ba6d75e 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ -# RustCrypto: Message Authentication Codes ![Rust Version][rustc-image] [![Project Chat][chat-image]][chat-link] [![dependency status][deps-image]][deps-link] +# RustCrypto: Message Authentication Codes [![Project Chat][chat-image]][chat-link] [![dependency status][deps-image]][deps-link] Collection of [Message Authentication Code][1] (MAC) algorithms written in pure Rust. ## Crates -| Name | Algorithm | Crates.io | Documentation | Build Status | -|--------|-----------|---------------|---------------|--------------| -| `cmac` | [CMAC] | [![crates.io](https://img.shields.io/crates/v/cmac.svg)](https://crates.io/crates/cmac) | [![Documentation](https://docs.rs/cmac/badge.svg)](https://docs.rs/cmac) | [![Build](https://github.com/RustCrypto/MACs/workflows/cmac/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/MACs/actions?query=workflow:cmac+branch:master) -| `daa` | [DAA] | [![crates.io](https://img.shields.io/crates/v/daa.svg)](https://crates.io/crates/daa) | [![Documentation](https://docs.rs/daa/badge.svg)](https://docs.rs/daa) | [![Build](https://github.com/RustCrypto/MACs/workflows/daa/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/MACs/actions?query=workflow:daa+branch:master) -| `hmac` | [HMAC] | [![crates.io](https://img.shields.io/crates/v/hmac.svg)](https://crates.io/crates/hmac) | [![Documentation](https://docs.rs/hmac/badge.svg)](https://docs.rs/hmac) | [![Build](https://github.com/RustCrypto/MACs/workflows/hmac/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/MACs/actions?query=workflow:hmac+branch:master) -| `pmac` | [PMAC] | [![crates.io](https://img.shields.io/crates/v/pmac.svg)](https://crates.io/crates/pmac) | [![Documentation](https://docs.rs/pmac/badge.svg)](https://docs.rs/pmac) | [![Build](https://github.com/RustCrypto/MACs/workflows/pmac/badge.svg?branch=master&event=push)](https://github.com/RustCrypto/MACs/actions?query=workflow:pmac+branch:master) +| Algorithm | Crate | Crates.io | Documentation | MSRV | +|-----------|--------|---------------|---------------|------| +| [CMAC] | `cmac` | [![crates.io](https://img.shields.io/crates/v/cmac.svg)](https://crates.io/crates/cmac) | [![Documentation](https://docs.rs/cmac/badge.svg)](https://docs.rs/cmac) | ![Minimum Supported Rust Version][msrv-1.41] | +| [DAA] | `daa` | [![crates.io](https://img.shields.io/crates/v/daa.svg)](https://crates.io/crates/daa) | [![Documentation](https://docs.rs/daa/badge.svg)](https://docs.rs/daa) | ![Minimum Supported Rust Version][msrv-1.41] | +| [HMAC] | `hmac` | [![crates.io](https://img.shields.io/crates/v/hmac.svg)](https://crates.io/crates/hmac) | [![Documentation](https://docs.rs/hmac/badge.svg)](https://docs.rs/hmac) | ![Minimum Supported Rust Version][msrv-1.41] | +| [PMAC] | `pmac` | [![crates.io](https://img.shields.io/crates/v/pmac.svg)](https://crates.io/crates/pmac) | [![Documentation](https://docs.rs/pmac/badge.svg)](https://docs.rs/pmac) | ![Minimum Supported Rust Version][msrv-1.41] | ## License @@ -22,16 +22,15 @@ at your option. ### 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 +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. [//]: # (badges) -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260044-MACs [deps-image]: https://deps.rs/repo/github/RustCrypto/MACs/status.svg [deps-link]: https://deps.rs/repo/github/RustCrypto/MACs +[msrv-1.41]: https://img.shields.io/badge/rustc-1.41.0+-blue.svg [//]: # (footnotes) diff --git a/cmac/Cargo.toml b/cmac/Cargo.toml index 3255ef6..fbfa536 100644 --- a/cmac/Cargo.toml +++ b/cmac/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cmac" -version = "0.6.0" +version = "0.7.0" # Also update html_root_url in lib.rs when bumping this description = "Generic implementation of Cipher-based Message Authentication Code" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" @@ -12,15 +12,16 @@ readme = "README.md" edition = "2018" [dependencies] -crypto-mac = { version = "0.11", features = ["cipher"] } +digest = { version = "0.10", features = ["mac"] } +cipher = "0.4" dbl = "0.3" [dev-dependencies] -aes = { version = "0.7", features = ["force-soft"] } # Uses `force-soft` for MSRV 1.41 -crypto-mac = { version = "0.11", features = ["dev"] } +aes = { version = "0.8", features = ["force-soft"] } # Uses `force-soft` for MSRV 1.41 +digest = { version = "0.10", features = ["dev"] } hex-literal = "0.2" -kuznyechik = "0.7" -magma = "0.7" +kuznyechik = "0.8" +magma = "0.8" [features] -std = ["crypto-mac/std"] +std = ["digest/std"] diff --git a/cmac/README.md b/cmac/README.md index 19eaa1d..ca65dc5 100644 --- a/cmac/README.md +++ b/cmac/README.md @@ -5,7 +5,6 @@ ![Apache2/MIT licensed][license-image] ![Rust Version][rustc-image] [![Project Chat][chat-image]][chat-link] -[![Build Status][build-image]][build-link] Pure Rust implementation of the [Cipher-based Message Authentication Code (CMAC)][1]. @@ -48,8 +47,6 @@ dual licensed as above, without any additional terms or conditions. [rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260044-MACs -[build-image]: https://github.com/RustCrypto/MACs/workflows/cmac/badge.svg?branch=master&event=push -[build-link]: https://github.com/RustCrypto/MACs/actions?query=workflow%3Acmac [//]: # (general links) diff --git a/cmac/src/lib.rs b/cmac/src/lib.rs index ca9de16..891a50b 100644 --- a/cmac/src/lib.rs +++ b/cmac/src/lib.rs @@ -8,31 +8,34 @@ //! //! ```rust //! use aes::Aes128; -//! use cmac::{Cmac, Mac, NewMac}; +//! use cmac::{Cmac, Mac}; +//! use hex_literal::hex; //! //! // Create `Mac` trait implementation, namely CMAC-AES128 //! let mut mac = Cmac::::new_from_slice(b"very secret key.").unwrap(); //! mac.update(b"input message"); //! -//! // `result` has type `Output` which is a thin wrapper around array of +//! // `result` has type `CtOutput` which is a thin wrapper around array of //! // bytes for providing constant time equality check //! let result = mac.finalize(); //! // To get underlying array use the `into_bytes` method, but be careful, //! // since incorrect use of the tag value may permit timing attacks which -//! // defeat the security provided by the `Output` wrapper +//! // defeat the security provided by the `CtOutput` wrapper //! let tag_bytes = result.into_bytes(); +//! assert_eq!(tag_bytes[..], hex!("4508cc6ab5e8aea8eb80f135d717d544")[..]); //! ``` //! //! To verify the message: //! //! ```rust //! # use aes::Aes128; -//! # use cmac::{Cmac, Mac, NewMac}; +//! # use cmac::{Cmac, Mac}; +//! # use hex_literal::hex; //! let mut mac = Cmac::::new_from_slice(b"very secret key.").unwrap(); //! //! mac.update(b"input message"); //! -//! # let tag_bytes = mac.clone().finalize().into_bytes(); +//! let tag_bytes = hex!("4508cc6ab5e8aea8eb80f135d717d544").into(); //! // `verify` will return `Ok(())` if tag is correct, `Err(MacError)` otherwise //! mac.verify(&tag_bytes).unwrap(); //! ``` @@ -41,160 +44,176 @@ #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_root_url = "https://docs.rs/cmac/0.7.0" )] #![forbid(unsafe_code)] #![warn(missing_docs, rust_2018_idioms)] -#[cfg(feature = "std")] -extern crate std; +pub use digest; +pub use digest::Mac; -pub use crypto_mac::{self, FromBlockCipher, Mac, NewMac}; +use cipher::{BlockCipher, BlockEncryptMut}; use core::fmt; -use crypto_mac::{ - cipher::{BlockCipher, BlockEncrypt}, +use dbl::Dbl; +use digest::{ + block_buffer::Lazy, + core_api::{Block, Buffer, BufferKindUser, CoreWrapper, FixedOutputCore, UpdateCore}, + crypto_common::{AlgorithmName, BlockSizeUser, InnerInit, InnerUser}, generic_array::{typenum::Unsigned, ArrayLength, GenericArray}, - Output, + MacMarker, Output, OutputSizeUser, Reset, }; -use dbl::Dbl; -type Block = GenericArray; +/// CMAC type which operates over slices. +pub type Cmac = CoreWrapper>; -/// Generic CMAC instance +/// Core CMAC type which operates over blocks. #[derive(Clone)] -pub struct Cmac +pub struct CmacCore where - C: BlockCipher + BlockEncrypt + Clone, - Block: Dbl, + C: BlockCipher + BlockEncryptMut, + Block: Dbl, { cipher: C, - key1: Block, - key2: Block, - buffer: Block, - pos: usize, + key1: Block, + key2: Block, + state: Block, +} + +impl MacMarker for CmacCore +where + C: BlockCipher + BlockEncryptMut, + Block: Dbl, +{ } -impl FromBlockCipher for Cmac +impl InnerUser for CmacCore where - C: BlockCipher + BlockEncrypt + Clone, - Block: Dbl, + C: BlockCipher + BlockEncryptMut, + Block: Dbl, { - type Cipher = C; + type Inner = C; +} + +impl BlockSizeUser for CmacCore +where + C: BlockCipher + BlockEncryptMut, + Block: Dbl, +{ + type BlockSize = C::BlockSize; +} - fn from_cipher(cipher: C) -> Self { +impl OutputSizeUser for CmacCore +where + C: BlockCipher + BlockEncryptMut, + Block: Dbl, +{ + type OutputSize = C::BlockSize; +} + +impl BufferKindUser for CmacCore +where + C: BlockCipher + BlockEncryptMut, + Block: Dbl, +{ + type BufferKind = Lazy; +} + +impl InnerInit for CmacCore +where + C: BlockCipher + BlockEncryptMut, + Block: Dbl, +{ + fn inner_init(mut cipher: C) -> Self { let mut subkey = GenericArray::default(); - cipher.encrypt_block(&mut subkey); + cipher.encrypt_block_mut(&mut subkey); let key1 = subkey.dbl(); let key2 = key1.clone().dbl(); + let state = GenericArray::default(); - Cmac { + Self { cipher, key1, key2, - buffer: Default::default(), - pos: 0, + state, } } } -impl Mac for Cmac +impl UpdateCore for CmacCore where - C: BlockCipher + BlockEncrypt + Clone, - Block: Dbl, + C: BlockCipher + BlockEncryptMut, + Block: Dbl, { - type OutputSize = C::BlockSize; - - #[inline] - fn update(&mut self, mut data: &[u8]) { - let n = C::BlockSize::to_usize(); - - let rem = n - self.pos; - if data.len() >= rem { - let (l, r) = data.split_at(rem); - data = r; - for (a, b) in self.buffer[self.pos..].iter_mut().zip(l) { - *a ^= *b; - } - self.pos = n; - } else { - for (a, b) in self.buffer[self.pos..].iter_mut().zip(data) { - *a ^= *b; - } - self.pos += data.len(); - return; - } - - while data.len() >= n { - self.cipher.encrypt_block(&mut self.buffer); - - let (l, r) = data.split_at(n); - let block = GenericArray::from_slice(l); - data = r; - - xor(&mut self.buffer, block); - } - - if !data.is_empty() { - self.cipher.encrypt_block(&mut self.buffer); - for (a, b) in self.buffer.iter_mut().zip(data) { - *a ^= *b; - } - self.pos = data.len(); + fn update_blocks(&mut self, blocks: &[Block]) { + for block in blocks { + xor(&mut self.state, block); + self.cipher.encrypt_block_mut(&mut self.state); } } +} +impl FixedOutputCore for CmacCore +where + C: BlockCipher + BlockEncryptMut, + Block: Dbl, +{ #[inline] - fn finalize(self) -> Output { - let n = C::BlockSize::to_usize(); - let mut buf = self.buffer.clone(); - if self.pos == n { - xor(&mut buf, &self.key1); + fn finalize_fixed_core(&mut self, buffer: &mut Buffer, out: &mut Output) { + let pos = buffer.get_pos(); + let mut res = buffer.pad_with_zeros(); + if pos == C::BlockSize::USIZE { + xor(&mut res, &self.key1); } else { - xor(&mut buf, &self.key2); - buf[self.pos] ^= 0x80; + res[pos] ^= 0x80; + xor(&mut res, &self.key2); } - self.cipher.encrypt_block(&mut buf); - Output::new(buf) - } - - fn reset(&mut self) { - self.buffer = Default::default(); - self.pos = 0; + xor(&mut self.state, res); + self.cipher.encrypt_block_b2b_mut(&self.state, out); } } -impl fmt::Debug for Cmac +impl Reset for CmacCore where - C: BlockCipher + BlockEncrypt + Clone + fmt::Debug, - Block: Dbl, + C: BlockCipher + BlockEncryptMut, + Block: Dbl, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - write!(f, "Cmac-{:?}", self.cipher) + #[inline] + fn reset(&mut self) { + self.state = Default::default(); } } -#[inline(always)] -fn xor>(buf: &mut Block, data: &Block) { - for i in 0..L::to_usize() { - buf[i] ^= data[i]; +impl AlgorithmName for CmacCore +where + C: AlgorithmName + BlockCipher + BlockEncryptMut, + Block: Dbl, +{ + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Cmac<")?; + C::write_alg_name(f)?; + f.write_str(">") } } -#[cfg(feature = "std")] -impl std::io::Write for Cmac +impl fmt::Debug for CmacCore where - C: BlockCipher + BlockEncrypt + Clone, - Block: Dbl, + C: AlgorithmName + BlockCipher + BlockEncryptMut, + Block: Dbl, { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - Mac::update(self, buf); - Ok(buf.len()) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("CmacCore<")?; + C::write_alg_name(f)?; + f.write_str("> { ... }") } +} - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) +#[inline(always)] +fn xor>(state: &mut GenericArray, data: &GenericArray) { + for i in 0..N::USIZE { + state[i] ^= data[i]; } } diff --git a/cmac/tests/data/kuznyechik.blb b/cmac/tests/data/kuznyechik.blb new file mode 100644 index 0000000..660fba2 Binary files /dev/null and b/cmac/tests/data/kuznyechik.blb differ diff --git a/cmac/tests/data/magma.blb b/cmac/tests/data/magma.blb new file mode 100644 index 0000000..c787d90 Binary files /dev/null and b/cmac/tests/data/magma.blb differ diff --git a/cmac/tests/data/wycheproof-aes128.blb b/cmac/tests/data/wycheproof-aes128.blb new file mode 100644 index 0000000..dfde593 Binary files /dev/null and b/cmac/tests/data/wycheproof-aes128.blb differ diff --git a/cmac/tests/data/wycheproof-aes192.blb b/cmac/tests/data/wycheproof-aes192.blb new file mode 100644 index 0000000..cb21624 Binary files /dev/null and b/cmac/tests/data/wycheproof-aes192.blb differ diff --git a/cmac/tests/data/wycheproof-aes256.blb b/cmac/tests/data/wycheproof-aes256.blb new file mode 100644 index 0000000..1502473 Binary files /dev/null and b/cmac/tests/data/wycheproof-aes256.blb differ diff --git a/cmac/tests/gost.rs b/cmac/tests/gost.rs deleted file mode 100644 index 8538b9b..0000000 --- a/cmac/tests/gost.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! Test vectors from GOST R 34.13-2015: -//! https://tc26.ru/standard/gost/GOST_R_3413-2015.pdf -use cmac::{Cmac, Mac, NewMac}; -use hex_literal::hex; -use kuznyechik::Kuznyechik; -use magma::Magma; - -#[test] -#[rustfmt::skip] -fn cmac_kuznyechik() { - let key = hex!(" - 8899aabbccddeeff0011223344556677 - fedcba98765432100123456789abcdef - "); - let pt = hex!(" - 1122334455667700ffeeddccbbaa9988 - 00112233445566778899aabbcceeff0a - 112233445566778899aabbcceeff0a00 - 2233445566778899aabbcceeff0a0011 - "); - let mac_res = hex!(" - 336f4d296059fbe34ddeb35b37749c67 - "); - let mut mac = Cmac::::new_from_slice(&key).unwrap(); - mac.update(&pt); - let tag_bytes = mac.finalize().into_bytes(); - assert_eq!(&tag_bytes[..mac_res.len()], &mac_res); -} - -#[test] -#[rustfmt::skip] -fn cmac_magma() { - let key = hex!(" - ffeeddccbbaa99887766554433221100 - f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff - "); - let pt = hex!(" - 92def06b3c130a59db54c704f8189d20 - 4a98fb2e67a8024c8912409b17b57e41 - "); - let mac_res = hex!("154e72102030c5bb"); - let mut mac = Cmac::::new_from_slice(&key).unwrap(); - mac.update(&pt); - let tag_bytes = mac.finalize().into_bytes(); - assert_eq!(&tag_bytes[..mac_res.len()], &mac_res); -} diff --git a/cmac/tests/mod.rs b/cmac/tests/mod.rs new file mode 100644 index 0000000..4c7d9d4 --- /dev/null +++ b/cmac/tests/mod.rs @@ -0,0 +1,24 @@ +use aes::{Aes128, Aes192, Aes256}; +use cmac::Cmac; +use digest::new_resettable_mac_test; + +// Tests from NIST SP 800-38B: +// https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/ +new_resettable_mac_test!(nist_cmac_aes128, "aes128", Cmac); +new_resettable_mac_test!(nist_cmac_aes192, "aes192", Cmac); +new_resettable_mac_test!(nist_cmac_aes256, "aes256", Cmac); + +// Tests from Project Wycheproof: +// https://github.com/google/wycheproof +new_resettable_mac_test!(wycheproof_cmac_aes128, "wycheproof-aes128", Cmac); +new_resettable_mac_test!(wycheproof_cmac_aes192, "wycheproof-aes192", Cmac); +new_resettable_mac_test!(wycheproof_cmac_aes256, "wycheproof-aes256", Cmac); + +// Test vectors from GOST R 34.13-2015: +// https://tc26.ru/standard/gost/GOST_R_3413-2015.pdf +new_resettable_mac_test!( + gost_cmac_kuznyechik, + "kuznyechik", + Cmac +); +new_resettable_mac_test!(gost_cmac_magma, "magma", Cmac); diff --git a/cmac/tests/nist.rs b/cmac/tests/nist.rs deleted file mode 100644 index d215e54..0000000 --- a/cmac/tests/nist.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Tests from NIST SP 800-38B: -//! https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/ -#![no_std] -use aes::{Aes128, Aes192, Aes256}; -use cmac::Cmac; -use crypto_mac::new_test; - -new_test!(cmac_aes128, "aes128", Cmac); -new_test!(cmac_aes192, "aes192", Cmac); -new_test!(cmac_aes256, "aes256", Cmac); diff --git a/daa/Cargo.toml b/daa/Cargo.toml index 30c6fb7..5328f56 100644 --- a/daa/Cargo.toml +++ b/daa/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "daa" -version = "0.5.0" +version = "0.6.0" # Also update html_root_url in lib.rs when bumping this description = "Implementation of Data Authentication Algorithm (DAA)" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" @@ -11,11 +11,12 @@ readme = "README.md" edition = "2018" [dependencies] -crypto-mac = { version = "0.11", features = ["cipher"] } -des = "0.7" +digest = { version = "0.10", features = ["mac"] } +des = "0.8" [dev-dependencies] -crypto-mac = { version = "0.11", features = ["dev"] } +digest = { version = "0.10", features = ["dev"] } +hex-literal = "0.2" [features] -std = ["crypto-mac/std"] +std = ["digest/std"] diff --git a/daa/README.md b/daa/README.md index 0936bc2..8255c04 100644 --- a/daa/README.md +++ b/daa/README.md @@ -5,7 +5,6 @@ ![Apache2/MIT licensed][license-image] ![Rust Version][rustc-image] [![Project Chat][chat-image]][chat-link] -[![Build Status][build-image]][build-link] Pure Rust implementation of the [Data Authentication Algorithm (DAA)][1]. @@ -48,8 +47,6 @@ dual licensed as above, without any additional terms or conditions. [rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260044-MACs -[build-image]: https://github.com/RustCrypto/MACs/workflows/daa/badge.svg?branch=master&event=push -[build-link]: https://github.com/RustCrypto/MACs/actions?query=workflow%3Adaa [//]: # (general links) diff --git a/daa/src/lib.rs b/daa/src/lib.rs index a0abfef..7179432 100644 --- a/daa/src/lib.rs +++ b/daa/src/lib.rs @@ -6,135 +6,123 @@ //! # Examples //! //! ``` -//! use daa::{Daa, Mac, NewMac}; +//! use daa::{Daa, Mac}; +//! use hex_literal::hex; //! //! // test from FIPS 113 -//! let key = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]; +//! let key = hex!("0123456789ABCDEF"); //! let mut mac = Daa::new_from_slice(&key).unwrap(); //! mac.update(b"7654321 Now is the time for "); -//! let correct = [0xF1, 0xD3, 0x0F, 0x68, 0x49, 0x31, 0x2C, 0xA4]; -//! mac.verify(&correct).unwrap(); +//! let correct = hex!("F1D30F6849312CA4"); +//! mac.verify(&correct.into()).unwrap(); //! ``` #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_root_url = "https://docs.rs/daa/0.6.0" )] #![forbid(unsafe_code)] #![warn(missing_docs, rust_2018_idioms)] #![allow(clippy::needless_range_loop)] -#[cfg(feature = "std")] -extern crate std; +pub use digest; +pub use digest::Mac; -pub use crypto_mac::{self, FromBlockCipher, Mac, NewMac}; +use des::cipher::BlockEncryptMut; use core::fmt; -use crypto_mac::{ - cipher::{BlockCipher, BlockEncrypt}, - generic_array::{typenum::Unsigned, GenericArray}, - Output, -}; use des::Des; +use digest::{ + block_buffer::Eager, + core_api::{Block, Buffer, BufferKindUser, CoreWrapper, FixedOutputCore, UpdateCore}, + crypto_common::{AlgorithmName, BlockSizeUser, InnerInit, InnerUser}, + generic_array::{ArrayLength, GenericArray}, + MacMarker, Output, OutputSizeUser, Reset, +}; -type Block = GenericArray::BlockSize>; +/// DAA type which operates over slices. +pub type Daa = CoreWrapper; -/// DAA instance +/// Core DAA type which operates over blocks. #[derive(Clone)] -pub struct Daa { +pub struct DaaCore { cipher: Des, - buffer: Block, - pos: usize, + state: Block, } -impl FromBlockCipher for Daa { - type Cipher = Des; +impl MacMarker for DaaCore {} - fn from_cipher(cipher: Des) -> Self { - Self { - cipher, - buffer: Default::default(), - pos: 0, - } - } +impl InnerUser for DaaCore { + type Inner = Des; } -impl Mac for Daa { - type OutputSize = ::BlockSize; - - #[inline] - fn update(&mut self, mut data: &[u8]) { - let n = ::BlockSize::to_usize(); - let rem = n - self.pos; - - if data.len() >= rem { - let (l, r) = data.split_at(rem); - data = r; - for (a, b) in self.buffer[self.pos..].iter_mut().zip(l) { - *a ^= *b; - } - self.pos = n; - } else { - for (a, b) in self.buffer[self.pos..].iter_mut().zip(data) { - *a ^= *b; - } - self.pos += data.len(); - return; - } +impl BufferKindUser for DaaCore { + type BufferKind = Eager; +} - while data.len() >= n { - self.cipher.encrypt_block(&mut self.buffer); +impl BlockSizeUser for DaaCore { + type BlockSize = ::BlockSize; +} - let (l, r) = data.split_at(n); - data = r; +impl OutputSizeUser for DaaCore { + type OutputSize = ::BlockSize; +} - for i in 0..n { - self.buffer[i] ^= l[i]; - } +impl InnerInit for DaaCore { + fn inner_init(cipher: Des) -> Self { + Self { + cipher, + state: Default::default(), } + } +} - if !data.is_empty() { - self.cipher.encrypt_block(&mut self.buffer); - for (a, b) in self.buffer.iter_mut().zip(data) { - *a ^= *b; - } - self.pos = data.len(); +impl UpdateCore for DaaCore { + fn update_blocks(&mut self, blocks: &[Block]) { + for block in blocks { + xor(&mut self.state, block); + self.cipher.encrypt_block_mut(&mut self.state); } } +} +impl FixedOutputCore for DaaCore { #[inline] - fn finalize(mut self) -> Output { - if self.pos != 0 { - self.cipher.encrypt_block(&mut self.buffer); + fn finalize_fixed_core(&mut self, buffer: &mut Buffer, out: &mut Output) { + let pos = buffer.get_pos(); + let res = buffer.pad_with_zeros(); + if pos != 0 { + xor(&mut self.state, res); + self.cipher.encrypt_block_mut(&mut self.state); } - - Output::new(self.buffer) + *out = self.state; } +} +impl Reset for DaaCore { #[inline] fn reset(&mut self) { - if self.pos != 0 { - self.pos = 0; - self.buffer = Default::default(); - } + self.state = Default::default(); } } -impl fmt::Debug for Daa { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - write!(f, "Daa") +impl AlgorithmName for DaaCore { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Daa") } } -#[cfg(feature = "std")] -impl std::io::Write for Daa { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - Mac::update(self, buf); - Ok(buf.len()) +impl fmt::Debug for DaaCore { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("DaaCore { ... }") } +} - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) +#[inline(always)] +fn xor>(state: &mut GenericArray, data: &GenericArray) { + for i in 0..N::USIZE { + state[i] ^= data[i]; } } diff --git a/hmac/Cargo.toml b/hmac/Cargo.toml index 23544f6..2a67c87 100644 --- a/hmac/Cargo.toml +++ b/hmac/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hmac" -version = "0.11.0" +version = "0.12.0" # Also update html_root_url in lib.rs when bumping this description = "Generic implementation of Hash-based Message Authentication Code (HMAC)" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" @@ -12,14 +12,15 @@ readme = "README.md" edition = "2018" [dependencies] -crypto-mac = "0.11" -digest = "0.9" +digest = { version = "0.10", features = ["mac"] } [dev-dependencies] -crypto-mac = { version = "0.11", features = ["dev"] } -md-5 = { version = "0.9", default-features = false } -sha2 = { version = "0.9", default-features = false } -streebog = { version = "0.9", default-features = false } +digest = { version = "0.10", features = ["dev"] } +md-5 = { version = "0.10", default-features = false } +sha-1 = { version = "0.10", default-features = false } +sha2 = { version = "0.10", default-features = false } +streebog = { version = "0.10", default-features = false } [features] -std = ["crypto-mac/std"] +std = ["digest/std"] +reset = [] # Enable ability to reset HMAC instances diff --git a/hmac/README.md b/hmac/README.md index ab50b2c..52d4ef9 100644 --- a/hmac/README.md +++ b/hmac/README.md @@ -5,7 +5,6 @@ ![Apache2/MIT licensed][license-image] ![Rust Version][rustc-image] [![Project Chat][chat-image]][chat-link] -[![Build Status][build-image]][build-link] Pure Rust implementation of the [Hash-based Message Authentication Code (HMAC)][1]. @@ -48,8 +47,6 @@ dual licensed as above, without any additional terms or conditions. [rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260044-MACs -[build-image]: https://github.com/RustCrypto/MACs/workflows/hmac/badge.svg?branch=master&event=push -[build-link]: https://github.com/RustCrypto/MACs/actions?query=workflow%3Ahmac [//]: # (general links) diff --git a/hmac/src/lib.rs b/hmac/src/lib.rs index b3f3666..5d30d12 100644 --- a/hmac/src/lib.rs +++ b/hmac/src/lib.rs @@ -1,8 +1,8 @@ //! Generic implementation of Hash-based Message Authentication Code (HMAC). //! //! To use it you'll need a cryptographic hash function implementation from -//! RustCrypto project. You can either import specific crate (e.g. `sha2`), or -//! meta-crate `crypto-hashes` which reexport all related crates. +//! the RustCrypto project, e.g. the from the [`sha2`](https://docs.rs/sha2/) +//! crate. //! //! # Usage //! Let us demonstrate how to use HMAC using SHA256 as an example. @@ -11,22 +11,21 @@ //! //! ```rust //! use sha2::Sha256; -//! use hmac::{Hmac, Mac, NewMac}; +//! use hmac::{Hmac, Mac}; //! //! // Create alias for HMAC-SHA256 //! type HmacSha256 = Hmac; //! -//! // Create HMAC-SHA256 instance which implements `Mac` trait //! let mut mac = HmacSha256::new_from_slice(b"my secret and secure key") //! .expect("HMAC can take key of any size"); //! mac.update(b"input message"); //! -//! // `result` has type `Output` which is a thin wrapper around array of +//! // `result` has type `CtOutput` which is a thin wrapper around array of //! // bytes for providing constant time equality check //! let result = mac.finalize(); -//! // To get underlying array use `into_bytes` method, but be careful, since -//! // incorrect use of the code value may permit timing attacks which defeat -//! // the security provided by the `Output` +//! // To get underlying array use `into_bytes`, but be careful, since +//! // incorrect use of the code value may permit timing attacks which defeats +//! // the security provided by the `CtOutput` //! let code_bytes = result.into_bytes(); //! ``` //! @@ -34,7 +33,7 @@ //! //! ```rust //! # use sha2::Sha256; -//! # use hmac::{Hmac, Mac, NewMac}; +//! # use hmac::{Hmac, Mac}; //! # type HmacSha256 = Hmac; //! let mut mac = HmacSha256::new_from_slice(b"my secret and secure key") //! .expect("HMAC can take key of any size"); @@ -54,160 +53,236 @@ #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_root_url = "https://docs.rs/hmac/0.12.0" )] +#![cfg_attr(docsrs, feature(doc_cfg))] #![forbid(unsafe_code)] #![warn(missing_docs, rust_2018_idioms)] #[cfg(feature = "std")] extern crate std; -pub use crypto_mac::{self, Mac, NewMac}; pub use digest; +pub use digest::Mac; -use core::{cmp::min, fmt}; -use crypto_mac::{ - generic_array::{sequence::GenericSequence, ArrayLength, GenericArray}, - InvalidKeyLength, Output, +use core::{fmt, slice}; +#[cfg(feature = "reset")] +use digest::Reset; +use digest::{ + block_buffer::Eager, + core_api::{ + AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreProxy, CoreWrapper, + FixedOutputCore, OutputSizeUser, UpdateCore, + }, + crypto_common::{Key, KeySizeUser}, + Digest, InvalidLength, KeyInit, MacMarker, Output, }; -use digest::{BlockInput, FixedOutput, Reset, Update}; const IPAD: u8 = 0x36; const OPAD: u8 = 0x5C; -/// The `Hmac` struct represents an HMAC using a given hash function `D`. -pub struct Hmac +/// Generic HMAC instance. +pub type Hmac = CoreWrapper>; + +/// Generic core HMAC instance, which operates over blocks. +pub struct HmacCore where - D: Update + BlockInput + FixedOutput + Reset + Default + Clone, - D::BlockSize: ArrayLength, + D: CoreProxy + Digest, + D::Core: UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, { - digest: D, - i_key_pad: GenericArray, - opad_digest: D, + digest: D::Core, + opad_digest: D::Core, + #[cfg(feature = "reset")] + ipad_digest: D::Core, } -impl Clone for Hmac +impl Clone for HmacCore where - D: Update + BlockInput + FixedOutput + Reset + Default + Clone, - D::BlockSize: ArrayLength, + D: CoreProxy + Digest, + D::Core: UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, { - fn clone(&self) -> Hmac { - Hmac { + fn clone(&self) -> Self { + Self { digest: self.digest.clone(), - i_key_pad: self.i_key_pad.clone(), opad_digest: self.opad_digest.clone(), + #[cfg(feature = "reset")] + ipad_digest: self.ipad_digest.clone(), } } } -impl fmt::Debug for Hmac +impl MacMarker for HmacCore where - D: Update + BlockInput + FixedOutput + Reset + Default + Clone + fmt::Debug, - D::BlockSize: ArrayLength, + D: CoreProxy + Digest, + D::Core: UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Hmac") - .field("digest", &self.digest) - .field("i_key_pad", &self.i_key_pad) - .field("opad_digest", &self.opad_digest) - .finish() - } } -impl NewMac for Hmac +impl BufferKindUser for HmacCore +where + D: CoreProxy + Digest, + D::Core: UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, +{ + type BufferKind = Eager; +} + +impl KeySizeUser for HmacCore where - D: Update + BlockInput + FixedOutput + Reset + Default + Clone, - D::BlockSize: ArrayLength, - D::OutputSize: ArrayLength, + D: CoreProxy + Digest, + D::Core: UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, { - type KeySize = D::BlockSize; + type KeySize = <::Core as BlockSizeUser>::BlockSize; +} - fn new(key: &GenericArray) -> Self { +impl BlockSizeUser for HmacCore +where + D: CoreProxy + Digest, + D::Core: UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, +{ + type BlockSize = <::Core as BlockSizeUser>::BlockSize; +} + +impl OutputSizeUser for HmacCore +where + D: CoreProxy + Digest, + D::Core: UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, +{ + type OutputSize = <::Core as OutputSizeUser>::OutputSize; +} + +impl KeyInit for HmacCore +where + D: CoreProxy + Digest, + D::Core: UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, +{ + fn new(key: &Key) -> Self { Self::new_from_slice(key.as_slice()).unwrap() } #[inline] - fn new_from_slice(key: &[u8]) -> Result { - let mut hmac = Self { - digest: Default::default(), - i_key_pad: GenericArray::generate(|_| IPAD), - opad_digest: Default::default(), - }; - - let mut opad = GenericArray::::generate(|_| OPAD); - debug_assert!(hmac.i_key_pad.len() == opad.len()); - - // The key that Hmac processes must be the same as the block size of the - // underlying Digest. If the provided key is smaller than that, we just - // pad it with zeros. If its larger, we hash it and then pad it with - // zeros. - if key.len() <= hmac.i_key_pad.len() { - for (k_idx, k_itm) in key.iter().enumerate() { - hmac.i_key_pad[k_idx] ^= *k_itm; - opad[k_idx] ^= *k_itm; - } + fn new_from_slice(key: &[u8]) -> Result { + let mut der_key = Block::::default(); + // The key that HMAC processes must be the same as the block size of the + // underlying hash function. If the provided key is smaller than that, + // we just pad it with zeros. If its larger, we hash it and then pad it + // with zeros. + if key.len() <= der_key.len() { + der_key[..key.len()].copy_from_slice(key); } else { - let mut digest = D::default(); - digest.update(key); - let output = digest.finalize_fixed(); - // `n` is calculated at compile time and will equal - // D::OutputSize. This is used to ensure panic-free code - let n = min(output.len(), hmac.i_key_pad.len()); - for idx in 0..n { - hmac.i_key_pad[idx] ^= output[idx]; - opad[idx] ^= output[idx]; + let hash = D::digest(key); + // All commonly used hash functions have block size bigger + // than output hash size, but to be extra rigorous we + // handle the potential uncommon cases as well. + // The condition is calcualted at compile time, so this + // branch gets removed in the final binary. + if hash.len() <= der_key.len() { + der_key[..hash.len()].copy_from_slice(&hash); + } else { + let n = der_key.len(); + der_key.copy_from_slice(&hash[..n]); } } - hmac.digest.update(&hmac.i_key_pad); - hmac.opad_digest.update(&opad); + let mut buf = der_key.clone(); + for b in buf.iter_mut() { + *b ^= IPAD; + } + let mut digest = D::Core::default(); + digest.update_blocks(slice::from_ref(&buf)); + + for b in buf.iter_mut() { + *b ^= IPAD ^ OPAD; + } - Ok(hmac) + let mut opad_digest = D::Core::default(); + opad_digest.update_blocks(slice::from_ref(&buf)); + + Ok(Self { + #[cfg(feature = "reset")] + ipad_digest: digest.clone(), + opad_digest, + digest, + }) } } -impl Mac for Hmac +impl UpdateCore for HmacCore where - D: Update + BlockInput + FixedOutput + Reset + Default + Clone, - D::BlockSize: ArrayLength, - D::OutputSize: ArrayLength, + D: CoreProxy + Digest, + D::Core: UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, { - type OutputSize = D::OutputSize; - - #[inline] - fn update(&mut self, data: &[u8]) { - self.digest.update(data); + #[inline(always)] + fn update_blocks(&mut self, blocks: &[Block]) { + self.digest.update_blocks(blocks); } +} - #[inline] - fn finalize(self) -> Output { - let mut opad_digest = self.opad_digest.clone(); - let hash = self.digest.finalize_fixed(); - opad_digest.update(&hash); - Output::new(opad_digest.finalize_fixed()) +impl FixedOutputCore for HmacCore +where + D: CoreProxy + Digest, + D::Core: UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, +{ + #[inline(always)] + fn finalize_fixed_core(&mut self, buffer: &mut Buffer, out: &mut Output) { + let mut hash = Output::::default(); + self.digest.finalize_fixed_core(buffer, &mut hash); + // finalize_fixed_core should reset the buffer as well, but + // to be extra safe we reset it explicitly again. + buffer.reset(); + #[cfg(not(feature = "reset"))] + let h = &mut self.opad_digest; + #[cfg(feature = "reset")] + let mut h = self.opad_digest.clone(); + buffer.digest_blocks(&hash, |b| h.update_blocks(b)); + h.finalize_fixed_core(buffer, out); } +} - #[inline] +#[cfg(feature = "reset")] +#[cfg_attr(docsrs, doc(cfg(feature = "reset")))] +impl Reset for HmacCore +where + D: CoreProxy + Digest, + D::Core: UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, +{ + #[inline(always)] fn reset(&mut self) { - self.digest.reset(); - self.digest.update(&self.i_key_pad); + self.digest = self.ipad_digest.clone(); } } -#[cfg(feature = "std")] -impl std::io::Write for Hmac +impl AlgorithmName for HmacCore where - D: Update + BlockInput + FixedOutput + Reset + Default + Clone, - D::BlockSize: ArrayLength, - D::OutputSize: ArrayLength, + D: CoreProxy + Digest, + D::Core: AlgorithmName + + UpdateCore + + FixedOutputCore + + BufferKindUser + + Default + + Clone, { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - Mac::update(self, buf); - Ok(buf.len()) + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Hmac<")?; + ::write_alg_name(f)?; + f.write_str(">") } +} - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) +impl fmt::Debug for HmacCore +where + D: CoreProxy + Digest, + D::Core: AlgorithmName + + UpdateCore + + FixedOutputCore + + BufferKindUser + + Default + + Clone, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("HmacCore<")?; + ::write_alg_name(f)?; + f.write_str("> { ... }") } } diff --git a/hmac/tests/data/wycheproof-sha1.blb b/hmac/tests/data/wycheproof-sha1.blb new file mode 100644 index 0000000..a4f8f43 Binary files /dev/null and b/hmac/tests/data/wycheproof-sha1.blb differ diff --git a/hmac/tests/data/wycheproof-sha256.blb b/hmac/tests/data/wycheproof-sha256.blb new file mode 100644 index 0000000..62f1d35 Binary files /dev/null and b/hmac/tests/data/wycheproof-sha256.blb differ diff --git a/hmac/tests/data/wycheproof-sha384.blb b/hmac/tests/data/wycheproof-sha384.blb new file mode 100644 index 0000000..69a7874 Binary files /dev/null and b/hmac/tests/data/wycheproof-sha384.blb differ diff --git a/hmac/tests/data/wycheproof-sha512.blb b/hmac/tests/data/wycheproof-sha512.blb new file mode 100644 index 0000000..e061fd5 Binary files /dev/null and b/hmac/tests/data/wycheproof-sha512.blb differ diff --git a/hmac/tests/lib.rs b/hmac/tests/lib.rs deleted file mode 100644 index 38714a0..0000000 --- a/hmac/tests/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Test vectors from: -//! - md5: RFC 2104, plus wiki test -//! - sha2: RFC 4231 - -#![no_std] - -use crypto_mac::new_test; -use hmac::Hmac; - -new_test!(hmac_md5, "md5", Hmac); -new_test!(hmac_sha224, "sha224", Hmac); -new_test!(hmac_sha256, "sha256", Hmac); -new_test!(hmac_sha384, "sha384", Hmac); -new_test!(hmac_sha512, "sha512", Hmac); -// Test vectors from R 50.1.113-2016: -// https://tc26.ru/standard/rs/Р 50.1.113-2016.pdf -new_test!(hmac_streebog256, "streebog256", Hmac); -new_test!(hmac_streebog512, "streebog512", Hmac); diff --git a/hmac/tests/mod.rs b/hmac/tests/mod.rs new file mode 100644 index 0000000..02e28c7 --- /dev/null +++ b/hmac/tests/mod.rs @@ -0,0 +1,49 @@ +#[cfg(not(feature = "reset"))] +use digest::new_mac_test as new_test; +#[cfg(feature = "reset")] +use digest::new_resettable_mac_test as new_test; +use hmac::Hmac; +use sha1::Sha1; +use sha2::{Sha224, Sha256, Sha384, Sha512}; +use streebog::{Streebog256, Streebog512}; + +// Test vectors from RFC 2104, plus wiki test +new_test!(rfc2104_hmac_md5, "md5", Hmac); + +// Test vectors from RFC 4231 +new_test!(rfc4231_hmac_sha224, "sha224", Hmac); +new_test!(rfc4231_hmac_sha256, "sha256", Hmac); +new_test!(rfc4231_hmac_sha384, "sha384", Hmac); +new_test!(rfc4231_hmac_sha512, "sha512", Hmac); + +// Tests from Project Wycheproof: +// https://github.com/google/wycheproof +new_test!( + wycheproof_hmac_sha1, + "wycheproof-sha1", + Hmac, + trunc_left, +); +new_test!( + wycheproof_hmac_sha256, + "wycheproof-sha256", + Hmac, + trunc_left, +); +new_test!( + wycheproof_hmac_sha384, + "wycheproof-sha384", + Hmac, + trunc_left, +); +new_test!( + wycheproof_hmac_sha512, + "wycheproof-sha512", + Hmac, + trunc_left, +); + +// Test vectors from R 50.1.113-2016: +// https://tc26.ru/standard/rs/Р 50.1.113-2016.pdf +new_test!(hmac_streebog256, "streebog256", Hmac); +new_test!(hmac_streebog512, "streebog512", Hmac); diff --git a/pmac/Cargo.toml b/pmac/Cargo.toml index b830a03..7ff36a0 100644 --- a/pmac/Cargo.toml +++ b/pmac/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pmac" -version = "0.6.0" +version = "0.7.0" # Also update html_root_url in lib.rs when bumping this description = "Generic implementation of Parallelizable Message Authentication Code" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" @@ -12,12 +12,14 @@ readme = "README.md" edition = "2018" [dependencies] -crypto-mac = { version = "0.11", features = ["cipher"] } +digest = { version = "0.10", features = ["mac"] } +cipher = "0.4" dbl = "0.3" [dev-dependencies] -aes = { version = "0.7", features = ["force-soft"] } # Uses `force-soft` for MSRV 1.41 -crypto-mac = { version = "0.11", features = ["dev"] } +aes = { version = "0.8", features = ["force-soft"] } # Uses `force-soft` for MSRV 1.41 +digest = { version = "0.10", features = ["dev"] } +hex-literal = "0.2" [features] -std = ["crypto-mac/std"] +std = ["digest/std"] diff --git a/pmac/README.md b/pmac/README.md index 41d2cf8..0afe291 100644 --- a/pmac/README.md +++ b/pmac/README.md @@ -5,7 +5,6 @@ ![Apache2/MIT licensed][license-image] ![Rust Version][rustc-image] [![Project Chat][chat-image]][chat-link] -[![Build Status][build-image]][build-link] Pure Rust implementation of the [Parallel Message Authentication Code (PMAC)][1]. @@ -48,8 +47,6 @@ dual licensed as above, without any additional terms or conditions. [rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260044-MACs -[build-image]: https://github.com/RustCrypto/MACs/workflows/pmac/badge.svg?branch=master&event=push -[build-link]: https://github.com/RustCrypto/MACs/actions?query=workflow%3Apmac [//]: # (general links) diff --git a/pmac/src/lib.rs b/pmac/src/lib.rs index 4021a4b..654b14d 100644 --- a/pmac/src/lib.rs +++ b/pmac/src/lib.rs @@ -8,7 +8,8 @@ //! //! ```rust //! use aes::Aes128; -//! use pmac::{Pmac, Mac, NewMac}; +//! use pmac::{Pmac, Mac}; +//! use hex_literal::hex; //! //! // Create `Mac` trait implementation, namely PMAC-AES128 //! let mut mac = Pmac::::new_from_slice(b"very secret key.").unwrap(); @@ -21,286 +22,234 @@ //! // incorrect use of the tag value may permit timing attacks which defeat //! // the security provided by the `Output` wrapper //! let tag_bytes = result.into_bytes(); +//! assert_eq!(tag_bytes[..], hex!("b8c60dc25262f0bfd071ffa692d04252")[..]); //! ``` //! //! To verify the message: //! //! ```rust //! # use aes::Aes128; -//! # use pmac::{Pmac, Mac, NewMac}; +//! # use pmac::{Pmac, Mac}; +//! # use hex_literal::hex; //! let mut mac = Pmac::::new_from_slice(b"very secret key.").unwrap(); //! //! mac.update(b"input message"); //! -//! # let tag_bytes = mac.clone().finalize().into_bytes(); +//! let tag_bytes = hex!("b8c60dc25262f0bfd071ffa692d04252"); //! // `verify` will return `Ok(())` if tag is correct, `Err(MacError)` otherwise -//! mac.verify(&tag_bytes).unwrap(); +//! mac.verify(&tag_bytes.into()).unwrap(); //! ``` //! //! [1]: https://en.wikipedia.org/wiki/PMAC_(cryptography) #![no_std] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_root_url = "https://docs.rs/pmac/0.7.0" )] -#![deny(unsafe_code)] +// #![deny(unsafe_code)] #![warn(missing_docs, rust_2018_idioms)] -#[cfg(feature = "std")] -extern crate std; +pub use digest; +pub use digest::Mac; -pub use crypto_mac::{self, FromBlockCipher, Mac, NewMac}; +use cipher::{BlockCipher, BlockEncryptMut}; -use core::{fmt, slice}; -use crypto_mac::{ - cipher::{BlockCipher, BlockEncrypt}, +use core::fmt; +use dbl::Dbl; +use digest::{ + block_buffer::Lazy, + core_api::{Block, Buffer, BufferKindUser, CoreWrapper, FixedOutputCore, UpdateCore}, + crypto_common::{AlgorithmName, BlockSizeUser, InnerInit, InnerUser}, generic_array::{typenum::Unsigned, ArrayLength, GenericArray}, - Output, + MacMarker, Output, OutputSizeUser, Reset, }; -use dbl::Dbl; -type Block = GenericArray; -type ParBlocks = GenericArray, M>; +/// Generic PMAC instance which operates over bytes. +pub type Pmac = CoreWrapper>; -/// Will use only precomputed table up to 16*2^20 = 16 MB of input data -/// (for 128 bit cipher), after that will dynamically calculate L value if -/// needed. In future it can become parameter of `Pmac`. -const LC_SIZE: usize = 20; - -/// Generic PMAC instance +/// Generic core PMAC instance which operates over blocks. +/// +/// The `LC_SIZE` constant determines size of a precomputed lookup table. +/// The [`Pmac`] alias uses value equal to 20, which for 128 bit cipher +/// sufficient for 16*2^20 = 16 MB of input data. #[derive(Clone)] -pub struct Pmac +pub struct PmacCore where - C: BlockCipher + BlockEncrypt + Clone, - Block: Dbl, + C: BlockCipher + BlockEncryptMut, + Block: Dbl, { cipher: C, - l_inv: Block, - l_cache: [Block; LC_SIZE], - buffer: ParBlocks, - tag: Block, - offset: Block, - pos: usize, + l_cache: [Block; LC_SIZE], + tag: Block, + offset: Block, counter: usize, } -impl Pmac +impl MacMarker for PmacCore where - C: BlockCipher + BlockEncrypt + Clone, - Block: Dbl, + C: BlockCipher + BlockEncryptMut, + Block: Dbl, { - /// Process full buffer and update tag - #[inline(always)] - fn process_buffer(&mut self) { - let mut offset = self.offset.clone(); - let mut counter = self.counter; - let mut buf = self.buffer.clone(); - for val in buf.iter_mut() { - let l = self.get_l(counter); - xor(&mut offset, &l); - counter += 1; - xor(val, &offset); - } - self.counter = counter; - self.offset = offset; - - // encrypt blocks in the buffer - self.cipher.encrypt_blocks(&mut buf); - // and xor them into tag - for val in buf.iter() { - xor(&mut self.tag, val); - } - } +} - /// Represent internal buffer as bytes slice (hopefully in future we will - /// be able to switch `&mut [u8]` to `&mut [u8; BlockSize*ParBlocks]`) - #[inline(always)] - fn as_mut_bytes(&mut self) -> &mut [u8] { - #[allow(unsafe_code)] - unsafe { - slice::from_raw_parts_mut( - &mut self.buffer as *mut ParBlocks as *mut u8, - C::BlockSize::to_usize() * C::ParBlocks::to_usize(), - ) - } - } +impl InnerUser for PmacCore +where + C: BlockCipher + BlockEncryptMut, + Block: Dbl, +{ + type Inner = C; +} - #[inline(always)] - fn get_l(&self, counter: usize) -> Block { - let ntz = counter.trailing_zeros() as usize; - if ntz < LC_SIZE { - self.l_cache[ntz].clone() - } else { - let mut block = self.l_cache[LC_SIZE - 1].clone(); - for _ in LC_SIZE - 1..ntz { - block = block.dbl(); - } - block - } - } +impl BlockSizeUser for PmacCore +where + C: BlockCipher + BlockEncryptMut, + Block: Dbl, +{ + type BlockSize = C::BlockSize; } -impl FromBlockCipher for Pmac +impl OutputSizeUser for PmacCore where - C: BlockCipher + BlockEncrypt + Clone, - Block: Dbl, + C: BlockCipher + BlockEncryptMut, + Block: Dbl, { - type Cipher = C; + type OutputSize = C::BlockSize; +} - fn from_cipher(cipher: C) -> Self { - let mut l0 = Default::default(); - cipher.encrypt_block(&mut l0); +impl BufferKindUser for PmacCore +where + C: BlockCipher + BlockEncryptMut, + Block: Dbl, +{ + type BufferKind = Lazy; +} - let mut l_cache: [Block; LC_SIZE] = Default::default(); - l_cache[0] = l0.clone(); - for i in 1..LC_SIZE { - l_cache[i] = l_cache[i - 1].clone().dbl(); +impl InnerInit for PmacCore +where + C: BlockCipher + BlockEncryptMut, + Block: Dbl, +{ + #[inline] + fn inner_init(mut cipher: C) -> Self { + // SAFETY: [Block; LC_SIZE] is equivalent to + // [[u8; BLOCK_SIZE]; LC_SIZE], so `zeroed` returns + // a valid value for it + // TODO: replace with `[(); LC_SIZE].map(..)` or + // `[[0u8; BLOCK_SIZE]; L]` on MSRV bump + let mut l_cache: [Block; LC_SIZE] = unsafe { core::mem::zeroed() }; + if LC_SIZE != 0 { + cipher.encrypt_block_mut(&mut l_cache[0]); + for i in 1..LC_SIZE { + l_cache[i] = l_cache[i - 1].clone().dbl(); + } } - let l_inv = l0.inv_dbl(); - Self { cipher, - l_inv, l_cache, - buffer: Default::default(), tag: Default::default(), offset: Default::default(), - pos: 0, counter: 1, } } } -impl Mac for Pmac +impl UpdateCore for PmacCore where - C: BlockCipher + BlockEncrypt + Clone, - Block: Dbl, + C: BlockCipher + BlockEncryptMut, + Block: Dbl, { - type OutputSize = C::BlockSize; - #[inline] - fn update(&mut self, mut data: &[u8]) { - let n = C::BlockSize::to_usize() * C::ParBlocks::to_usize(); - - let p = self.pos; - let rem = n - p; - if data.len() >= rem { - let (l, r) = data.split_at(rem); - data = r; - self.as_mut_bytes()[p..].clone_from_slice(l); - } else { - self.as_mut_bytes()[p..p + data.len()].clone_from_slice(data); - self.pos += data.len(); - return; - } - - while data.len() >= n { - self.process_buffer(); - - let (l, r) = data.split_at(n); - self.as_mut_bytes().clone_from_slice(l); - data = r; - } - - self.pos = n; - - if !data.is_empty() { - self.process_buffer(); - self.as_mut_bytes()[..data.len()].clone_from_slice(data); - self.pos = data.len(); + fn update_blocks(&mut self, blocks: &[Block]) { + // TODO: use parallel encryption, move the branching outside the loop + for block in blocks { + let ntz = self.counter.trailing_zeros() as usize; + let l = if ntz < LC_SIZE { + self.l_cache[ntz].clone() + } else { + let mut block = self.l_cache[LC_SIZE - 1].clone(); + for _ in LC_SIZE - 1..ntz { + block = block.dbl(); + } + block + }; + + xor(&mut self.offset, &l); + self.counter += 1; + let mut block = block.clone(); + xor(&mut block, &self.offset); + self.cipher.encrypt_block_mut(&mut block); + xor(&mut self.tag, &block); } } +} - fn finalize(self) -> Output { - let mut tag = self.tag.clone(); - // Special case for empty input - if self.pos == 0 { - tag[0] = 0x80; - self.cipher.encrypt_block(&mut tag); - return Output::new(tag); - } - - let bs = C::BlockSize::to_usize(); - let k = self.pos % bs; - let is_full = k == 0; - // number of full blocks excluding last - let n = if is_full { - (self.pos / bs) - 1 - } else { - self.pos / bs - }; - assert!(n < C::ParBlocks::to_usize(), "invalid buffer position"); - - let mut offset = self.offset.clone(); - let mut counter = self.counter; - for i in 0..n { - let mut buf = self.buffer[i].clone(); - - let l = self.get_l(counter); - xor(&mut offset, &l); - xor(&mut buf, &offset); - self.cipher.encrypt_block(&mut buf); - - xor(&mut tag, &buf); - counter += 1; - } +impl FixedOutputCore for PmacCore +where + C: BlockCipher + BlockEncryptMut, + Block: Dbl, +{ + #[inline] + fn finalize_fixed_core(&mut self, buffer: &mut Buffer, out: &mut Output) { + let pos = buffer.get_pos(); + let is_full = pos == Self::BlockSize::USIZE; + let last_block = buffer.pad_with_zeros(); if is_full { - xor(&mut tag, &self.buffer[n]); - xor(&mut tag, &self.l_inv); + xor(&mut self.tag, last_block); + let l_inv = self.l_cache[0].clone().inv_dbl(); + xor(&mut self.tag, &l_inv); } else { - let mut block = self.buffer[n].clone(); - block[k] = 0x80; - for v in block[k + 1..].iter_mut() { - *v = 0; - } - xor(&mut tag, &block); + last_block[pos] = 0x80; + xor(&mut self.tag, last_block); } - self.cipher.encrypt_block(&mut tag); - Output::new(tag) + self.cipher.encrypt_block_b2b_mut(&self.tag, out); } +} +impl Reset for PmacCore +where + C: BlockCipher + BlockEncryptMut, + Block: Dbl, +{ + #[inline] fn reset(&mut self) { - self.buffer = Default::default(); self.tag = Default::default(); self.offset = Default::default(); - self.pos = 0; self.counter = 1; } } -impl fmt::Debug for Pmac +impl AlgorithmName for PmacCore where - C: BlockCipher + BlockEncrypt + Clone + fmt::Debug, - Block: Dbl, + C: AlgorithmName + BlockCipher + BlockEncryptMut, + Block: Dbl, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - write!(f, "Pmac{:?}", self.cipher) + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Pmac<")?; + C::write_alg_name(f)?; + f.write_str(">") } } -#[inline(always)] -fn xor>(buf: &mut Block, data: &Block) { - for i in 0..L::to_usize() { - buf[i] ^= data[i]; - } -} - -#[cfg(feature = "std")] -impl std::io::Write for Pmac +impl fmt::Debug for PmacCore where - C: BlockCipher + BlockEncrypt + Clone, - Block: Dbl, + C: AlgorithmName + BlockCipher + BlockEncryptMut, + Block: Dbl, { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - Mac::update(self, buf); - Ok(buf.len()) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("PmacCore<")?; + C::write_alg_name(f)?; + f.write_str("> { ... }") } +} - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) +#[inline(always)] +fn xor>(buf: &mut GenericArray, data: &GenericArray) { + for i in 0..N::USIZE { + buf[i] ^= data[i]; } } diff --git a/pmac/tests/lib.rs b/pmac/tests/lib.rs deleted file mode 100644 index 26704fa..0000000 --- a/pmac/tests/lib.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Tests taken from: http://web.cs.ucdavis.edu/~rogaway/ocb/pmac-test.htm -#![no_std] -#[macro_use] -extern crate crypto_mac; - -use aes::{Aes128, Aes192, Aes256}; -use pmac::Pmac; - -new_test!(pmac_aes128, "aes128", Pmac); -new_test!(pmac_aes192, "aes192", Pmac); -new_test!(pmac_aes256, "aes256", Pmac); diff --git a/pmac/tests/mod.rs b/pmac/tests/mod.rs new file mode 100644 index 0000000..30d017a --- /dev/null +++ b/pmac/tests/mod.rs @@ -0,0 +1,8 @@ +use aes::{Aes128, Aes192, Aes256}; +use digest::new_resettable_mac_test; +use pmac::Pmac; + +// Test vectors from: http://web.cs.ucdavis.edu/~rogaway/ocb/pmac-test.htm +new_resettable_mac_test!(pmac_aes128, "aes128", Pmac); +new_resettable_mac_test!(pmac_aes192, "aes192", Pmac); +new_resettable_mac_test!(pmac_aes256, "aes256", Pmac);