Skip to main content

grammers_crypto/
auth_key.rs

1// Copyright 2020 - developers of the `grammers` project.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::fmt;
10
11use crate::sha1;
12
13/// Telegram's [Authorization Key](https://core.telegram.org/mtproto/auth_key).
14///
15/// This library does not provide the means to generate a valid key,
16/// because doing so relies on (de-)serializing Telegram types.
17#[derive(Clone)]
18pub struct AuthKey {
19    pub(crate) data: [u8; 256],
20    pub(crate) aux_hash: [u8; 8],
21    pub(crate) key_id: [u8; 8],
22}
23
24impl PartialEq for AuthKey {
25    fn eq(&self, other: &Self) -> bool {
26        self.key_id == other.key_id
27    }
28}
29
30impl AuthKey {
31    /// Creates a new authorization key from the given binary data.
32    pub fn from_bytes(data: [u8; 256]) -> Self {
33        let sha = sha1!(&data);
34        let aux_hash = {
35            let mut buffer = [0; 8];
36            buffer.copy_from_slice(&sha[0..8]);
37            buffer
38        };
39        let key_id = {
40            let mut buffer = [0; 8];
41            buffer.copy_from_slice(&sha[12..12 + 8]);
42            buffer
43        };
44
45        Self {
46            data,
47            aux_hash,
48            key_id,
49        }
50    }
51
52    /// Converts the authorization key to a sequence of bytes, which can
53    /// be loaded back later.
54    pub fn to_bytes(&self) -> [u8; 256] {
55        self.data
56    }
57
58    /// Calculates the new nonce hash based on the current attributes.
59    pub fn calc_new_nonce_hash(&self, new_nonce: &[u8; 32], number: u8) -> [u8; 16] {
60        let data = {
61            let mut buffer = Vec::with_capacity(new_nonce.len() + 1 + self.aux_hash.len());
62            buffer.extend(new_nonce);
63            buffer.push(number);
64            buffer.extend(&self.aux_hash);
65            buffer
66        };
67
68        let mut result = [0u8; 16];
69        result.copy_from_slice(&sha1!(data)[4..]);
70        result
71    }
72}
73
74impl fmt::Debug for AuthKey {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        f.debug_struct("AuthKey")
77            .field("key_id", &u64::from_le_bytes(self.key_id))
78            .finish()
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    fn get_test_auth_key() -> AuthKey {
87        let mut buffer = [0u8; 256];
88        buffer
89            .iter_mut()
90            .enumerate()
91            .for_each(|(i, x)| *x = i as u8);
92
93        AuthKey::from_bytes(buffer)
94    }
95
96    fn get_test_new_nonce() -> [u8; 32] {
97        let mut buffer = [0u8; 32];
98        buffer
99            .iter_mut()
100            .enumerate()
101            .for_each(|(i, x)| *x = i as u8);
102
103        buffer
104    }
105
106    #[test]
107    fn auth_key_aux_hash() {
108        let auth_key = get_test_auth_key();
109        let expected = [73, 22, 214, 189, 183, 247, 142, 104];
110
111        assert_eq!(auth_key.aux_hash, expected);
112    }
113
114    #[test]
115    fn auth_key_id() {
116        let auth_key = get_test_auth_key();
117        let expected = [50, 209, 88, 110, 164, 87, 223, 200];
118
119        assert_eq!(auth_key.key_id, expected);
120    }
121
122    #[test]
123    fn calc_new_nonce_hash1() {
124        let auth_key = get_test_auth_key();
125        let new_nonce = get_test_new_nonce();
126        assert_eq!(
127            auth_key.calc_new_nonce_hash(&new_nonce, 1),
128            [
129                194, 206, 210, 179, 62, 89, 58, 85, 210, 127, 74, 93, 171, 238, 124, 103
130            ]
131        );
132    }
133
134    #[test]
135    fn calc_new_nonce_hash2() {
136        let auth_key = get_test_auth_key();
137        let new_nonce = get_test_new_nonce();
138        assert_eq!(
139            auth_key.calc_new_nonce_hash(&new_nonce, 2),
140            [
141                244, 49, 142, 133, 189, 47, 243, 190, 132, 217, 254, 252, 227, 220, 227, 159
142            ]
143        );
144    }
145
146    #[test]
147    fn calc_new_nonce_hash3() {
148        let auth_key = get_test_auth_key();
149        let new_nonce = get_test_new_nonce();
150        assert_eq!(
151            auth_key.calc_new_nonce_hash(&new_nonce, 3),
152            [
153                75, 249, 215, 179, 125, 180, 19, 238, 67, 29, 40, 81, 118, 49, 203, 61
154            ]
155        );
156    }
157}