1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// Copyright 2020 The Tink-Rust Authors
//
// 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.
//
////////////////////////////////////////////////////////////////////////////////

//! Common methods needed in subtle implementations.

use crate::TinkError;
use digest::Digest;
use subtle::ConstantTimeEq;
use tink_proto::HashType;

mod hkdf;
pub use self::hkdf::*;
pub mod random;

/// Return the digest size of the specified hash algorithm.
pub fn get_hash_digest_size(hash: HashType) -> Result<usize, TinkError> {
    match hash {
        HashType::Sha1 => Ok(20),
        HashType::Sha256 => Ok(32),
        HashType::Sha384 => Ok(48),
        HashType::Sha512 => Ok(64),
        _ => Err("invalid hash algorithm".into()),
    }
}

/// Hash function object.
pub enum HashFunc {
    Sha1(sha1::Sha1),
    Sha256(sha2::Sha256),
    Sha384(sha2::Sha384),
    Sha512(sha2::Sha512),
}

/// Return the corresponding hash function of the given hash.
pub fn get_hash_func(hash: HashType) -> Option<HashFunc> {
    match hash {
        HashType::Sha1 => Some(HashFunc::Sha1(sha1::Sha1::new())),
        HashType::Sha256 => Some(HashFunc::Sha256(sha2::Sha256::new())),
        HashType::Sha384 => Some(HashFunc::Sha384(sha2::Sha384::new())),
        HashType::Sha512 => Some(HashFunc::Sha512(sha2::Sha512::new())),
        _ => None,
    }
}

/// Calculate a hash of the given data using the given hash function.
pub fn compute_hash(hash_fn: &mut HashFunc, data: &[u8]) -> Result<Vec<u8>, TinkError> {
    Ok(match hash_fn {
        HashFunc::Sha1(h) => compute_hash_with(h, data),
        HashFunc::Sha256(h) => compute_hash_with(h, data),
        HashFunc::Sha384(h) => compute_hash_with(h, data),
        HashFunc::Sha512(h) => compute_hash_with(h, data),
    })
}

/// Calculate a hash of the given data with the given hash function.
fn compute_hash_with<T>(hash_func: &mut T, data: &[u8]) -> Vec<u8>
where
    T: digest::Digest,
{
    hash_func.reset();
    hash_func.update(data);
    hash_func.finalize_reset().to_vec()
}

/// Compare two slices in constant time. Return `true` if they are equal, `false` otherwise.
pub fn constant_time_compare(left: &[u8], right: &[u8]) -> bool {
    left.ct_eq(right).into()
}