Skip to main content

rustssh2/mac/
mod.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12//
13
14//!
15//! This module exports cipher names for use with [Preferred].
16use std::collections::HashMap;
17use std::convert::TryFrom;
18use std::marker::PhantomData;
19use std::sync::LazyLock;
20
21use delegate::delegate;
22use digest::typenum::{U20, U32, U64};
23use hmac::Hmac;
24use sha1::Sha1;
25use sha2::{Sha256, Sha512};
26use ssh_encoding::Encode;
27
28use self::crypto::CryptoMacAlgorithm;
29use self::crypto_etm::CryptoEtmMacAlgorithm;
30use self::none::NoMacAlgorithm;
31
32mod crypto;
33mod crypto_etm;
34mod none;
35
36pub(crate) trait MacAlgorithm {
37    fn key_len(&self) -> usize;
38    fn make_mac(&self, key: &[u8]) -> Box<dyn Mac + Send>;
39}
40
41pub(crate) trait Mac {
42    fn mac_len(&self) -> usize;
43    fn is_etm(&self) -> bool {
44        false
45    }
46    fn compute(&self, sequence_number: u32, payload: &[u8], output: &mut [u8]);
47    fn verify(&self, sequence_number: u32, payload: &[u8], mac: &[u8]) -> bool;
48}
49
50#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
51pub struct Name(&'static str);
52impl AsRef<str> for Name {
53    fn as_ref(&self) -> &str {
54        self.0
55    }
56}
57
58impl Encode for Name {
59    delegate! { to self.as_ref() {
60        fn encoded_len(&self) -> Result<usize, ssh_encoding::Error>;
61        fn encode(&self, writer: &mut impl ssh_encoding::Writer) -> Result<(), ssh_encoding::Error>;
62    }}
63}
64
65impl TryFrom<&str> for Name {
66    type Error = ();
67    fn try_from(s: &str) -> Result<Name, ()> {
68        MACS.keys().find(|x| x.0 == s).map(|x| **x).ok_or(())
69    }
70}
71
72/// `none`
73pub const NONE: Name = Name("none");
74/// `hmac-sha1`
75pub const HMAC_SHA1: Name = Name("hmac-sha1");
76/// `hmac-sha2-256`
77pub const HMAC_SHA256: Name = Name("hmac-sha2-256");
78/// `hmac-sha2-512`
79pub const HMAC_SHA512: Name = Name("hmac-sha2-512");
80/// `hmac-sha1-etm@openssh.com`
81pub const HMAC_SHA1_ETM: Name = Name("hmac-sha1-etm@openssh.com");
82/// `hmac-sha2-256-etm@openssh.com`
83pub const HMAC_SHA256_ETM: Name = Name("hmac-sha2-256-etm@openssh.com");
84/// `hmac-sha2-512-etm@openssh.com`
85pub const HMAC_SHA512_ETM: Name = Name("hmac-sha2-512-etm@openssh.com");
86
87pub(crate) static _NONE: NoMacAlgorithm = NoMacAlgorithm {};
88pub(crate) static _HMAC_SHA1: CryptoMacAlgorithm<Hmac<Sha1>, U20> =
89    CryptoMacAlgorithm(PhantomData, PhantomData);
90pub(crate) static _HMAC_SHA256: CryptoMacAlgorithm<Hmac<Sha256>, U32> =
91    CryptoMacAlgorithm(PhantomData, PhantomData);
92pub(crate) static _HMAC_SHA512: CryptoMacAlgorithm<Hmac<Sha512>, U64> =
93    CryptoMacAlgorithm(PhantomData, PhantomData);
94pub(crate) static _HMAC_SHA1_ETM: CryptoEtmMacAlgorithm<Hmac<Sha1>, U20> =
95    CryptoEtmMacAlgorithm(PhantomData, PhantomData);
96pub(crate) static _HMAC_SHA256_ETM: CryptoEtmMacAlgorithm<Hmac<Sha256>, U32> =
97    CryptoEtmMacAlgorithm(PhantomData, PhantomData);
98pub(crate) static _HMAC_SHA512_ETM: CryptoEtmMacAlgorithm<Hmac<Sha512>, U64> =
99    CryptoEtmMacAlgorithm(PhantomData, PhantomData);
100
101pub const ALL_MAC_ALGORITHMS: &[&Name] = &[
102    &NONE,
103    &HMAC_SHA1,
104    &HMAC_SHA256,
105    &HMAC_SHA512,
106    &HMAC_SHA1_ETM,
107    &HMAC_SHA256_ETM,
108    &HMAC_SHA512_ETM,
109];
110
111pub(crate) static MACS: LazyLock<HashMap<&'static Name, &(dyn MacAlgorithm + Send + Sync)>> =
112    LazyLock::new(|| {
113        let mut h: HashMap<&'static Name, &(dyn MacAlgorithm + Send + Sync)> = HashMap::new();
114        h.insert(&NONE, &_NONE);
115        h.insert(&HMAC_SHA1, &_HMAC_SHA1);
116        h.insert(&HMAC_SHA256, &_HMAC_SHA256);
117        h.insert(&HMAC_SHA512, &_HMAC_SHA512);
118        h.insert(&HMAC_SHA1_ETM, &_HMAC_SHA1_ETM);
119        h.insert(&HMAC_SHA256_ETM, &_HMAC_SHA256_ETM);
120        h.insert(&HMAC_SHA512_ETM, &_HMAC_SHA512_ETM);
121        assert_eq!(h.len(), ALL_MAC_ALGORITHMS.len());
122        h
123    });