datex_core/crypto/
crypto_native.rs

1use crate::stdlib::{future::Future, pin::Pin, usize};
2use std::sync::atomic::{AtomicU64, Ordering};
3use std::sync::OnceLock;
4
5use super::crypto::{CryptoError, CryptoTrait};
6use crate::runtime::global_context::get_global_context;
7use rand::{rngs::OsRng, Rng};
8use rsa::{
9    pkcs8::{EncodePrivateKey, EncodePublicKey},
10    RsaPrivateKey, RsaPublicKey,
11};
12use uuid::Uuid;
13
14static UUID_COUNTER: OnceLock<AtomicU64> = OnceLock::new();
15
16fn init_counter() -> &'static AtomicU64 {
17    UUID_COUNTER.get_or_init(|| AtomicU64::new(1))
18}
19fn generate_pseudo_uuid() -> String {
20    let counter = init_counter();
21    let count = counter.fetch_add(1, Ordering::Relaxed);
22
23    // Encode counter into last segment, keeping UUID-like structure
24    format!("00000000-0000-0000-0000-{count:012x}")
25}
26
27#[derive(Debug, Clone, PartialEq)]
28pub struct CryptoNative;
29impl CryptoTrait for CryptoNative {
30    fn encrypt_rsa(
31        &self,
32        data: Vec<u8>,
33        public_key: Vec<u8>,
34    ) -> Pin<Box<(dyn Future<Output = Result<Vec<u8>, CryptoError>> + 'static)>>
35    {
36        todo!("#164 Undescribed by author.")
37    }
38
39    fn decrypt_rsa(
40        &self,
41        data: Vec<u8>,
42        private_key: Vec<u8>,
43    ) -> Pin<Box<(dyn Future<Output = Result<Vec<u8>, CryptoError>> + 'static)>>
44    {
45        todo!("#165 Undescribed by author.")
46    }
47
48    fn sign_rsa(
49        &self,
50        data: Vec<u8>,
51        private_key: Vec<u8>,
52    ) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, CryptoError>>>> {
53        todo!("#166 Undescribed by author.")
54    }
55
56    fn verify_rsa(
57        &self,
58        data: Vec<u8>,
59        signature: Vec<u8>,
60        public_key: Vec<u8>,
61    ) -> Pin<Box<dyn Future<Output = Result<bool, CryptoError>>>> {
62        todo!("#167 Undescribed by author.")
63    }
64
65    fn create_uuid(&self) -> String {
66        // use pseudo-random UUID for testing
67        cfg_if::cfg_if! {
68            if #[cfg(feature = "debug")] {
69                if get_global_context().debug_flags.enable_deterministic_behavior {
70                    generate_pseudo_uuid()
71                }
72                else {
73                    Uuid::new_v4().to_string()
74                }
75            }
76            else {
77                Uuid::new_v4().to_string()
78            }
79        }
80    }
81
82    fn random_bytes(&self, length: usize) -> Vec<u8> {
83        let mut rng = rand::thread_rng();
84        (0..length).map(|_| rng.r#gen()).collect()
85    }
86
87    fn new_encryption_key_pair(
88        &self,
89    ) -> Pin<Box<dyn Future<Output = Result<(Vec<u8>, Vec<u8>), CryptoError>>>>
90    {
91        Box::pin(async {
92            let mut rng = OsRng;
93            let private_key = RsaPrivateKey::new(&mut rng, 4096)
94                .map_err(|_| CryptoError::KeyGeneratorFailed)?;
95
96            let private_key_der = private_key
97                .to_pkcs8_der()
98                .map_err(|_| CryptoError::KeyExportFailed)?
99                .as_bytes()
100                .to_vec();
101            let public_key = RsaPublicKey::from(&private_key);
102
103            let public_key_der = public_key
104                .to_public_key_der()
105                .map_err(|_| CryptoError::KeyExportFailed)?
106                .as_bytes()
107                .to_vec();
108
109            Ok((public_key_der, private_key_der))
110        })
111    }
112
113    fn new_sign_key_pair(
114        &self,
115    ) -> Pin<Box<dyn Future<Output = Result<(Vec<u8>, Vec<u8>), CryptoError>>>>
116    {
117        todo!("#168 Undescribed by author.")
118    }
119}
120
121// TODO #169: reenable
122/*#[cfg(test)]
123mod tests {
124    use super::*;
125    static CRYPTO: CryptoNative = CryptoNative {};
126
127    #[test]
128    fn uuid() {
129        let uuid = CRYPTO.create_uuid();
130        assert_eq!(uuid.len(), 36);
131
132        for _ in 0..100 {
133            assert_ne!(CRYPTO.create_uuid(), uuid);
134        }
135    }
136
137    #[test]
138    fn random_bytes() {
139        let random_bytes = CRYPTO.random_bytes(32);
140        assert_eq!(random_bytes.len(), 32);
141    }
142
143    #[tokio::test]
144    async fn test_enc_key_pair() {
145        let key_pair = CRYPTO.new_encryption_key_pair().await.unwrap();
146        assert_eq!(key_pair.0.len(), 550);
147        // assert_eq!(key_pair.1.len(), 2375);
148    }
149}*/