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}