tink_mac/subtle/
hmac.rs

1// Copyright 2020 The Tink-Rust Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15////////////////////////////////////////////////////////////////////////////////
16
17//! Provides an implementation of MAC using HMAC.
18
19use tink_core::{utils::wrap_err, Prf, TinkError};
20use tink_proto::HashType;
21
22/// Minimum key size in bytes.
23const MIN_KEY_SIZE_IN_BYTES: usize = 16;
24
25/// Minimum tag size in bytes. This provides minimum 80-bit security strength.
26const MIN_TAG_SIZE_IN_BYTES: usize = 10;
27
28/// Implementation of trait `tink_core::Mac`.
29#[derive(Clone)]
30pub struct Hmac {
31    prf: tink_prf::subtle::HmacPrf,
32    tag_size: usize,
33}
34
35impl Hmac {
36    /// Create a new instance of [`Hmac`] with the specified key and tag size.
37    pub fn new(hash_alg: HashType, key: &[u8], tag_size: usize) -> Result<Self, TinkError> {
38        let key_size = key.len();
39        if let Err(e) = validate_hmac_params(hash_alg, key_size, tag_size) {
40            return Err(wrap_err("Hmac", e));
41        }
42        let prf = tink_prf::subtle::HmacPrf::new(hash_alg, key)?;
43        Ok(Hmac { prf, tag_size })
44    }
45}
46
47/// Validate parameters of [`Hmac`] constructor.
48pub fn validate_hmac_params(
49    hash: HashType,
50    key_size: usize,
51    tag_size: usize,
52) -> Result<(), TinkError> {
53    // validate tag size
54    let digest_size = tink_core::subtle::get_hash_digest_size(hash)?;
55    if tag_size > digest_size {
56        return Err("tag size too big".into());
57    }
58    if tag_size < MIN_TAG_SIZE_IN_BYTES {
59        return Err("tag size too small".into());
60    }
61    // validate key size
62    if key_size < MIN_KEY_SIZE_IN_BYTES {
63        return Err("key too short".into());
64    }
65    Ok(())
66}
67
68impl tink_core::Mac for Hmac {
69    fn compute_mac(&self, data: &[u8]) -> Result<Vec<u8>, TinkError> {
70        self.prf.compute_prf(data, self.tag_size)
71    }
72}