picky_krb/crypto/
cipher.rs

1use crate::constants::etypes::{AES128_CTS_HMAC_SHA1_96, AES256_CTS_HMAC_SHA1_96, DES3_CBC_SHA1_KD};
2
3use super::aes::{Aes128CtsHmacSha196, Aes256CtsHmacSha196};
4use super::des::Des3CbcSha1Kd;
5use super::{ChecksumSuite, DecryptWithoutChecksum, EncryptWithoutChecksum, KerberosCryptoError, KerberosCryptoResult};
6
7pub trait Cipher {
8    fn key_size(&self) -> usize;
9    fn seed_bit_len(&self) -> usize;
10    fn cipher_type(&self) -> CipherSuite;
11    fn checksum_type(&self) -> ChecksumSuite;
12
13    fn encrypt(&self, key: &[u8], key_usage: i32, payload: &[u8]) -> KerberosCryptoResult<Vec<u8>>;
14    fn decrypt(&self, key: &[u8], key_usage: i32, cipher_data: &[u8]) -> KerberosCryptoResult<Vec<u8>>;
15
16    fn encrypt_no_checksum(
17        &self,
18        key: &[u8],
19        key_usage: i32,
20        payload: &[u8],
21    ) -> KerberosCryptoResult<EncryptWithoutChecksum>;
22    fn decrypt_no_checksum(
23        &self,
24        key: &[u8],
25        key_usage: i32,
26        cipher_data: &[u8],
27    ) -> KerberosCryptoResult<DecryptWithoutChecksum>;
28
29    /// Calculates Kerberos checksum over the provided data.
30    ///
31    /// Note: this method differs from [Checksum::checksum]. Key derivation processes for
32    /// encryption checksum and just checksum are different. More details:
33    /// * [Encryption and Checksum Specifications for Kerberos 5](https://datatracker.ietf.org/doc/html/rfc3961).
34    fn encryption_checksum(&self, key: &[u8], key_usage: i32, payload: &[u8]) -> KerberosCryptoResult<Vec<u8>>;
35
36    fn generate_key_from_password(&self, password: &[u8], salt: &[u8]) -> KerberosCryptoResult<Vec<u8>>;
37    fn random_to_key(&self, key: Vec<u8>) -> Vec<u8>;
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
41pub enum CipherSuite {
42    Aes128CtsHmacSha196,
43    Aes256CtsHmacSha196,
44    Des3CbcSha1Kd,
45}
46
47impl CipherSuite {
48    pub fn cipher(&self) -> Box<dyn Cipher> {
49        match self {
50            CipherSuite::Aes256CtsHmacSha196 => Box::new(Aes256CtsHmacSha196::new()),
51            CipherSuite::Aes128CtsHmacSha196 => Box::new(Aes128CtsHmacSha196::new()),
52            CipherSuite::Des3CbcSha1Kd => Box::new(Des3CbcSha1Kd::new()),
53        }
54    }
55}
56
57impl TryFrom<&[u8]> for CipherSuite {
58    type Error = KerberosCryptoError;
59
60    fn try_from(identifier: &[u8]) -> Result<Self, Self::Error> {
61        if identifier.len() != 1 {
62            return Err(KerberosCryptoError::AlgorithmIdentifierData(identifier.into()));
63        }
64
65        match u8::from_be_bytes(identifier.try_into().unwrap()) as usize {
66            AES256_CTS_HMAC_SHA1_96 => Ok(Self::Aes256CtsHmacSha196),
67            AES128_CTS_HMAC_SHA1_96 => Ok(Self::Aes128CtsHmacSha196),
68            DES3_CBC_SHA1_KD => Ok(Self::Des3CbcSha1Kd),
69            _ => Err(KerberosCryptoError::AlgorithmIdentifierData(identifier.into())),
70        }
71    }
72}
73
74impl TryFrom<usize> for CipherSuite {
75    type Error = KerberosCryptoError;
76
77    fn try_from(identifier: usize) -> Result<Self, Self::Error> {
78        match identifier {
79            AES256_CTS_HMAC_SHA1_96 => Ok(Self::Aes256CtsHmacSha196),
80            AES128_CTS_HMAC_SHA1_96 => Ok(Self::Aes128CtsHmacSha196),
81            DES3_CBC_SHA1_KD => Ok(Self::Des3CbcSha1Kd),
82            _ => Err(KerberosCryptoError::AlgorithmIdentifier(identifier)),
83        }
84    }
85}
86
87impl From<CipherSuite> for usize {
88    fn from(cipher: CipherSuite) -> Self {
89        match cipher {
90            CipherSuite::Aes256CtsHmacSha196 => AES256_CTS_HMAC_SHA1_96,
91            CipherSuite::Aes128CtsHmacSha196 => AES128_CTS_HMAC_SHA1_96,
92            CipherSuite::Des3CbcSha1Kd => DES3_CBC_SHA1_KD,
93        }
94    }
95}
96
97impl From<&CipherSuite> for u32 {
98    fn from(cipher: &CipherSuite) -> Self {
99        match cipher {
100            CipherSuite::Aes256CtsHmacSha196 => AES256_CTS_HMAC_SHA1_96 as u32,
101            CipherSuite::Aes128CtsHmacSha196 => AES128_CTS_HMAC_SHA1_96 as u32,
102            CipherSuite::Des3CbcSha1Kd => DES3_CBC_SHA1_KD as u32,
103        }
104    }
105}
106
107impl From<CipherSuite> for u8 {
108    fn from(cipher: CipherSuite) -> Self {
109        match cipher {
110            CipherSuite::Aes256CtsHmacSha196 => AES256_CTS_HMAC_SHA1_96 as u8,
111            CipherSuite::Aes128CtsHmacSha196 => AES128_CTS_HMAC_SHA1_96 as u8,
112            CipherSuite::Des3CbcSha1Kd => DES3_CBC_SHA1_KD as u8,
113        }
114    }
115}
116
117impl From<&CipherSuite> for u8 {
118    fn from(cipher: &CipherSuite) -> Self {
119        match cipher {
120            CipherSuite::Aes256CtsHmacSha196 => AES256_CTS_HMAC_SHA1_96 as u8,
121            CipherSuite::Aes128CtsHmacSha196 => AES128_CTS_HMAC_SHA1_96 as u8,
122            CipherSuite::Des3CbcSha1Kd => DES3_CBC_SHA1_KD as u8,
123        }
124    }
125}