why2_chat/crypto/
mod.rs

1/*
2This is part of WHY2
3Copyright (C) 2022-2026 Václav Šmejkal
4
5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation, either version 3 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program.  If not, see <https://www.gnu.org/licenses/>.
17*/
18
19//MODULES
20#[cfg(feature = "server")]
21pub mod password;
22pub mod kex;
23
24use why2::
25{
26    encrypter,
27    decrypter,
28    grid::Grid,
29    types::EncryptedData,
30    auth::AuthenticatedData,
31};
32
33use zeroize::Zeroizing;
34
35use hkdf::Hkdf;
36use sha2::{ Sha256, Digest };
37
38use crate::options;
39
40//PRIVATE
41pub fn get_correct_key<const W: usize, const H: usize>(key: &Zeroizing<Vec<i64>>) -> Zeroizing<Vec<i64>> //DERIVE VALID KEYDIM USING HKDF
42{
43    //CONVERT KEY TO BYTES
44    let mut key_bytes = Vec::with_capacity(key.len() * 8);
45    for val in key.iter()
46    {
47        key_bytes.extend_from_slice(&val.to_be_bytes());
48    }
49
50    //INIT HKDF
51    let hkdf = Hkdf::<Sha256>::new(None, &key_bytes);
52
53    let required_len = W * H * 2;
54    let needed_bytes = required_len * 8;
55    let mut output_bytes = vec![0u8; needed_bytes];
56
57    //EXPAND
58    hkdf.expand(format!("WHY2-DERIVED-KEY-{W}x{H}").as_bytes(), &mut output_bytes).expect("Key derivation failed");
59
60    //CONVERT BACK TO i64
61    let mut derived_key = Vec::with_capacity(required_len);
62    for chunk in output_bytes.chunks_exact(8)
63    {
64        let mut buf = [0u8; 8];
65        buf.copy_from_slice(chunk);
66        derived_key.push(i64::from_be_bytes(buf));
67    }
68
69    Zeroizing::new(derived_key)
70}
71
72//PUBLIC
73pub fn sha256(seed_str: &str) -> [u8; 32] //GET HASH SEED; USED FOR PADDING
74{
75    //SHA256
76    let mut hasher = Sha256::new();
77    hasher.update(seed_str.as_bytes());
78
79    //FINALIZE
80    hasher.finalize().into()
81}
82
83pub fn encrypt_packet<const W: usize, const H: usize>(packet_bytes: Vec<u8>, keys: &options::SharedKeys) -> Vec<u8>
84{
85    //CONVERT packet_bytes to BINARY
86    let mut input_i64 = Vec::with_capacity((packet_bytes.len() + 7) / 8);
87    for chunk in packet_bytes.chunks(8)
88    {
89        let mut buf = [0u8; 8];
90        buf[..chunk.len()].copy_from_slice(chunk);
91        input_i64.push(i64::from_be_bytes(buf));
92    }
93
94    //GET VALID KEY
95    let key = if keys.0.len() == W * H * 2
96    {
97        &keys.0
98    } else
99    {
100        &get_correct_key::<W, H>(&keys.0)
101    };
102
103    //ENCRYPT
104    let encrypted_data = encrypter::encrypt::<W, H>(&input_i64, Some(key))
105        .expect("Encrypting packet failed");
106
107    //AUTHENTICATE
108    AuthenticatedData::authenticate(encrypted_data, keys.1.as_slice().try_into().unwrap()).into()
109}
110
111pub fn decrypt_packet<const W: usize, const H: usize>(mut decoded_packet: Vec<u8>, keys: &options::SharedKeys) -> Option<Vec<u8>>
112{
113    //DESERIALIZE
114    let auth_packet: AuthenticatedData<W, H> = decoded_packet.as_slice().try_into().ok()?;
115
116    //VERIFY HMAC
117    if !auth_packet.verify(keys.1.as_slice().try_into().ok()?)
118    {
119        return None;
120    }
121
122    //GET VALID KEY
123    let key = if keys.0.len() == W * H * 2
124    {
125        &keys.0
126    } else
127    {
128        &get_correct_key::<W, H>(&keys.0)
129    };
130
131    //DECRYPT
132    let decrypted_packet = decrypter::decrypt(EncryptedData
133    {
134        output: auth_packet.encrypted_data.output,
135        key: Grid::from_key(&key).ok()?,
136        nonce: auth_packet.encrypted_data.nonce,
137    }).ok()?;
138
139    //OVERWRITE decoded_packet
140    decoded_packet = Vec::with_capacity(decrypted_packet.output.len() * 8);
141    for val in decrypted_packet.output.to_vec()
142    {
143        decoded_packet.extend_from_slice(&val.to_be_bytes());
144    }
145
146    Some(decoded_packet)
147}