ferogram_mtproto/
bind_temp_key.rs1use ferogram_crypto::{aes, derive_aes_key_iv_v1};
35use sha1::{Digest, Sha1};
36
37fn serialize_inner(
38 nonce: i64,
39 temp_auth_key_id: i64,
40 perm_auth_key_id: i64,
41 temp_session_id: i64,
42 expires_at: i32,
43) -> [u8; 40] {
44 let mut out = [0u8; 40];
45 out[0..4].copy_from_slice(&0x75a3f765_u32.to_le_bytes());
46 out[4..12].copy_from_slice(&nonce.to_le_bytes());
47 out[12..20].copy_from_slice(&temp_auth_key_id.to_le_bytes());
48 out[20..28].copy_from_slice(&perm_auth_key_id.to_le_bytes());
49 out[28..36].copy_from_slice(&temp_session_id.to_le_bytes());
50 out[36..40].copy_from_slice(&expires_at.to_le_bytes());
51 out
52}
53
54pub fn encrypt_bind_inner(
56 perm_auth_key: &[u8; 256],
57 msg_id: i64,
58 nonce: i64,
59 temp_auth_key_id: i64,
60 perm_auth_key_id: i64,
61 temp_session_id: i64,
62 expires_at: i32,
63) -> Vec<u8> {
64 let inner = serialize_inner(
65 nonce,
66 temp_auth_key_id,
67 perm_auth_key_id,
68 temp_session_id,
69 expires_at,
70 );
71
72 let header_len = 32usize;
73 let content_len = header_len + 40;
74 let pad_len = (16 - content_len % 16) % 16;
75 let total = content_len + pad_len;
76
77 let mut rnd = [0u8; 24];
78 getrandom::getrandom(&mut rnd).expect("getrandom");
79
80 let mut plaintext = Vec::with_capacity(total);
81 plaintext.extend_from_slice(&rnd[..8]);
82 plaintext.extend_from_slice(&rnd[8..16]);
83 plaintext.extend_from_slice(&msg_id.to_le_bytes());
84 plaintext.extend_from_slice(&0i32.to_le_bytes());
85 plaintext.extend_from_slice(&40u32.to_le_bytes());
86 plaintext.extend_from_slice(&inner);
87 plaintext.extend_from_slice(&rnd[16..16 + pad_len]);
88 assert_eq!(plaintext.len(), total);
89
90 let hash: [u8; 20] = {
91 let mut h = Sha1::new();
92 h.update(&plaintext[..content_len]);
93 h.finalize().into()
94 };
95 let mut msg_key = [0u8; 16];
96 msg_key.copy_from_slice(&hash[4..20]);
97
98 let (aes_key, aes_iv) = derive_aes_key_iv_v1(perm_auth_key, &msg_key);
99 aes::ige_encrypt(&mut plaintext, &aes_key, &aes_iv);
100
101 let key_sha: [u8; 20] = {
102 let mut h = Sha1::new();
103 h.update(perm_auth_key);
104 h.finalize().into()
105 };
106
107 let mut result = Vec::with_capacity(8 + 16 + plaintext.len());
108 result.extend_from_slice(&key_sha[12..20]);
109 result.extend_from_slice(&msg_key);
110 result.extend_from_slice(&plaintext);
111 result
112}
113
114pub fn serialize_bind_temp_auth_key(
116 perm_auth_key_id: i64,
117 nonce: i64,
118 expires_at: i32,
119 encrypted_message: &[u8],
120) -> Vec<u8> {
121 let mut out = Vec::new();
122 out.extend_from_slice(&0xcdd42a05_u32.to_le_bytes());
123 out.extend_from_slice(&perm_auth_key_id.to_le_bytes());
124 out.extend_from_slice(&nonce.to_le_bytes());
125 out.extend_from_slice(&expires_at.to_le_bytes());
126 tl_write_bytes(&mut out, encrypted_message);
127 out
128}
129
130pub fn gen_msg_id() -> i64 {
132 use std::time::{SystemTime, UNIX_EPOCH};
133 let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
134 ((now.as_secs() << 32) | (now.subsec_nanos() as u64 & !3)) as i64
135}
136
137fn tl_write_bytes(out: &mut Vec<u8>, data: &[u8]) {
138 let len = data.len();
139 if len < 254 {
140 out.push(len as u8);
141 out.extend_from_slice(data);
142 let pad = (4 - (1 + len) % 4) % 4;
143 out.extend(std::iter::repeat_n(0u8, pad));
144 } else {
145 out.push(0xfe);
146 out.push((len & 0xff) as u8);
147 out.push(((len >> 8) & 0xff) as u8);
148 out.push(((len >> 16) & 0xff) as u8);
149 out.extend_from_slice(data);
150 let pad = (4 - (4 + len) % 4) % 4;
151 out.extend(std::iter::repeat_n(0u8, pad));
152 }
153}