digest-0.10.7/.cargo_vcs_info.json0000644000000001440000000000100123770ustar { "git": { "sha1": "344389411fd9718a0742435152e933a9e71461ee" }, "path_in_vcs": "digest" }digest-0.10.7/CHANGELOG.md000064400000000000000000000072601046102023000130060ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## 0.10.7 (2023-05-19) ### Changed - Loosen `subtle` version requirement ([#1260]) [#1260]: https://github.com/RustCrypto/traits/pull/1260 ## 0.10.6 (2022-11-17) ### Added - `Mac::verify_reset` and `Mac::verify_slice_reset` methods ([#1154]) [#1154]: https://github.com/RustCrypto/traits/pull/1154 ## 0.10.5 (2022-09-16) ### Fixed - MSRV build ([#1117]) [#1117]: https://github.com/RustCrypto/traits/pull/1117 ## 0.10.4 (2022-09-16) ### Added - Feature-gated implementation of the `const_oid::AssociatedOid` trait for the core wrappers. ([#1098]) [#1098]: https://github.com/RustCrypto/traits/pull/1098 ## 0.10.3 (2022-02-16) ### Fixed - Minimal versions build ([#940]) [#940]: https://github.com/RustCrypto/traits/pull/940 ## 0.10.2 (2022-02-10) ### Changed - Relax bounds on the `Mac` trait ([#849]) [#849]: https://github.com/RustCrypto/traits/pull/849 ## 0.10.1 (2021-12-14) [YANKED] ### Added - `Update::chain` and `Digest::new_with_prefix` methods. ([#846]) - `Mac::generate_key` method. ([#847]) ### Fixed - Doc cfg attribute for `CtOutput` and `MacError`. ([#842]) - Expose `KeyInit::generate_key` method in docs. ([#847]) [#842]: https://github.com/RustCrypto/traits/pull/842 [#846]: https://github.com/RustCrypto/traits/pull/846 [#847]: https://github.com/RustCrypto/traits/pull/847 ## 0.10.0 (2021-12-07) [YANKED] ### Changed - Dirty traits are removed and instead block-level traits are introduced. Variable output traits reworked and now support both run and compile time selection of output size. ([#380], [#819]) - The `crypto-mac` traits are reworked and merged in. ([#819]) [#819]: https://github.com/RustCrypto/traits/pull/819 [#380]: https://github.com/RustCrypto/traits/pull/380 ## 0.9.0 (2020-06-09) ### Added - `ExtendableOutputDirty` and `VariableOutputDirty` traits ([#183]) - `FixedOutputDirty` trait + `finalize_into*` ([#180]) - `XofReader::read_boxed` method ([#178], [#181], [#182]) - `alloc` feature ([#163]) - Re-export `typenum::consts` as `consts` ([#123]) - `Output` type alias ([#115]) ### Changed - Rename `*result*` methods to `finalize` ala IUF ([#161]) - Use `impl AsRef<[u8]>` instead of generic params on methods ([#112]) - Rename `Input::input` to `Update::update` ala IUF ([#111]) - Upgrade to Rust 2018 edition ([#109]) - Bump `generic-array` to v0.14 ([#95]) [#183]: https://github.com/RustCrypto/traits/pull/183 [#181]: https://github.com/RustCrypto/traits/pull/181 [#182]: https://github.com/RustCrypto/traits/pull/182 [#180]: https://github.com/RustCrypto/traits/pull/180 [#178]: https://github.com/RustCrypto/traits/pull/178 [#163]: https://github.com/RustCrypto/traits/pull/163 [#161]: https://github.com/RustCrypto/traits/pull/161 [#123]: https://github.com/RustCrypto/traits/pull/123 [#115]: https://github.com/RustCrypto/traits/pull/115 [#111]: https://github.com/RustCrypto/traits/pull/111 [#112]: https://github.com/RustCrypto/traits/pull/112 [#109]: https://github.com/RustCrypto/traits/pull/109 [#95]: https://github.com/RustCrypto/traits/pull/95 ## 0.8.1 (2019-06-30) ## 0.8.0 (2018-10-01) ## 0.7.6 (2018-09-21) ## 0.7.5 (2018-07-13) ## 0.7.4 (2018-06-21) ## 0.7.3 (2018-06-20) ## 0.7.2 (2017-11-17) ## 0.7.1 (2017-11-15) ## 0.7.0 (2017-11-14) ## 0.6.2 (2017-07-24) ## 0.6.1 (2017-06-18) ## 0.6.0 (2017-06-12) ## 0.5.2 (2017-05-02) ## 0.5.1 (2017-05-02) ## 0.5.0 (2017-04-06) ## 0.4.0 (2016-12-24) ## 0.3.1 (2016-12-16) ## 0.3.0 (2016-11-17) ## 0.2.1 (2016-10-14) ## 0.2.0 (2016-10-14) ## 0.1.0 (2016-10-06) digest-0.10.7/Cargo.toml0000644000000027550000000000100104070ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "digest" version = "0.10.7" authors = ["RustCrypto Developers"] description = "Traits for cryptographic hash functions and message authentication codes" documentation = "https://docs.rs/digest" readme = "README.md" keywords = [ "digest", "crypto", "hash", ] categories = [ "cryptography", "no-std", ] license = "MIT OR Apache-2.0" repository = "https://github.com/RustCrypto/traits" [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--cfg", "docsrs", ] [dependencies.blobby] version = "0.3" optional = true [dependencies.block-buffer] version = "0.10" optional = true [dependencies.const-oid] version = "0.9" optional = true [dependencies.crypto-common] version = "0.1.3" [dependencies.subtle] version = "2.4" optional = true default-features = false [features] alloc = [] core-api = ["block-buffer"] default = ["core-api"] dev = ["blobby"] mac = ["subtle"] oid = ["const-oid"] rand_core = ["crypto-common/rand_core"] std = [ "alloc", "crypto-common/std", ] digest-0.10.7/Cargo.toml.orig000064400000000000000000000022001046102023000140510ustar 00000000000000[package] name = "digest" description = "Traits for cryptographic hash functions and message authentication codes" version = "0.10.7" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" readme = "README.md" edition = "2018" documentation = "https://docs.rs/digest" repository = "https://github.com/RustCrypto/traits" keywords = ["digest", "crypto", "hash"] categories = ["cryptography", "no-std"] [dependencies] crypto-common = { version = "0.1.3", path = "../crypto-common" } # optional dependencies block-buffer = { version = "0.10", optional = true } subtle = { version = "2.4", default-features = false, optional = true } blobby = { version = "0.3", optional = true } const-oid = { version = "0.9", optional = true } [features] default = ["core-api"] core-api = ["block-buffer"] # Enable Core API traits mac = ["subtle"] # Enable MAC traits rand_core = ["crypto-common/rand_core"] # Enable random key generation methods oid = ["const-oid"] # OID support. WARNING: Bumps MSRV to 1.57 alloc = [] std = ["alloc", "crypto-common/std"] dev = ["blobby"] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] digest-0.10.7/LICENSE-APACHE000064400000000000000000000251411046102023000131170ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. digest-0.10.7/LICENSE-MIT000064400000000000000000000020411046102023000126210ustar 00000000000000Copyright (c) 2017 Artyom Pavlov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. digest-0.10.7/README.md000064400000000000000000000113661046102023000124560ustar 00000000000000# RustCrypto: Digest Algorithm Traits [![crate][crate-image]][crate-link] [![Docs][docs-image]][docs-link] ![Apache2/MIT licensed][license-image] ![Rust Version][rustc-image] [![Project Chat][chat-image]][chat-link] [![Build Status][build-image]][build-link] Traits which describe functionality of [cryptographic hash functions][0], a.k.a. digest algorithms. See [RustCrypto/hashes][1] for implementations which use this trait. [Documentation][docs-link] ## Minimum Supported Rust Version Rust **1.41** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. ## SemVer Policy - All on-by-default features of this library are covered by SemVer - MSRV is considered exempt from SemVer as noted above ## Usage Let us demonstrate how to use crates in this repository using Sha256 as an example. First add the `sha2` crate to your `Cargo.toml`: ```toml [dependencies] sha2 = "0.10" ``` `sha2` and other crates re-export `digest` crate and `Digest` trait for convenience, so you don't have to add `digest` crate as an explicit dependency. Now you can write the following code: ```rust use sha2::{Sha256, Digest}; let mut hasher = Sha256::new(); let data = b"Hello world!"; hasher.update(data); // `input` can be called repeatedly and is generic over `AsRef<[u8]>` hasher.update("String data"); // Note that calling `finalize()` consumes hasher let hash = hasher.finalize(); println!("Result: {:x}", hash); ``` In this example `hash` has type [`GenericArray`][2], which is a generic alternative to `[u8; 64]`. Alternatively you can use chained approach, which is equivalent to the previous example: ```rust let hash = Sha256::new() .chain_update(b"Hello world!") .chain_update("String data") .finalize(); println!("Result: {:x}", hash); ``` If the whole message is available you also can use convenience `digest` method: ```rust let hash = Sha256::digest(b"my message"); println!("Result: {:x}", hash); ``` ### Hashing `Read`-able objects If you want to hash data from [`Read`][3] trait (e.g. from file) you can rely on implementation of [`Write`][4] trait (requires enabled-by-default `std` feature): ```rust use sha2::{Sha256, Digest}; use std::{fs, io}; let mut file = fs::File::open(&path)?; let mut hasher = Sha256::new(); let n = io::copy(&mut file, &mut hasher)?; let hash = hasher.finalize(); println!("Path: {}", path); println!("Bytes processed: {}", n); println!("Hash value: {:x}", hash); ``` ### Generic code You can write generic code over `Digest` (or other traits from `digest` crate) trait which will work over different hash functions: ```rust use digest::Digest; // Toy example, do not use it in practice! // Instead use crates from: https://github.com/RustCrypto/password-hashing fn hash_password(password: &str, salt: &str, output: &mut [u8]) { let mut hasher = D::new(); hasher.update(password.as_bytes()); hasher.update(b"$"); hasher.update(salt.as_bytes()); output.copy_from_slice(hasher.finalize().as_slice()) } let mut buf1 = [0u8; 32]; let mut buf2 = [0u8; 64]; hash_password::("my_password", "abcd", &mut buf1); hash_password::("my_password", "abcd", &mut buf2); ``` If you want to use hash functions with trait objects, use `digest::DynDigest` trait. ## License Licensed under either of: * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) * [MIT license](http://opensource.org/licenses/MIT) 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, shall be dual licensed as above, without any additional terms or conditions. [//]: # (badges) [crate-image]: https://img.shields.io/crates/v/digest.svg [crate-link]: https://crates.io/crates/digest [docs-image]: https://docs.rs/digest/badge.svg [docs-link]: https://docs.rs/digest/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg [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/260041-hashes [build-image]: https://github.com/RustCrypto/traits/workflows/digest/badge.svg?branch=master&event=push [build-link]: https://github.com/RustCrypto/traits/actions?query=workflow%3Adigest [//]: # (general links) [0]: https://en.wikipedia.org/wiki/Cryptographic_hash_function [1]: https://github.com/RustCrypto/hashes [2]: https://docs.rs/generic-array [3]: https://doc.rust-lang.org/std/io/trait.Read.html [4]: https://doc.rust-lang.org/std/io/trait.Write.html [5]: https://en.wikipedia.org/wiki/Hash-based_message_authentication_code [6]: https://github.com/RustCrypto/MACs digest-0.10.7/src/core_api/ct_variable.rs000064400000000000000000000136571046102023000163750ustar 00000000000000use super::{ AlgorithmName, Buffer, BufferKindUser, FixedOutputCore, Reset, TruncSide, UpdateCore, VariableOutputCore, }; use crate::HashMarker; #[cfg(feature = "mac")] use crate::MacMarker; #[cfg(feature = "oid")] use const_oid::{AssociatedOid, ObjectIdentifier}; use core::{fmt, marker::PhantomData}; use crypto_common::{ generic_array::{ArrayLength, GenericArray}, typenum::{IsLess, IsLessOrEqual, Le, LeEq, NonZero, U256}, Block, BlockSizeUser, OutputSizeUser, }; /// Dummy type used with [`CtVariableCoreWrapper`] in cases when /// resulting hash does not have a known OID. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct NoOid; /// Wrapper around [`VariableOutputCore`] which selects output size /// at compile time. #[derive(Clone)] pub struct CtVariableCoreWrapper where T: VariableOutputCore, OutSize: ArrayLength + IsLessOrEqual, LeEq: NonZero, T::BlockSize: IsLess, Le: NonZero, { inner: T, _out: PhantomData<(OutSize, O)>, } impl HashMarker for CtVariableCoreWrapper where T: VariableOutputCore + HashMarker, OutSize: ArrayLength + IsLessOrEqual, LeEq: NonZero, T::BlockSize: IsLess, Le: NonZero, { } #[cfg(feature = "mac")] impl MacMarker for CtVariableCoreWrapper where T: VariableOutputCore + MacMarker, OutSize: ArrayLength + IsLessOrEqual, LeEq: NonZero, T::BlockSize: IsLess, Le: NonZero, { } impl BlockSizeUser for CtVariableCoreWrapper where T: VariableOutputCore, OutSize: ArrayLength + IsLessOrEqual, LeEq: NonZero, T::BlockSize: IsLess, Le: NonZero, { type BlockSize = T::BlockSize; } impl UpdateCore for CtVariableCoreWrapper where T: VariableOutputCore, OutSize: ArrayLength + IsLessOrEqual, LeEq: NonZero, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn update_blocks(&mut self, blocks: &[Block]) { self.inner.update_blocks(blocks); } } impl OutputSizeUser for CtVariableCoreWrapper where T: VariableOutputCore, OutSize: ArrayLength + IsLessOrEqual + 'static, LeEq: NonZero, T::BlockSize: IsLess, Le: NonZero, { type OutputSize = OutSize; } impl BufferKindUser for CtVariableCoreWrapper where T: VariableOutputCore, OutSize: ArrayLength + IsLessOrEqual, LeEq: NonZero, T::BlockSize: IsLess, Le: NonZero, { type BufferKind = T::BufferKind; } impl FixedOutputCore for CtVariableCoreWrapper where T: VariableOutputCore, OutSize: ArrayLength + IsLessOrEqual + 'static, LeEq: NonZero, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn finalize_fixed_core( &mut self, buffer: &mut Buffer, out: &mut GenericArray, ) { let mut full_res = Default::default(); self.inner.finalize_variable_core(buffer, &mut full_res); let n = out.len(); let m = full_res.len() - n; match T::TRUNC_SIDE { TruncSide::Left => out.copy_from_slice(&full_res[..n]), TruncSide::Right => out.copy_from_slice(&full_res[m..]), } } } impl Default for CtVariableCoreWrapper where T: VariableOutputCore, OutSize: ArrayLength + IsLessOrEqual, LeEq: NonZero, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn default() -> Self { Self { inner: T::new(OutSize::USIZE).unwrap(), _out: PhantomData, } } } impl Reset for CtVariableCoreWrapper where T: VariableOutputCore, OutSize: ArrayLength + IsLessOrEqual, LeEq: NonZero, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn reset(&mut self) { *self = Default::default(); } } impl AlgorithmName for CtVariableCoreWrapper where T: VariableOutputCore + AlgorithmName, OutSize: ArrayLength + IsLessOrEqual, LeEq: NonZero, T::BlockSize: IsLess, Le: NonZero, { fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { T::write_alg_name(f)?; f.write_str("_")?; write!(f, "{}", OutSize::USIZE) } } #[cfg(feature = "oid")] #[cfg_attr(docsrs, doc(cfg(feature = "oid")))] impl AssociatedOid for CtVariableCoreWrapper where T: VariableOutputCore, O: AssociatedOid, OutSize: ArrayLength + IsLessOrEqual, LeEq: NonZero, T::BlockSize: IsLess, Le: NonZero, { const OID: ObjectIdentifier = O::OID; } /// Implement dummy type with hidden docs which is used to "carry" hasher /// OID for [`CtVariableCoreWrapper`]. #[macro_export] macro_rules! impl_oid_carrier { ($name:ident, $oid:literal) => { #[doc(hidden)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct $name; #[cfg(feature = "oid")] impl AssociatedOid for $name { const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap($oid); } }; } digest-0.10.7/src/core_api/rt_variable.rs000064400000000000000000000104721046102023000164040ustar 00000000000000use super::{AlgorithmName, TruncSide, UpdateCore, VariableOutputCore}; #[cfg(feature = "mac")] use crate::MacMarker; use crate::{HashMarker, InvalidBufferSize}; use crate::{InvalidOutputSize, Reset, Update, VariableOutput, VariableOutputReset}; use block_buffer::BlockBuffer; use core::fmt; use crypto_common::typenum::{IsLess, Le, NonZero, Unsigned, U256}; /// Wrapper around [`VariableOutputCore`] which selects output size /// at run time. #[derive(Clone)] pub struct RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore, T::BlockSize: IsLess, Le: NonZero, { core: T, buffer: BlockBuffer, output_size: usize, } impl RtVariableCoreWrapper where T: VariableOutputCore, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn finalize_dirty(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize> { let Self { core, buffer, output_size, } = self; if out.len() != *output_size || out.len() > Self::MAX_OUTPUT_SIZE { return Err(InvalidBufferSize); } let mut full_res = Default::default(); core.finalize_variable_core(buffer, &mut full_res); let n = out.len(); let m = full_res.len() - n; match T::TRUNC_SIDE { TruncSide::Left => out.copy_from_slice(&full_res[..n]), TruncSide::Right => out.copy_from_slice(&full_res[m..]), } Ok(()) } } impl HashMarker for RtVariableCoreWrapper where T: VariableOutputCore + HashMarker, T::BlockSize: IsLess, Le: NonZero, { } #[cfg(feature = "mac")] #[cfg_attr(docsrs, doc(cfg(feature = "mac")))] impl MacMarker for RtVariableCoreWrapper where T: VariableOutputCore + MacMarker, T::BlockSize: IsLess, Le: NonZero, { } impl Reset for RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore + Reset, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn reset(&mut self) { self.buffer.reset(); self.core.reset(); } } impl Update for RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn update(&mut self, input: &[u8]) { let Self { core, buffer, .. } = self; buffer.digest_blocks(input, |blocks| core.update_blocks(blocks)); } } impl VariableOutput for RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore, T::BlockSize: IsLess, Le: NonZero, { const MAX_OUTPUT_SIZE: usize = T::OutputSize::USIZE; fn new(output_size: usize) -> Result { let buffer = Default::default(); T::new(output_size).map(|core| Self { core, buffer, output_size, }) } fn output_size(&self) -> usize { self.output_size } fn finalize_variable(mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize> { self.finalize_dirty(out) } } impl VariableOutputReset for RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore + Reset, T::BlockSize: IsLess, Le: NonZero, { fn finalize_variable_reset(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize> { self.finalize_dirty(out)?; self.core.reset(); self.buffer.reset(); Ok(()) } } impl fmt::Debug for RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore + AlgorithmName, T::BlockSize: IsLess, Le: NonZero, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { T::write_alg_name(f)?; f.write_str(" { .. }") } } #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl std::io::Write for RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn write(&mut self, buf: &[u8]) -> std::io::Result { Update::update(self, buf); Ok(buf.len()) } #[inline] fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } digest-0.10.7/src/core_api/wrapper.rs000064400000000000000000000156001046102023000155700ustar 00000000000000use super::{ AlgorithmName, Buffer, BufferKindUser, ExtendableOutputCore, FixedOutputCore, OutputSizeUser, Reset, UpdateCore, XofReaderCoreWrapper, }; use crate::{ ExtendableOutput, ExtendableOutputReset, FixedOutput, FixedOutputReset, HashMarker, Update, }; use block_buffer::BlockBuffer; use core::fmt; use crypto_common::{ typenum::{IsLess, Le, NonZero, U256}, BlockSizeUser, InvalidLength, Key, KeyInit, KeySizeUser, Output, }; #[cfg(feature = "mac")] use crate::MacMarker; #[cfg(feature = "oid")] use const_oid::{AssociatedOid, ObjectIdentifier}; /// Wrapper around [`BufferKindUser`]. /// /// It handles data buffering and implements the slice-based traits. #[derive(Clone, Default)] pub struct CoreWrapper where T: BufferKindUser, T::BlockSize: IsLess, Le: NonZero, { core: T, buffer: BlockBuffer, } impl HashMarker for CoreWrapper where T: BufferKindUser + HashMarker, T::BlockSize: IsLess, Le: NonZero, { } #[cfg(feature = "mac")] #[cfg_attr(docsrs, doc(cfg(feature = "mac")))] impl MacMarker for CoreWrapper where T: BufferKindUser + MacMarker, T::BlockSize: IsLess, Le: NonZero, { } // this blanket impl is needed for HMAC impl BlockSizeUser for CoreWrapper where T: BufferKindUser + HashMarker, T::BlockSize: IsLess, Le: NonZero, { type BlockSize = T::BlockSize; } impl CoreWrapper where T: BufferKindUser, T::BlockSize: IsLess, Le: NonZero, { /// Create new wrapper from `core`. #[inline] pub fn from_core(core: T) -> Self { let buffer = Default::default(); Self { core, buffer } } /// Decompose wrapper into inner parts. #[inline] pub fn decompose(self) -> (T, Buffer) { let Self { core, buffer } = self; (core, buffer) } } impl KeySizeUser for CoreWrapper where T: BufferKindUser + KeySizeUser, T::BlockSize: IsLess, Le: NonZero, { type KeySize = T::KeySize; } impl KeyInit for CoreWrapper where T: BufferKindUser + KeyInit, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn new(key: &Key) -> Self { Self { core: T::new(key), buffer: Default::default(), } } #[inline] fn new_from_slice(key: &[u8]) -> Result { Ok(Self { core: T::new_from_slice(key)?, buffer: Default::default(), }) } } impl fmt::Debug for CoreWrapper where T: BufferKindUser + AlgorithmName, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { T::write_alg_name(f)?; f.write_str(" { .. }") } } impl Reset for CoreWrapper where T: BufferKindUser + Reset, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn reset(&mut self) { self.core.reset(); self.buffer.reset(); } } impl Update for CoreWrapper where T: BufferKindUser + UpdateCore, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn update(&mut self, input: &[u8]) { let Self { core, buffer } = self; buffer.digest_blocks(input, |blocks| core.update_blocks(blocks)); } } impl OutputSizeUser for CoreWrapper where T: BufferKindUser + OutputSizeUser, T::BlockSize: IsLess, Le: NonZero, { type OutputSize = T::OutputSize; } impl FixedOutput for CoreWrapper where T: FixedOutputCore, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn finalize_into(mut self, out: &mut Output) { let Self { core, buffer } = &mut self; core.finalize_fixed_core(buffer, out); } } impl FixedOutputReset for CoreWrapper where T: FixedOutputCore + Reset, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn finalize_into_reset(&mut self, out: &mut Output) { let Self { core, buffer } = self; core.finalize_fixed_core(buffer, out); core.reset(); buffer.reset(); } } impl ExtendableOutput for CoreWrapper where T: ExtendableOutputCore, T::BlockSize: IsLess, Le: NonZero, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { type Reader = XofReaderCoreWrapper; #[inline] fn finalize_xof(self) -> Self::Reader { let (mut core, mut buffer) = self.decompose(); let core = core.finalize_xof_core(&mut buffer); let buffer = Default::default(); Self::Reader { core, buffer } } } impl ExtendableOutputReset for CoreWrapper where T: ExtendableOutputCore + Reset, T::BlockSize: IsLess, Le: NonZero, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { #[inline] fn finalize_xof_reset(&mut self) -> Self::Reader { let Self { core, buffer } = self; let reader_core = core.finalize_xof_core(buffer); core.reset(); buffer.reset(); let buffer = Default::default(); Self::Reader { core: reader_core, buffer, } } } #[cfg(feature = "oid")] #[cfg_attr(docsrs, doc(cfg(feature = "oid")))] impl AssociatedOid for CoreWrapper where T: BufferKindUser + AssociatedOid, T::BlockSize: IsLess, Le: NonZero, { const OID: ObjectIdentifier = T::OID; } #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl std::io::Write for CoreWrapper where T: BufferKindUser + UpdateCore, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn write(&mut self, buf: &[u8]) -> std::io::Result { Update::update(self, buf); Ok(buf.len()) } #[inline] fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } /// A proxy trait to a core type implemented by [`CoreWrapper`] // TODO: replace with an inherent associated type on stabilization: // https://github.com/rust-lang/rust/issues/8995 pub trait CoreProxy: sealed::Sealed { /// Type wrapped by [`CoreWrapper`]. type Core; } mod sealed { pub trait Sealed {} } impl sealed::Sealed for CoreWrapper where T: BufferKindUser, T::BlockSize: IsLess, Le: NonZero, { } impl CoreProxy for CoreWrapper where T: BufferKindUser, T::BlockSize: IsLess, Le: NonZero, { type Core = T; } digest-0.10.7/src/core_api/xof_reader.rs000064400000000000000000000031101046102023000162170ustar 00000000000000use super::{AlgorithmName, XofReaderCore}; use crate::XofReader; use block_buffer::EagerBuffer; use core::fmt; use crypto_common::typenum::{IsLess, Le, NonZero, U256}; /// Wrapper around [`XofReaderCore`] implementations. /// /// It handles data buffering and implements the mid-level traits. #[derive(Clone, Default)] pub struct XofReaderCoreWrapper where T: XofReaderCore, T::BlockSize: IsLess, Le: NonZero, { pub(super) core: T, pub(super) buffer: EagerBuffer, } impl fmt::Debug for XofReaderCoreWrapper where T: XofReaderCore + AlgorithmName, T::BlockSize: IsLess, Le: NonZero, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { T::write_alg_name(f)?; f.write_str(" { .. }") } } impl XofReader for XofReaderCoreWrapper where T: XofReaderCore, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn read(&mut self, buffer: &mut [u8]) { let Self { core, buffer: buf } = self; buf.set_data(buffer, |blocks| { for block in blocks { *block = core.read_block(); } }); } } #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl std::io::Read for XofReaderCoreWrapper where T: XofReaderCore, T::BlockSize: IsLess, Le: NonZero, { #[inline] fn read(&mut self, buf: &mut [u8]) -> std::io::Result { XofReader::read(self, buf); Ok(buf.len()) } } digest-0.10.7/src/core_api.rs000064400000000000000000000101721046102023000141070ustar 00000000000000//! Low-level traits operating on blocks and wrappers around them. //! //! Usage of traits in this module in user code is discouraged. Instead use //! core algorithm wrapped by the wrapper types, which implement the //! higher-level traits. use crate::InvalidOutputSize; pub use crypto_common::{AlgorithmName, Block, BlockSizeUser, OutputSizeUser, Reset}; use block_buffer::{BlockBuffer, BufferKind}; use crypto_common::{ typenum::{IsLess, Le, NonZero, U256}, Output, }; mod ct_variable; mod rt_variable; mod wrapper; mod xof_reader; pub use ct_variable::CtVariableCoreWrapper; pub use rt_variable::RtVariableCoreWrapper; pub use wrapper::{CoreProxy, CoreWrapper}; pub use xof_reader::XofReaderCoreWrapper; /// Buffer type used by type which implements [`BufferKindUser`]. pub type Buffer = BlockBuffer<::BlockSize, ::BufferKind>; /// Types which consume data in blocks. pub trait UpdateCore: BlockSizeUser { /// Update state using the provided data blocks. fn update_blocks(&mut self, blocks: &[Block]); } /// Types which use [`BlockBuffer`] functionality. pub trait BufferKindUser: BlockSizeUser { /// Block buffer kind over which type operates. type BufferKind: BufferKind; } /// Core trait for hash functions with fixed output size. pub trait FixedOutputCore: UpdateCore + BufferKindUser + OutputSizeUser where Self::BlockSize: IsLess, Le: NonZero, { /// Finalize state using remaining data stored in the provided block buffer, /// write result into provided array and leave `self` in a dirty state. fn finalize_fixed_core(&mut self, buffer: &mut Buffer, out: &mut Output); } /// Core trait for hash functions with extendable (XOF) output size. pub trait ExtendableOutputCore: UpdateCore + BufferKindUser where Self::BlockSize: IsLess, Le: NonZero, { /// XOF reader core state. type ReaderCore: XofReaderCore; /// Retrieve XOF reader using remaining data stored in the block buffer /// and leave hasher in a dirty state. fn finalize_xof_core(&mut self, buffer: &mut Buffer) -> Self::ReaderCore; } /// Core reader trait for extendable-output function (XOF) result. pub trait XofReaderCore: BlockSizeUser { /// Read next XOF block. fn read_block(&mut self) -> Block; } /// Core trait for hash functions with variable output size. /// /// Maximum output size is equal to [`OutputSizeUser::OutputSize`]. /// Users are expected to truncate result returned by the /// [`finalize_variable_core`] to `output_size` passed to the [`new`] method /// during construction. Truncation side is defined by the [`TRUNC_SIDE`] /// associated constant. /// /// [`finalize_variable_core`]: VariableOutputCore::finalize_variable_core /// [`new`]: VariableOutputCore::new /// [`TRUNC_SIDE`]: VariableOutputCore::TRUNC_SIDE pub trait VariableOutputCore: UpdateCore + OutputSizeUser + BufferKindUser + Sized where Self::BlockSize: IsLess, Le: NonZero, { /// Side which should be used in a truncated result. const TRUNC_SIDE: TruncSide; /// Initialize hasher state for given output size. /// /// Returns [`InvalidOutputSize`] if `output_size` is not valid for /// the algorithm, e.g. if it's bigger than the [`OutputSize`] /// associated type. /// /// [`OutputSize`]: OutputSizeUser::OutputSize fn new(output_size: usize) -> Result; /// Finalize hasher and write full hashing result into the `out` buffer. /// /// The result must be truncated to `output_size` used during hasher /// construction. Truncation side is defined by the [`TRUNC_SIDE`] /// associated constant. /// /// [`TRUNC_SIDE`]: VariableOutputCore::TRUNC_SIDE fn finalize_variable_core(&mut self, buffer: &mut Buffer, out: &mut Output); } /// Type which used for defining truncation side in the [`VariableOutputCore`] /// trait. #[derive(Copy, Clone, Debug)] pub enum TruncSide { /// Truncate left side, i.e. `&out[..n]`. Left, /// Truncate right side, i.e. `&out[m..]`. Right, } digest-0.10.7/src/dev/fixed.rs000064400000000000000000000037451046102023000142130ustar 00000000000000use crate::{Digest, FixedOutput, FixedOutputReset, HashMarker, Update}; use core::fmt::Debug; /// Fixed-output resettable digest test via the `Digest` trait pub fn fixed_reset_test(input: &[u8], output: &[u8]) -> Option<&'static str> where D: FixedOutputReset + Debug + Clone + Default + Update + HashMarker, { let mut hasher = D::new(); // Test that it works when accepting the message all at once hasher.update(input); let mut hasher2 = hasher.clone(); if hasher.finalize()[..] != output[..] { return Some("whole message"); } // Test if reset works correctly hasher2.reset(); hasher2.update(input); if hasher2.finalize_reset()[..] != output[..] { return Some("whole message after reset"); } // Test that it works when accepting the message in chunks for n in 1..core::cmp::min(17, input.len()) { let mut hasher = D::new(); for chunk in input.chunks(n) { hasher.update(chunk); hasher2.update(chunk); } if hasher.finalize()[..] != output[..] { return Some("message in chunks"); } if hasher2.finalize_reset()[..] != output[..] { return Some("message in chunks"); } } None } /// Variable-output resettable digest test pub fn fixed_test(input: &[u8], output: &[u8]) -> Option<&'static str> where D: FixedOutput + Default + Debug + Clone, { let mut hasher = D::default(); // Test that it works when accepting the message all at once hasher.update(input); if hasher.finalize_fixed()[..] != output[..] { return Some("whole message"); } // Test that it works when accepting the message in chunks for n in 1..core::cmp::min(17, input.len()) { let mut hasher = D::default(); for chunk in input.chunks(n) { hasher.update(chunk); } if hasher.finalize_fixed()[..] != output[..] { return Some("message in chunks"); } } None } digest-0.10.7/src/dev/mac.rs000064400000000000000000000135731046102023000136540ustar 00000000000000/// Define MAC test #[macro_export] #[cfg(feature = "mac")] #[cfg_attr(docsrs, doc(cfg(all(feature = "dev", feature = "mac"))))] macro_rules! new_mac_test { ($name:ident, $test_name:expr, $mac:ty $(,)?) => { digest::new_mac_test!($name, $test_name, $mac, ""); }; ($name:ident, $test_name:expr, $mac:ty, trunc_left $(,)?) => { digest::new_mac_test!($name, $test_name, $mac, "left"); }; ($name:ident, $test_name:expr, $mac:ty, trunc_right $(,)?) => { digest::new_mac_test!($name, $test_name, $mac, "right"); }; ($name:ident, $test_name:expr, $mac:ty, $trunc:expr $(,)?) => { #[test] fn $name() { use core::cmp::min; use digest::dev::blobby::Blob3Iterator; use digest::Mac; fn run_test(key: &[u8], input: &[u8], tag: &[u8]) -> Option<&'static str> { let mac0 = <$mac as Mac>::new_from_slice(key).unwrap(); let mut mac = mac0.clone(); mac.update(input); let result = mac.finalize().into_bytes(); let n = tag.len(); let result_bytes = match $trunc { "left" => &result[..n], "right" => &result[result.len() - n..], _ => &result[..], }; if result_bytes != tag { return Some("whole message"); } // test reading different chunk sizes for chunk_size in 1..min(64, input.len()) { let mut mac = mac0.clone(); for chunk in input.chunks(chunk_size) { mac.update(chunk); } let res = match $trunc { "left" => mac.verify_truncated_left(tag), "right" => mac.verify_truncated_right(tag), _ => mac.verify_slice(tag), }; if res.is_err() { return Some("chunked message"); } } None } let data = include_bytes!(concat!("data/", $test_name, ".blb")); for (i, row) in Blob3Iterator::new(data).unwrap().enumerate() { let [key, input, tag] = row.unwrap(); if let Some(desc) = run_test(key, input, tag) { panic!( "\n\ Failed test №{}: {}\n\ key:\t{:?}\n\ input:\t{:?}\n\ tag:\t{:?}\n", i, desc, key, input, tag, ); } } } }; } /// Define resettable MAC test #[macro_export] #[cfg(feature = "mac")] #[cfg_attr(docsrs, doc(cfg(all(feature = "dev", feature = "mac"))))] macro_rules! new_resettable_mac_test { ($name:ident, $test_name:expr, $mac:ty $(,)?) => { digest::new_resettable_mac_test!($name, $test_name, $mac, ""); }; ($name:ident, $test_name:expr, $mac:ty, trunc_left $(,)?) => { digest::new_resettable_mac_test!($name, $test_name, $mac, "left"); }; ($name:ident, $test_name:expr, $mac:ty, trunc_right $(,)?) => { digest::new_resettable_mac_test!($name, $test_name, $mac, "right"); }; ($name:ident, $test_name:expr, $mac:ty, $trunc:expr $(,)?) => { #[test] fn $name() { use core::cmp::min; use digest::dev::blobby::Blob3Iterator; use digest::Mac; fn run_test(key: &[u8], input: &[u8], tag: &[u8]) -> Option<&'static str> { let mac0 = <$mac as Mac>::new_from_slice(key).unwrap(); let mut mac = mac0.clone(); mac.update(input); let result = mac.finalize_reset().into_bytes(); let n = tag.len(); let result_bytes = match $trunc { "left" => &result[..n], "right" => &result[result.len() - n..], _ => &result[..], }; if result_bytes != tag { return Some("whole message"); } // test if reset worked correctly mac.update(input); let res = match $trunc { "left" => mac.verify_truncated_left(tag), "right" => mac.verify_truncated_right(tag), _ => mac.verify_slice(tag), }; if res.is_err() { return Some("after reset"); } // test reading different chunk sizes for chunk_size in 1..min(64, input.len()) { let mut mac = mac0.clone(); for chunk in input.chunks(chunk_size) { mac.update(chunk); } let res = match $trunc { "left" => mac.verify_truncated_left(tag), "right" => mac.verify_truncated_right(tag), _ => mac.verify_slice(tag), }; if res.is_err() { return Some("chunked message"); } } None } let data = include_bytes!(concat!("data/", $test_name, ".blb")); for (i, row) in Blob3Iterator::new(data).unwrap().enumerate() { let [key, input, tag] = row.unwrap(); if let Some(desc) = run_test(key, input, tag) { panic!( "\n\ Failed test №{}: {}\n\ key:\t{:?}\n\ input:\t{:?}\n\ tag:\t{:?}\n", i, desc, key, input, tag, ); } } } }; } digest-0.10.7/src/dev/rng.rs000064400000000000000000000017261046102023000136770ustar 00000000000000//! Xorshift RNG used for tests. Based on the `rand_xorshift` crate. use core::num::Wrapping; /// Initial RNG state used in tests. // chosen by fair dice roll. guaranteed to be random. pub(crate) const RNG: XorShiftRng = XorShiftRng { x: Wrapping(0x0787_3B4A), y: Wrapping(0xFAAB_8FFE), z: Wrapping(0x1745_980F), w: Wrapping(0xB0AD_B4F3), }; /// Xorshift RNG instance/ pub(crate) struct XorShiftRng { x: Wrapping, y: Wrapping, z: Wrapping, w: Wrapping, } impl XorShiftRng { pub(crate) fn fill(&mut self, buf: &mut [u8; 1024]) { for chunk in buf.chunks_exact_mut(4) { chunk.copy_from_slice(&self.next_u32().to_le_bytes()); } } fn next_u32(&mut self) -> u32 { let x = self.x; let t = x ^ (x << 11); self.x = self.y; self.y = self.z; self.z = self.w; let w = self.w; self.w = w ^ (w >> 19) ^ (t ^ (t >> 8)); self.w.0 } } digest-0.10.7/src/dev/variable.rs000064400000000000000000000047741046102023000147040ustar 00000000000000use crate::{VariableOutput, VariableOutputReset}; use core::fmt::Debug; /// Variable-output resettable digest test pub fn variable_reset_test(input: &[u8], output: &[u8]) -> Option<&'static str> where D: VariableOutputReset + Debug + Clone, { let mut hasher = D::new(output.len()).unwrap(); let mut buf = [0u8; 128]; let buf = &mut buf[..output.len()]; // Test that it works when accepting the message all at once hasher.update(input); let mut hasher2 = hasher.clone(); hasher.finalize_variable(buf).unwrap(); if buf != output { return Some("whole message"); } buf.iter_mut().for_each(|b| *b = 0); // Test if reset works correctly hasher2.reset(); hasher2.update(input); hasher2.finalize_variable_reset(buf).unwrap(); if buf != output { return Some("whole message after reset"); } buf.iter_mut().for_each(|b| *b = 0); // Test that it works when accepting the message in chunks for n in 1..core::cmp::min(17, input.len()) { let mut hasher = D::new(output.len()).unwrap(); for chunk in input.chunks(n) { hasher.update(chunk); hasher2.update(chunk); } hasher.finalize_variable(buf).unwrap(); if buf != output { return Some("message in chunks"); } buf.iter_mut().for_each(|b| *b = 0); hasher2.finalize_variable_reset(buf).unwrap(); if buf != output { return Some("message in chunks"); } buf.iter_mut().for_each(|b| *b = 0); } None } /// Variable-output resettable digest test pub fn variable_test(input: &[u8], output: &[u8]) -> Option<&'static str> where D: VariableOutput + Debug + Clone, { let mut hasher = D::new(output.len()).unwrap(); let mut buf = [0u8; 128]; let buf = &mut buf[..output.len()]; // Test that it works when accepting the message all at once hasher.update(input); hasher.finalize_variable(buf).unwrap(); if buf != output { return Some("whole message"); } buf.iter_mut().for_each(|b| *b = 0); // Test that it works when accepting the message in chunks for n in 1..core::cmp::min(17, input.len()) { let mut hasher = D::new(output.len()).unwrap(); for chunk in input.chunks(n) { hasher.update(chunk); } hasher.finalize_variable(buf).unwrap(); if buf != output { return Some("message in chunks"); } buf.iter_mut().for_each(|b| *b = 0); } None } digest-0.10.7/src/dev/xof.rs000064400000000000000000000027101046102023000136770ustar 00000000000000use crate::ExtendableOutputReset; use core::fmt::Debug; /// Resettable XOF test pub fn xof_reset_test(input: &[u8], output: &[u8]) -> Option<&'static str> where D: ExtendableOutputReset + Default + Debug + Clone, { let mut hasher = D::default(); let mut buf = [0u8; 1024]; let buf = &mut buf[..output.len()]; // Test that it works when accepting the message all at once hasher.update(input); let mut hasher2 = hasher.clone(); hasher.finalize_xof_into(buf); if buf != output { return Some("whole message"); } buf.iter_mut().for_each(|b| *b = 0); // Test if reset works correctly hasher2.reset(); hasher2.update(input); hasher2.finalize_xof_reset_into(buf); if buf != output { return Some("whole message after reset"); } buf.iter_mut().for_each(|b| *b = 0); // Test that it works when accepting the message in chunks for n in 1..core::cmp::min(17, input.len()) { let mut hasher = D::default(); for chunk in input.chunks(n) { hasher.update(chunk); hasher2.update(chunk); } hasher.finalize_xof_into(buf); if buf != output { return Some("message in chunks"); } buf.iter_mut().for_each(|b| *b = 0); hasher2.finalize_xof_reset_into(buf); if buf != output { return Some("message in chunks"); } buf.iter_mut().for_each(|b| *b = 0); } None } digest-0.10.7/src/dev.rs000064400000000000000000000037221046102023000131070ustar 00000000000000//! Development-related functionality pub use blobby; mod fixed; mod mac; mod rng; mod variable; mod xof; pub use fixed::*; pub use mac::*; pub use variable::*; pub use xof::*; /// Define hash function test #[macro_export] #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] macro_rules! new_test { ($name:ident, $test_name:expr, $hasher:ty, $test_func:ident $(,)?) => { #[test] fn $name() { use digest::dev::blobby::Blob2Iterator; let data = include_bytes!(concat!("data/", $test_name, ".blb")); for (i, row) in Blob2Iterator::new(data).unwrap().enumerate() { let [input, output] = row.unwrap(); if let Some(desc) = $test_func::<$hasher>(input, output) { panic!( "\n\ Failed test №{}: {}\n\ input:\t{:?}\n\ output:\t{:?}\n", i, desc, input, output, ); } } } }; } /// Define [`Update`][crate::Update] impl benchmark #[macro_export] #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] macro_rules! bench_update { ( $init:expr; $($name:ident $bs:expr;)* ) => { $( #[bench] fn $name(b: &mut Bencher) { let mut d = $init; let data = [0; $bs]; b.iter(|| { digest::Update::update(&mut d, &data[..]); }); b.bytes = $bs; } )* }; } /// Feed ~1 MiB of pseudorandom data to an updatable state. pub fn feed_rand_16mib(d: &mut D) { let buf = &mut [0u8; 1024]; let mut rng = rng::RNG; let n = 16 * (1 << 20) / buf.len(); for _ in 0..n { rng.fill(buf); d.update(buf); // additional byte, so size of fed data // will not be multiple of block size d.update(&[42]); } } digest-0.10.7/src/digest.rs000064400000000000000000000150751046102023000136140ustar 00000000000000use super::{FixedOutput, FixedOutputReset, InvalidBufferSize, Reset, Update}; use crypto_common::{typenum::Unsigned, Output, OutputSizeUser}; #[cfg(feature = "alloc")] use alloc::boxed::Box; /// Marker trait for cryptographic hash functions. pub trait HashMarker {} /// Convenience wrapper trait covering functionality of cryptographic hash /// functions with fixed output size. /// /// This trait wraps [`Update`], [`FixedOutput`], [`Default`], and /// [`HashMarker`] traits and provides additional convenience methods. pub trait Digest: OutputSizeUser { /// Create new hasher instance. fn new() -> Self; /// Create new hasher instance which has processed the provided data. fn new_with_prefix(data: impl AsRef<[u8]>) -> Self; /// Process data, updating the internal state. fn update(&mut self, data: impl AsRef<[u8]>); /// Process input data in a chained manner. #[must_use] fn chain_update(self, data: impl AsRef<[u8]>) -> Self; /// Retrieve result and consume hasher instance. fn finalize(self) -> Output; /// Write result into provided array and consume the hasher instance. fn finalize_into(self, out: &mut Output); /// Retrieve result and reset hasher instance. fn finalize_reset(&mut self) -> Output where Self: FixedOutputReset; /// Write result into provided array and reset the hasher instance. fn finalize_into_reset(&mut self, out: &mut Output) where Self: FixedOutputReset; /// Reset hasher instance to its initial state. fn reset(&mut self) where Self: Reset; /// Get output size of the hasher fn output_size() -> usize; /// Compute hash of `data`. fn digest(data: impl AsRef<[u8]>) -> Output; } impl Digest for D { #[inline] fn new() -> Self { Self::default() } #[inline] fn new_with_prefix(data: impl AsRef<[u8]>) -> Self where Self: Default + Sized, { let mut h = Self::default(); h.update(data.as_ref()); h } #[inline] fn update(&mut self, data: impl AsRef<[u8]>) { Update::update(self, data.as_ref()); } #[inline] fn chain_update(mut self, data: impl AsRef<[u8]>) -> Self { Update::update(&mut self, data.as_ref()); self } #[inline] fn finalize(self) -> Output { FixedOutput::finalize_fixed(self) } #[inline] fn finalize_into(self, out: &mut Output) { FixedOutput::finalize_into(self, out); } #[inline] fn finalize_reset(&mut self) -> Output where Self: FixedOutputReset, { FixedOutputReset::finalize_fixed_reset(self) } #[inline] fn finalize_into_reset(&mut self, out: &mut Output) where Self: FixedOutputReset, { FixedOutputReset::finalize_into_reset(self, out); } #[inline] fn reset(&mut self) where Self: Reset, { Reset::reset(self) } #[inline] fn output_size() -> usize { Self::OutputSize::to_usize() } #[inline] fn digest(data: impl AsRef<[u8]>) -> Output { let mut hasher = Self::default(); hasher.update(data.as_ref()); hasher.finalize() } } /// Modification of the [`Digest`] trait suitable for trait objects. pub trait DynDigest { /// Digest input data. /// /// This method can be called repeatedly for use with streaming messages. fn update(&mut self, data: &[u8]); /// Retrieve result and reset hasher instance #[cfg(feature = "alloc")] #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] fn finalize_reset(&mut self) -> Box<[u8]> { let mut result = vec![0; self.output_size()]; self.finalize_into_reset(&mut result).unwrap(); result.into_boxed_slice() } /// Retrieve result and consume boxed hasher instance #[cfg(feature = "alloc")] #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] #[allow(clippy::boxed_local)] fn finalize(mut self: Box) -> Box<[u8]> { let mut result = vec![0; self.output_size()]; self.finalize_into_reset(&mut result).unwrap(); result.into_boxed_slice() } /// Write result into provided array and consume the hasher instance. /// /// Returns error if buffer length is not equal to `output_size`. fn finalize_into(self, buf: &mut [u8]) -> Result<(), InvalidBufferSize>; /// Write result into provided array and reset the hasher instance. /// /// Returns error if buffer length is not equal to `output_size`. fn finalize_into_reset(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize>; /// Reset hasher instance to its initial state. fn reset(&mut self); /// Get output size of the hasher fn output_size(&self) -> usize; /// Clone hasher state into a boxed trait object #[cfg(feature = "alloc")] #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] fn box_clone(&self) -> Box; } impl DynDigest for D { fn update(&mut self, data: &[u8]) { Update::update(self, data); } #[cfg(feature = "alloc")] fn finalize_reset(&mut self) -> Box<[u8]> { FixedOutputReset::finalize_fixed_reset(self) .to_vec() .into_boxed_slice() } #[cfg(feature = "alloc")] fn finalize(self: Box) -> Box<[u8]> { FixedOutput::finalize_fixed(*self) .to_vec() .into_boxed_slice() } fn finalize_into(self, buf: &mut [u8]) -> Result<(), InvalidBufferSize> { if buf.len() == self.output_size() { FixedOutput::finalize_into(self, Output::::from_mut_slice(buf)); Ok(()) } else { Err(InvalidBufferSize) } } fn finalize_into_reset(&mut self, buf: &mut [u8]) -> Result<(), InvalidBufferSize> { if buf.len() == self.output_size() { FixedOutputReset::finalize_into_reset(self, Output::::from_mut_slice(buf)); Ok(()) } else { Err(InvalidBufferSize) } } fn reset(&mut self) { Reset::reset(self); } fn output_size(&self) -> usize { ::OutputSize::to_usize() } #[cfg(feature = "alloc")] fn box_clone(&self) -> Box { Box::new(self.clone()) } } #[cfg(feature = "alloc")] #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] impl Clone for Box { fn clone(&self) -> Self { self.box_clone() } } digest-0.10.7/src/lib.rs000064400000000000000000000246171046102023000131050ustar 00000000000000//! This crate provides traits which describe functionality of cryptographic hash //! functions and Message Authentication algorithms. //! //! Traits in this repository are organized into the following levels: //! //! - **High-level convenience traits**: [`Digest`], [`DynDigest`], [`Mac`]. //! Wrappers around lower-level traits for most common use-cases. Users should //! usually prefer using these traits. //! - **Mid-level traits**: [`Update`], [`FixedOutput`], [`FixedOutputReset`], //! [`ExtendableOutput`], [`ExtendableOutputReset`], [`XofReader`], //! [`VariableOutput`], [`Reset`], [`KeyInit`], and [`InnerInit`]. These //! traits atomically describe available functionality of an algorithm. //! - **Marker traits**: [`HashMarker`], [`MacMarker`]. Used to distinguish //! different algorithm classes. //! - **Low-level traits** defined in the [`core_api`] module. These traits //! operate at a block-level and do not contain any built-in buffering. //! They are intended to be implemented by low-level algorithm providers only. //! Usually they should not be used in application-level code. //! //! Additionally hash functions implement traits from the standard library: //! [`Default`], [`Clone`], [`Write`][std::io::Write]. The latter is //! feature-gated behind `std` feature, which is usually enabled by default //! by hash implementation crates. #![no_std] #![cfg_attr(docsrs, feature(doc_cfg))] #![forbid(unsafe_code)] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" )] #![warn(missing_docs, rust_2018_idioms)] #[cfg(feature = "alloc")] #[macro_use] extern crate alloc; #[cfg(feature = "std")] extern crate std; #[cfg(feature = "rand_core")] #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] pub use crypto_common::rand_core; #[cfg(feature = "alloc")] use alloc::boxed::Box; #[cfg(feature = "dev")] #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] pub mod dev; #[cfg(feature = "core-api")] #[cfg_attr(docsrs, doc(cfg(feature = "core-api")))] pub mod core_api; mod digest; #[cfg(feature = "mac")] mod mac; #[cfg(feature = "core-api")] #[cfg_attr(docsrs, doc(cfg(feature = "core-api")))] pub use block_buffer; #[cfg(feature = "oid")] #[cfg_attr(docsrs, doc(cfg(feature = "oid")))] pub use const_oid; pub use crypto_common; pub use crate::digest::{Digest, DynDigest, HashMarker}; pub use crypto_common::{generic_array, typenum, typenum::consts, Output, OutputSizeUser, Reset}; #[cfg(feature = "mac")] pub use crypto_common::{InnerInit, InvalidLength, Key, KeyInit}; #[cfg(feature = "mac")] pub use mac::{CtOutput, Mac, MacError, MacMarker}; use core::fmt; /// Types which consume data with byte granularity. pub trait Update { /// Update state using the provided data. fn update(&mut self, data: &[u8]); /// Digest input data in a chained manner. #[must_use] fn chain(mut self, data: impl AsRef<[u8]>) -> Self where Self: Sized, { self.update(data.as_ref()); self } } /// Trait for hash functions with fixed-size output. pub trait FixedOutput: Update + OutputSizeUser + Sized { /// Consume value and write result into provided array. fn finalize_into(self, out: &mut Output); /// Retrieve result and consume the hasher instance. #[inline] fn finalize_fixed(self) -> Output { let mut out = Default::default(); self.finalize_into(&mut out); out } } /// Trait for hash functions with fixed-size output able to reset themselves. pub trait FixedOutputReset: FixedOutput + Reset { /// Write result into provided array and reset the hasher state. fn finalize_into_reset(&mut self, out: &mut Output); /// Retrieve result and reset the hasher state. #[inline] fn finalize_fixed_reset(&mut self) -> Output { let mut out = Default::default(); self.finalize_into_reset(&mut out); out } } /// Trait for reader types which are used to extract extendable output /// from a XOF (extendable-output function) result. pub trait XofReader { /// Read output into the `buffer`. Can be called an unlimited number of times. fn read(&mut self, buffer: &mut [u8]); /// Read output into a boxed slice of the specified size. /// /// Can be called an unlimited number of times in combination with `read`. /// /// `Box<[u8]>` is used instead of `Vec` to save stack space, since /// they have size of 2 and 3 words respectively. #[cfg(feature = "alloc")] #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] fn read_boxed(&mut self, n: usize) -> Box<[u8]> { let mut buf = vec![0u8; n].into_boxed_slice(); self.read(&mut buf); buf } } /// Trait for hash functions with extendable-output (XOF). pub trait ExtendableOutput: Sized + Update { /// Reader type Reader: XofReader; /// Retrieve XOF reader and consume hasher instance. fn finalize_xof(self) -> Self::Reader; /// Finalize XOF and write result into `out`. fn finalize_xof_into(self, out: &mut [u8]) { self.finalize_xof().read(out); } /// Compute hash of `data` and write it into `output`. fn digest_xof(input: impl AsRef<[u8]>, output: &mut [u8]) where Self: Default, { let mut hasher = Self::default(); hasher.update(input.as_ref()); hasher.finalize_xof().read(output); } /// Retrieve result into a boxed slice of the specified size and consume /// the hasher. /// /// `Box<[u8]>` is used instead of `Vec` to save stack space, since /// they have size of 2 and 3 words respectively. #[cfg(feature = "alloc")] #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] fn finalize_boxed(self, output_size: usize) -> Box<[u8]> { let mut buf = vec![0u8; output_size].into_boxed_slice(); self.finalize_xof().read(&mut buf); buf } } /// Trait for hash functions with extendable-output (XOF) able to reset themselves. pub trait ExtendableOutputReset: ExtendableOutput + Reset { /// Retrieve XOF reader and reset hasher instance state. fn finalize_xof_reset(&mut self) -> Self::Reader; /// Finalize XOF, write result into `out`, and reset the hasher state. fn finalize_xof_reset_into(&mut self, out: &mut [u8]) { self.finalize_xof_reset().read(out); } /// Retrieve result into a boxed slice of the specified size and reset /// the hasher state. /// /// `Box<[u8]>` is used instead of `Vec` to save stack space, since /// they have size of 2 and 3 words respectively. #[cfg(feature = "alloc")] #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] fn finalize_boxed_reset(&mut self, output_size: usize) -> Box<[u8]> { let mut buf = vec![0u8; output_size].into_boxed_slice(); self.finalize_xof_reset().read(&mut buf); buf } } /// Trait for hash functions with variable-size output. pub trait VariableOutput: Sized + Update { /// Maximum size of output hash. const MAX_OUTPUT_SIZE: usize; /// Create new hasher instance with the given output size. /// /// It will return `Err(InvalidOutputSize)` in case if hasher can not return /// hash of the specified output size. fn new(output_size: usize) -> Result; /// Get output size of the hasher instance provided to the `new` method fn output_size(&self) -> usize; /// Write result into the output buffer. /// /// Returns `Err(InvalidOutputSize)` if `out` size is not equal to /// `self.output_size()`. fn finalize_variable(self, out: &mut [u8]) -> Result<(), InvalidBufferSize>; /// Compute hash of `data` and write it to `output`. /// /// Length of the output hash is determined by `output`. If `output` is /// bigger than `Self::MAX_OUTPUT_SIZE`, this method returns /// `InvalidOutputSize`. fn digest_variable( input: impl AsRef<[u8]>, output: &mut [u8], ) -> Result<(), InvalidOutputSize> { let mut hasher = Self::new(output.len())?; hasher.update(input.as_ref()); hasher .finalize_variable(output) .map_err(|_| InvalidOutputSize) } /// Retrieve result into a boxed slice and consume hasher. /// /// `Box<[u8]>` is used instead of `Vec` to save stack space, since /// they have size of 2 and 3 words respectively. #[cfg(feature = "alloc")] #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] fn finalize_boxed(self) -> Box<[u8]> { let n = self.output_size(); let mut buf = vec![0u8; n].into_boxed_slice(); self.finalize_variable(&mut buf) .expect("buf length is equal to output_size"); buf } } /// Trait for hash functions with variable-size output able to reset themselves. pub trait VariableOutputReset: VariableOutput + Reset { /// Write result into the output buffer and reset the hasher state. /// /// Returns `Err(InvalidOutputSize)` if `out` size is not equal to /// `self.output_size()`. fn finalize_variable_reset(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize>; /// Retrieve result into a boxed slice and reset the hasher state. /// /// `Box<[u8]>` is used instead of `Vec` to save stack space, since /// they have size of 2 and 3 words respectively. #[cfg(feature = "alloc")] #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] fn finalize_boxed_reset(&mut self) -> Box<[u8]> { let n = self.output_size(); let mut buf = vec![0u8; n].into_boxed_slice(); self.finalize_variable_reset(&mut buf) .expect("buf length is equal to output_size"); buf } } /// The error type used in variable hash traits. #[derive(Clone, Copy, Debug, Default)] pub struct InvalidOutputSize; impl fmt::Display for InvalidOutputSize { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("invalid output size") } } #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl std::error::Error for InvalidOutputSize {} /// Buffer length is not equal to hash output size. #[derive(Default, Debug, Copy, Clone, Eq, PartialEq)] pub struct InvalidBufferSize; impl fmt::Display for InvalidBufferSize { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("invalid buffer length") } } #[cfg(feature = "std")] impl std::error::Error for InvalidBufferSize {} digest-0.10.7/src/mac.rs000064400000000000000000000202471046102023000130720ustar 00000000000000use crate::{FixedOutput, FixedOutputReset, Update}; use crypto_common::{InvalidLength, Key, KeyInit, Output, OutputSizeUser, Reset}; #[cfg(feature = "rand_core")] use crate::rand_core::{CryptoRng, RngCore}; use core::fmt; use crypto_common::typenum::Unsigned; use subtle::{Choice, ConstantTimeEq}; /// Marker trait for Message Authentication algorithms. #[cfg_attr(docsrs, doc(cfg(feature = "mac")))] pub trait MacMarker {} /// Convenience wrapper trait covering functionality of Message Authentication algorithms. /// /// This trait wraps [`KeyInit`], [`Update`], [`FixedOutput`], and [`MacMarker`] /// traits and provides additional convenience methods. #[cfg_attr(docsrs, doc(cfg(feature = "mac")))] pub trait Mac: OutputSizeUser + Sized { /// Create new value from fixed size key. fn new(key: &Key) -> Self where Self: KeyInit; /// Generate random key using the provided [`CryptoRng`]. #[cfg(feature = "rand_core")] #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] fn generate_key(rng: impl CryptoRng + RngCore) -> Key where Self: KeyInit; /// Create new value from variable size key. fn new_from_slice(key: &[u8]) -> Result where Self: KeyInit; /// Update state using the provided data. fn update(&mut self, data: &[u8]); /// Process input data in a chained manner. #[must_use] fn chain_update(self, data: impl AsRef<[u8]>) -> Self; /// Obtain the result of a [`Mac`] computation as a [`CtOutput`] and consume /// [`Mac`] instance. fn finalize(self) -> CtOutput; /// Obtain the result of a [`Mac`] computation as a [`CtOutput`] and reset /// [`Mac`] instance. fn finalize_reset(&mut self) -> CtOutput where Self: FixedOutputReset; /// Reset MAC instance to its initial state. fn reset(&mut self) where Self: Reset; /// Check if tag/code value is correct for the processed input. fn verify(self, tag: &Output) -> Result<(), MacError>; /// Check if tag/code value is correct for the processed input and reset /// [`Mac`] instance. fn verify_reset(&mut self, tag: &Output) -> Result<(), MacError> where Self: FixedOutputReset; /// Check truncated tag correctness using all bytes /// of calculated tag. /// /// Returns `Error` if `tag` is not valid or not equal in length /// to MAC's output. fn verify_slice(self, tag: &[u8]) -> Result<(), MacError>; /// Check truncated tag correctness using all bytes /// of calculated tag and reset [`Mac`] instance. /// /// Returns `Error` if `tag` is not valid or not equal in length /// to MAC's output. fn verify_slice_reset(&mut self, tag: &[u8]) -> Result<(), MacError> where Self: FixedOutputReset; /// Check truncated tag correctness using left side bytes /// (i.e. `tag[..n]`) of calculated tag. /// /// Returns `Error` if `tag` is not valid or empty. fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError>; /// Check truncated tag correctness using right side bytes /// (i.e. `tag[n..]`) of calculated tag. /// /// Returns `Error` if `tag` is not valid or empty. fn verify_truncated_right(self, tag: &[u8]) -> Result<(), MacError>; } impl Mac for T { #[inline(always)] fn new(key: &Key) -> Self where Self: KeyInit, { KeyInit::new(key) } #[inline(always)] fn new_from_slice(key: &[u8]) -> Result where Self: KeyInit, { KeyInit::new_from_slice(key) } #[inline] fn update(&mut self, data: &[u8]) { Update::update(self, data); } #[inline] fn chain_update(mut self, data: impl AsRef<[u8]>) -> Self { Update::update(&mut self, data.as_ref()); self } #[inline] fn finalize(self) -> CtOutput { CtOutput::new(self.finalize_fixed()) } #[inline(always)] fn finalize_reset(&mut self) -> CtOutput where Self: FixedOutputReset, { CtOutput::new(self.finalize_fixed_reset()) } #[inline] fn reset(&mut self) where Self: Reset, { Reset::reset(self) } #[inline] fn verify(self, tag: &Output) -> Result<(), MacError> { if self.finalize() == tag.into() { Ok(()) } else { Err(MacError) } } #[inline] fn verify_reset(&mut self, tag: &Output) -> Result<(), MacError> where Self: FixedOutputReset, { if self.finalize_reset() == tag.into() { Ok(()) } else { Err(MacError) } } #[inline] fn verify_slice(self, tag: &[u8]) -> Result<(), MacError> { let n = tag.len(); if n != Self::OutputSize::USIZE { return Err(MacError); } let choice = self.finalize_fixed().ct_eq(tag); if choice.into() { Ok(()) } else { Err(MacError) } } #[inline] fn verify_slice_reset(&mut self, tag: &[u8]) -> Result<(), MacError> where Self: FixedOutputReset, { let n = tag.len(); if n != Self::OutputSize::USIZE { return Err(MacError); } let choice = self.finalize_fixed_reset().ct_eq(tag); if choice.into() { Ok(()) } else { Err(MacError) } } fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError> { let n = tag.len(); if n == 0 || n > Self::OutputSize::USIZE { return Err(MacError); } let choice = self.finalize_fixed()[..n].ct_eq(tag); if choice.into() { Ok(()) } else { Err(MacError) } } fn verify_truncated_right(self, tag: &[u8]) -> Result<(), MacError> { let n = tag.len(); if n == 0 || n > Self::OutputSize::USIZE { return Err(MacError); } let m = Self::OutputSize::USIZE - n; let choice = self.finalize_fixed()[m..].ct_eq(tag); if choice.into() { Ok(()) } else { Err(MacError) } } #[cfg(feature = "rand_core")] #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] #[inline] fn generate_key(rng: impl CryptoRng + RngCore) -> Key where Self: KeyInit, { ::generate_key(rng) } } /// Fixed size output value which provides a safe [`Eq`] implementation that /// runs in constant time. /// /// It is useful for implementing Message Authentication Codes (MACs). #[derive(Clone)] #[cfg_attr(docsrs, doc(cfg(feature = "mac")))] pub struct CtOutput { bytes: Output, } impl CtOutput { /// Create a new [`CtOutput`] value. #[inline(always)] pub fn new(bytes: Output) -> Self { Self { bytes } } /// Get the inner [`Output`] array this type wraps. #[inline(always)] pub fn into_bytes(self) -> Output { self.bytes } } impl From> for CtOutput { #[inline(always)] fn from(bytes: Output) -> Self { Self { bytes } } } impl<'a, T: OutputSizeUser> From<&'a Output> for CtOutput { #[inline(always)] fn from(bytes: &'a Output) -> Self { bytes.clone().into() } } impl ConstantTimeEq for CtOutput { #[inline(always)] fn ct_eq(&self, other: &Self) -> Choice { self.bytes.ct_eq(&other.bytes) } } impl PartialEq for CtOutput { #[inline(always)] fn eq(&self, x: &CtOutput) -> bool { self.ct_eq(x).into() } } impl Eq for CtOutput {} /// Error type for when the [`Output`] of a [`Mac`] /// is not equal to the expected value. #[derive(Default, Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(docsrs, doc(cfg(feature = "mac")))] pub struct MacError; impl fmt::Display for MacError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("MAC tag mismatch") } } #[cfg(feature = "std")] impl std::error::Error for MacError {}