datex_core/crypto/
crypto_native.rs

1use super::crypto::{CryptoError, CryptoResult, CryptoTrait};
2use crate::stdlib::sync::OnceLock;
3use crate::stdlib::sync::atomic::{AtomicU64, Ordering};
4use core::prelude::rust_2024::*;
5use openssl::{
6    aes::{AesKey, unwrap_key, wrap_key},
7    derive::Deriver,
8    md::Md,
9    pkey::{Id, PKey},
10    pkey_ctx::{HkdfMode, PkeyCtx},
11    sha::sha256,
12    sign::{Signer, Verifier},
13    symm::{Cipher, Crypter, Mode},
14};
15use rand::Rng;
16use uuid::Uuid;
17
18static UUID_COUNTER: OnceLock<AtomicU64> = OnceLock::new();
19
20fn init_counter() -> &'static AtomicU64 {
21    UUID_COUNTER.get_or_init(|| AtomicU64::new(1))
22}
23fn generate_pseudo_uuid() -> String {
24    let counter = init_counter();
25    let count = counter.fetch_add(1, Ordering::Relaxed);
26
27    // Encode counter into last segment, keeping UUID-like structure
28    format!("00000000-0000-0000-0000-{count:012x}")
29}
30
31#[derive(Debug, Clone, PartialEq)]
32pub struct CryptoNative;
33impl CryptoTrait for CryptoNative {
34    fn create_uuid(&self) -> String {
35        // use pseudo-random UUID for testing
36        cfg_if::cfg_if! {
37            if #[cfg(feature = "debug")] {
38                use crate::runtime::global_context::get_global_context;
39                if get_global_context().debug_flags.enable_deterministic_behavior {
40                    generate_pseudo_uuid()
41                }
42                else {
43                    Uuid::new_v4().to_string()
44                }
45            }
46            else {
47                Uuid::new_v4().to_string()
48            }
49        }
50    }
51
52    fn random_bytes(&self, length: usize) -> Vec<u8> {
53        let mut rng = rand::thread_rng();
54        (0..length).map(|_| rng.r#gen()).collect()
55    }
56
57    fn hash_sha256<'a>(
58        &'a self,
59        to_digest: &'a [u8],
60    ) -> CryptoResult<'a, [u8; 32]> {
61        Box::pin(async move {
62            let hash = sha256(to_digest);
63            Ok(hash)
64        })
65    }
66
67    fn hkdf_sha256<'a>(
68        &'a self,
69        ikm: &'a [u8],
70        salt: &'a [u8],
71    ) -> CryptoResult<'a, [u8; 32]> {
72        Box::pin(async move {
73            let info = b"";
74            let mut ctx = PkeyCtx::new_id(Id::HKDF)
75                .map_err(|_| CryptoError::KeyGeneration)?;
76            ctx.derive_init().map_err(|_| CryptoError::KeyGeneration)?;
77            ctx.set_hkdf_mode(HkdfMode::EXTRACT_THEN_EXPAND)
78                .map_err(|_| CryptoError::KeyGeneration)?;
79            ctx.set_hkdf_md(Md::sha256())
80                .map_err(|_| CryptoError::KeyGeneration)?;
81            ctx.set_hkdf_salt(salt)
82                .map_err(|_| CryptoError::KeyGeneration)?;
83            ctx.set_hkdf_key(ikm)
84                .map_err(|_| CryptoError::KeyGeneration)?;
85            ctx.add_hkdf_info(info)
86                .map_err(|_| CryptoError::KeyGeneration)?;
87            let mut okm = [0u8; 32_usize];
88            ctx.derive(Some(&mut okm))
89                .map_err(|_| CryptoError::KeyGeneration)?;
90            Ok(okm)
91        })
92    }
93    // EdDSA keygen
94    fn gen_ed25519<'a>(&'a self) -> CryptoResult<'a, (Vec<u8>, Vec<u8>)> {
95        Box::pin(async move {
96            let key = PKey::generate_ed25519()
97                .map_err(|_| CryptoError::KeyGeneration)?;
98
99            let public_key: Vec<u8> = key
100                .public_key_to_der()
101                .map_err(|_| CryptoError::KeyGeneration)?;
102            let private_key: Vec<u8> = key
103                .private_key_to_pkcs8()
104                .map_err(|_| CryptoError::KeyGeneration)?;
105            Ok((public_key, private_key))
106        })
107    }
108
109    // EdDSA signature
110    fn sig_ed25519<'a>(
111        &'a self,
112        pri_key: &'a [u8],
113        data: &'a [u8],
114    ) -> CryptoResult<'a, [u8; 64]> {
115        Box::pin(async move {
116            let sig_key = PKey::private_key_from_pkcs8(pri_key)
117                .map_err(|_| CryptoError::KeyImport)?;
118            let mut signer = Signer::new_without_digest(&sig_key)
119                .map_err(|_| CryptoError::Signing)?;
120            let signature = signer
121                .sign_oneshot_to_vec(data)
122                .map_err(|_| CryptoError::Signing)?;
123            let signature: [u8; 64] =
124                signature.try_into().expect("Invalid signature length");
125            Ok(signature)
126        })
127    }
128
129    // EdDSA verification of signature
130    fn ver_ed25519<'a>(
131        &'a self,
132        pub_key: &'a [u8],
133        sig: &'a [u8],
134        data: &'a [u8],
135    ) -> CryptoResult<'a, bool> {
136        Box::pin(async move {
137            let public_key = PKey::public_key_from_der(pub_key)
138                .map_err(|_| CryptoError::KeyImport)?;
139            let mut verifier = Verifier::new_without_digest(&public_key)
140                .map_err(|_| CryptoError::KeyImport)?;
141            let verification = verifier
142                .verify_oneshot(sig, data)
143                .map_err(|_| CryptoError::Verification)?;
144            Ok(verification)
145        })
146    }
147
148    // AES CTR
149    fn aes_ctr_encrypt<'a>(
150        &'a self,
151        key: &'a [u8; 32],
152        iv: &'a [u8; 16],
153        plaintext: &'a [u8],
154    ) -> CryptoResult<'a, Vec<u8>> {
155        Box::pin(async move {
156            let cipher = Cipher::aes_256_ctr();
157            let mut enc = Crypter::new(cipher, Mode::Encrypt, key, Some(iv))
158                .map_err(|_| CryptoError::Encryption)?;
159
160            let mut out = vec![0u8; plaintext.len()];
161            let count = enc
162                .update(plaintext, &mut out)
163                .map_err(|_| CryptoError::Encryption)?;
164            out.truncate(count);
165            Ok(out)
166        })
167    }
168
169    fn aes_ctr_decrypt<'a>(
170        &'a self,
171        key: &'a [u8; 32],
172        iv: &'a [u8; 16],
173        ciphertext: &'a [u8],
174    ) -> CryptoResult<'a, Vec<u8>> {
175        self.aes_ctr_encrypt(key, iv, ciphertext)
176    }
177
178    // AES KW
179    fn key_upwrap<'a>(
180        &'a self,
181        kek_bytes: &'a [u8; 32],
182        rb: &'a [u8; 32],
183    ) -> CryptoResult<'a, [u8; 40]> {
184        Box::pin(async move {
185            // Key encryption key
186            let kek = AesKey::new_encrypt(kek_bytes)
187                .map_err(|_| CryptoError::Encryption)?;
188
189            // Key wrap
190            let mut wrapped = [0u8; 40];
191            let _length = wrap_key(&kek, None, &mut wrapped, rb);
192
193            Ok(wrapped)
194        })
195    }
196
197    fn key_unwrap<'a>(
198        &'a self,
199        kek_bytes: &'a [u8; 32],
200        cipher: &'a [u8; 40],
201    ) -> CryptoResult<'a, [u8; 32]> {
202        Box::pin(async move {
203            // Key encryption key
204            let kek = AesKey::new_decrypt(kek_bytes)
205                .map_err(|_| CryptoError::Decryption)?;
206
207            // Unwrap key
208            let mut unwrapped: [u8; 32] = [0u8; 32];
209            let _length = unwrap_key(&kek, None, &mut unwrapped, cipher);
210            Ok(unwrapped)
211        })
212    }
213
214    // Generate encryption keypair
215    fn gen_x25519<'a>(&'a self) -> CryptoResult<'a, ([u8; 44], [u8; 48])> {
216        Box::pin(async move {
217            let key = PKey::generate_x25519()
218                .map_err(|_| CryptoError::KeyGeneration)?;
219            let public_key: [u8; 44] = key
220                .public_key_to_der()
221                .map_err(|_| CryptoError::KeyGeneration)?
222                .try_into()
223                .map_err(|_| CryptoError::KeyGeneration)?;
224            let private_key: [u8; 48] = key
225                .private_key_to_pkcs8()
226                .map_err(|_| CryptoError::KeyGeneration)?
227                .try_into()
228                .map_err(|_| CryptoError::KeyGeneration)?;
229            Ok((public_key, private_key))
230        })
231    }
232
233    // Derive shared secret on x255109
234    fn derive_x25519<'a>(
235        &'a self,
236        pri_key: &'a [u8; 48],
237        peer_pub: &'a [u8; 44],
238    ) -> CryptoResult<'a, Vec<u8>> {
239        Box::pin(async move {
240            let peer_pub = PKey::public_key_from_der(peer_pub)
241                .map_err(|_| CryptoError::KeyImport)?;
242            let my_priv = PKey::private_key_from_pkcs8(pri_key)
243                .map_err(|_| CryptoError::KeyImport)?;
244
245            let mut deriver = Deriver::new(&my_priv)
246                .map_err(|_| CryptoError::KeyGeneration)?;
247            deriver
248                .set_peer(&peer_pub)
249                .map_err(|_| CryptoError::KeyGeneration)?;
250            let derived = deriver
251                .derive_to_vec()
252                .map_err(|_| CryptoError::KeyGeneration)?;
253            Ok(derived)
254        })
255    }
256}
257
258#[cfg(test)]
259mod tests {
260    use super::*;
261    static CRYPTO: CryptoNative = CryptoNative {};
262
263    #[tokio::test]
264    pub async fn hash_sha256() {
265        let ikm = Vec::from([0u8; 32]);
266        let hash = CRYPTO.hash_sha256(&ikm).await.unwrap();
267        assert_eq!(
268            hash,
269            [
270                102, 104, 122, 173, 248, 98, 189, 119, 108, 143, 193, 139, 142,
271                159, 142, 32, 8, 151, 20, 133, 110, 226, 51, 179, 144, 42, 89,
272                29, 13, 95, 41, 37
273            ]
274        );
275    }
276
277    #[tokio::test]
278    pub async fn hash_sha256_key_derivation() {
279        let mut ikm = Vec::from([0u8; 32]);
280        let salt = Vec::from([0u8; 16]);
281        let hash_a = CRYPTO.hkdf_sha256(&ikm, &salt).await.unwrap();
282        ikm[0] = 1u8;
283        let hash_b = CRYPTO.hkdf_sha256(&ikm, &salt).await.unwrap();
284        assert_ne!(hash_a, hash_b);
285        assert_ne!(hash_a.to_vec(), ikm);
286        assert_eq!(
287            hash_a,
288            [
289                223, 114, 4, 84, 111, 27, 238, 120, 184, 83, 36, 167, 137, 140,
290                161, 25, 179, 135, 224, 19, 134, 209, 174, 240, 55, 120, 29,
291                74, 138, 3, 106, 238
292            ]
293        );
294    }
295
296    #[test]
297    pub fn base58() {
298        let something = b"yellow submarineyellow submarine".to_owned();
299        let some_check =
300            b"9At2nzU19GjL8F4WFRyB7RZSGLemMGUMVBZAMChfndF2".to_owned();
301
302        let based = CRYPTO.enc_b58(&something).unwrap();
303        let unbased = CRYPTO.dec_b58(&some_check).unwrap();
304        assert_eq!(something, unbased);
305        assert_eq!(some_check, based);
306    }
307
308    // Signatures
309    #[tokio::test]
310    pub async fn dsa_ed25519() {
311        // Checks gen_ed25519, sig_ed25519, ver_ed25519 against itself
312        let data = b"Some message to  sign".to_vec();
313        let other_data = b"Some message to sign".to_vec();
314
315        // Generate key and signature
316        let (pub_key, pri_key) = CRYPTO.gen_ed25519().await.unwrap();
317        assert_eq!(pub_key.len(), 44_usize);
318        assert_eq!(pri_key.len(), 48_usize);
319
320        let sig = CRYPTO.sig_ed25519(&pri_key, &data).await.unwrap();
321        assert_eq!(sig.len(), 64_usize);
322
323        // Verify key, signature and data
324        let ver = CRYPTO.ver_ed25519(&pub_key, &sig, &data).await.unwrap();
325        assert!(ver);
326
327        // Falsify other data
328        let ver = CRYPTO
329            .ver_ed25519(&pub_key, &sig, &other_data)
330            .await
331            .unwrap();
332        assert!(!ver);
333
334        // Falsify other key
335        let (other_pub_key, other_pri_key) =
336            CRYPTO.gen_ed25519().await.unwrap();
337        let ver = CRYPTO
338            .ver_ed25519(&other_pub_key, &sig, &data)
339            .await
340            .unwrap();
341        assert!(!ver);
342
343        // Falsify other signature
344        let other_sig =
345            CRYPTO.sig_ed25519(&other_pri_key, &data).await.unwrap();
346        let ver = CRYPTO
347            .ver_ed25519(&pub_key, &other_sig, &data)
348            .await
349            .unwrap();
350        assert!(!ver);
351    }
352
353    #[tokio::test]
354    pub async fn aes_ctr() {
355        let key = [0u8; 32];
356        let iv = [0u8; 16];
357
358        let data = b"Some message to encrypt".to_vec();
359
360        let ciphered = CRYPTO.aes_ctr_encrypt(&key, &iv, &data).await.unwrap();
361        let deciphered =
362            CRYPTO.aes_ctr_decrypt(&key, &iv, &ciphered).await.unwrap();
363
364        assert_ne!(ciphered, data);
365        assert_eq!(data, deciphered.to_vec());
366    }
367
368    #[tokio::test]
369    pub async fn key_wrap() {
370        let kek_bytes = [1u8; 32];
371        let sym_key: [u8; 32] =
372            CRYPTO.random_bytes(32_usize).try_into().unwrap();
373        let arand = CRYPTO.key_upwrap(&kek_bytes, &sym_key).await.unwrap();
374        let brand = CRYPTO.key_unwrap(&kek_bytes, &arand).await.unwrap();
375
376        assert_ne!(arand.to_vec(), brand.to_vec());
377        assert_eq!(arand.len(), brand.len() + 8);
378    }
379
380    #[tokio::test]
381    async fn dh_x25519() {
382        let (ser_pub, ser_pri) = CRYPTO.gen_x25519().await.unwrap();
383        let (cli_pub, cli_pri) = CRYPTO.gen_x25519().await.unwrap();
384
385        let cli_shared =
386            CRYPTO.derive_x25519(&cli_pri, &ser_pub).await.unwrap();
387        let ser_shared =
388            CRYPTO.derive_x25519(&ser_pri, &cli_pub).await.unwrap();
389
390        assert_eq!(cli_shared, ser_shared);
391        assert_eq!(cli_shared.len(), 32);
392    }
393
394    #[tokio::test]
395    pub async fn crypto_multi_roundtrip() {
396        // Given
397        let mut client_list = Vec::new();
398
399        // Generate symmetric random key
400        let sym_key: [u8; 32] = CRYPTO.random_bytes(32).try_into().unwrap();
401
402        for _ in 0..10 {
403            let (cli_pub, cli_pri) = CRYPTO.gen_x25519().await.unwrap();
404            client_list.push((cli_pri, cli_pub));
405        }
406
407        // Encrypt data with symmetric key
408        let data = b"Some message to encrypt".to_vec();
409        let iv = [0u8; 16];
410        let cipher =
411            CRYPTO.aes_ctr_encrypt(&sym_key, &iv, &data).await.unwrap();
412
413        // Sender (server)
414        let mut payloads = Vec::new();
415        for (_, peer_pub) in client_list.iter().take(10) {
416            let (ser_pub, ser_pri) = CRYPTO.gen_x25519().await.unwrap();
417            let ser_kek_bytes: [u8; 32] = CRYPTO
418                .derive_x25519(&ser_pri, peer_pub)
419                .await
420                .unwrap()
421                .try_into()
422                .unwrap();
423
424            let wrapped =
425                CRYPTO.key_upwrap(&ser_kek_bytes, &sym_key).await.unwrap();
426
427            payloads.push((ser_pub, wrapped));
428        }
429
430        // Receiver (client)
431        for i in 0..10 {
432            // Unwraps key and decrypts
433            let cli_kek_bytes: [u8; 32] = CRYPTO
434                .derive_x25519(&client_list[i].0, &payloads[i].0)
435                .await
436                .unwrap()
437                .try_into()
438                .unwrap();
439            let unwrapped = CRYPTO
440                .key_unwrap(&cli_kek_bytes, &payloads[i].1)
441                .await
442                .unwrap();
443            let plain = CRYPTO
444                .aes_ctr_decrypt(&unwrapped, &iv, &cipher)
445                .await
446                .unwrap();
447
448            // Check key wraps
449            assert_ne!(payloads[i].1.to_vec(), unwrapped.to_vec());
450            assert_eq!(payloads[i].1.len(), unwrapped.len() + 8);
451
452            // Check data, cipher and deciphered
453            assert_ne!(data, cipher);
454            assert_eq!(plain, data);
455        }
456    }
457}