product_os_security/
lib.rs

1#![no_std]
2extern crate no_std_compat as std;
3extern crate alloc;
4
5use std::prelude::v1::*;
6
7#[cfg(feature = "certificates")]
8pub mod certificates;
9
10#[cfg(feature = "certificates_custom")]
11pub mod certificates_custom;
12
13#[cfg(feature = "certificates_custom")]
14mod x509_cert;
15
16#[cfg(any(feature = "auth_verify", feature = "diffie_hellman_key_store", feature = "diffie_hellman_client_server_key_store", feature = "jwt_auth_verify"))]
17use std::collections::BTreeMap;
18
19#[cfg(any(feature = "hash", feature = "hasher", feature = "mac"))]
20use blake2::digest::{ Mac, FixedOutput, Digest };
21
22
23#[cfg(feature = "public_private_sign_verify")]
24use ring::{
25    signature::KeyPair
26};
27
28#[cfg(feature = "password_hash")]
29use argon2::{
30    password_hash::{ PasswordHasher, PasswordVerifier }
31};
32
33#[cfg(any(feature = "generator", feature = "symmetric_encrypt_decrypt"))]
34pub use product_os_random::{ RandomGenerator, RandomGeneratorTemplate };
35
36#[cfg(any(feature = "random", feature = "thread_send"))]
37pub use product_os_random::RNG;
38
39#[cfg(all(feature = "random", not(feature = "thread_send")))]
40pub use product_os_random::{ OsRng, ThreadRng, CryptoRNG };
41
42#[cfg(any(feature = "random", feature = "thread_send"))]
43pub use product_os_random::StdRng;
44
45#[cfg(any(feature = "thread_send", feature = "random"))]
46pub use product_os_random::SeedableRng;
47
48#[cfg(feature = "jwt_encrypt_decrypt")]
49use base64::{ Engine as _, engine::general_purpose as base64GP };
50
51#[cfg(feature = "jwt_auth_verify")]
52use jwt_compact::{ prelude::*, alg::{ Hs256, Hs256Key } };
53
54#[cfg(feature = "jwt_auth_verify")]
55use serde::{Serialize, Deserialize};
56
57#[cfg(feature = "jwt_auth_verify")]
58use serde_json::Value;
59
60#[cfg(any(feature = "auth_verify", feature = "byte_vector"))]
61pub trait AsByteVector {
62    fn as_byte_vector(&self) -> Vec<u8>;
63}
64
65#[cfg(any(feature = "auth_verify", feature = "byte_vector"))]
66impl AsByteVector for serde_json::Value {
67    fn as_byte_vector(&self) -> Vec<u8> {
68        self.to_string().into_bytes()
69    }
70}
71
72#[cfg(feature = "auth_verify")]
73pub fn create_auth_request<T>(query: Option<&BTreeMap<String, String>>, encoded: bool, payload: Option<T>,
74                              headers: Option<&BTreeMap<String, String>>, exclude_headers: &[&str], key: Option<&[u8]>) -> String
75where T: AsByteVector
76{
77    let mut representation: Vec<u8> = vec!();
78
79    match query {
80        Some(q) => representation.extend_from_slice(create_auth_query(q, encoded, key).as_bytes()),
81        None => ()
82    }
83
84    match headers {
85        Some(h) => representation.extend_from_slice(create_auth_headers(h, exclude_headers, key).as_bytes()),
86        None => ()
87    }
88
89    match payload {
90        Some(p) => representation.extend_from_slice(create_auth_payload(&p, key).as_slice()),
91        None => ()
92    }
93
94    hex_encode(create_auth(representation.as_slice(), key, None))
95}
96
97#[cfg(feature = "auth_verify")]
98pub fn verify_auth_request<T>(query: Option<&BTreeMap<String, String>>, encoded: bool, payload: Option<T>,
99                           headers: Option<&BTreeMap<String, String>>, exclude_headers: &[&str], tag: &str, key: Option<&[u8]>) -> bool
100where T: AsByteVector
101{
102    let auth = create_auth_request(query, encoded, payload, headers, exclude_headers, key);
103    auth.as_str() == tag
104}
105
106#[cfg(feature = "auth_verify")]
107pub fn create_auth_request_json(query: Option<&BTreeMap<String, String>>, encoded: bool, json: Option<&serde_json::Value>,
108                              headers: Option<&BTreeMap<String, String>>, exclude_headers: &[&str], key: Option<&[u8]>) -> String
109{
110    let mut representation: Vec<u8> = vec!();
111
112    match query {
113        Some(q) => representation.extend_from_slice(create_auth_query(q, encoded, key).as_bytes()),
114        None => ()
115    }
116
117    match headers {
118        Some(h) => representation.extend_from_slice(create_auth_headers(h, exclude_headers, key).as_bytes()),
119        None => ()
120    }
121
122    match json {
123        Some(v) => representation.extend_from_slice(create_auth_json(&v, key).as_slice()),
124        None => ()
125    }
126
127    hex_encode(create_auth(representation.as_slice(), key, None))
128}
129
130#[cfg(feature = "auth_verify")]
131pub fn verify_auth_request_json(query: Option<&BTreeMap<String, String>>, encoded: bool, json: Option<&serde_json::Value>,
132                              headers: Option<&BTreeMap<String, String>>, exclude_headers: &[&str], tag: &str, key: Option<&[u8]>) -> bool
133{
134    let auth = create_auth_request_json(query, encoded, json, headers, exclude_headers, key);
135    auth.as_str() == tag
136}
137
138
139#[cfg(feature = "auth_verify")]
140pub fn create_auth_query(query: &BTreeMap<String, String>, encoded: bool, key: Option<&[u8]>) -> String {
141    let mut representation: Vec<u8> = vec!();
142
143    for (key, value) in query {
144
145        if encoded {
146            representation.extend_from_slice(product_os_urlencoding::decode(key.as_str()).unwrap().to_string().as_bytes());
147            representation.extend_from_slice(product_os_urlencoding::decode(value.as_str()).unwrap().to_string().as_bytes());
148        }
149        else {
150            representation.extend_from_slice(key.as_bytes());
151            representation.extend_from_slice(value.as_bytes());
152        }
153    }
154
155    hex_encode(create_auth(representation.as_slice(), key, None))
156}
157
158#[cfg(feature = "auth_verify")]
159pub fn verify_auth_query(query: &BTreeMap<String, String>, encoded: bool, tag: &str, key: Option<&[u8]>) -> bool
160{
161    let auth = create_auth_query(query, encoded, key);
162    auth.as_str() == tag
163}
164
165#[cfg(feature = "auth_verify")]
166pub fn create_auth_headers(headers: &BTreeMap<String, String>, exclude_headers: &[&str], key: Option<&[u8]>) -> String {
167    let mut representation: Vec<u8> = vec!();
168
169    for (key, value) in headers {
170        if !exclude_headers.contains(&key.as_str()) {
171            representation.extend_from_slice(key.as_bytes());
172            representation.extend_from_slice(value.as_bytes());
173        }
174    }
175
176    hex_encode(create_auth(representation.as_slice(), key, None))
177}
178
179#[cfg(feature = "auth_verify")]
180pub fn verify_auth_headers(headers: &BTreeMap<String, String>, encoded: bool, tag: &str, key: Option<&[u8]>) -> bool
181{
182    let auth = create_auth_query(headers, encoded, key);
183    auth.as_str() == tag
184}
185
186#[cfg(feature = "auth_verify")]
187pub fn create_auth_payload<T>(payload: &T, key: Option<&[u8]>) -> Vec<u8>
188where T: AsByteVector
189{
190    let byte_representation = payload.as_byte_vector();
191    create_auth(byte_representation.as_slice(), key, None)
192}
193
194#[cfg(feature = "auth_verify")]
195pub fn verify_auth_payload<T>(payload: &T, tag: &[u8], key: Option<&[u8]>) -> bool
196    where T: AsByteVector
197{
198    let auth = create_auth_payload(payload, key);
199    verify_auth(auth.as_slice(), tag, key, None)
200}
201
202#[cfg(feature = "auth_verify")]
203pub fn create_auth_json(json: &serde_json::Value, key: Option<&[u8]>) -> Vec<u8>
204{
205    let byte_representation = json.to_string();
206    create_auth(byte_representation.as_bytes(), key, None)
207}
208
209#[cfg(feature = "auth_verify")]
210pub fn verify_auth_json(json: &serde_json::Value, tag: &[u8], key: Option<&[u8]>) -> bool
211{
212    let auth = create_auth_json(json, key);
213    verify_auth(auth.as_slice(), tag, key, None)
214}
215
216
217
218#[cfg(feature = "auth_verify")]
219pub fn create_auth(data: &[u8], key: Option<&[u8]>, algorithm: Option<&str>) -> Vec<u8> {
220    match key {
221        Some(k) => {
222            if k.len() == 0 { return Vec::from([]); } // Bad key length
223            match algorithm {
224                Some(alg) => {
225                    match alg {
226                        // "jwt" => { jwt_auth(data, k).into_bytes() },
227                        "blake2" => blake2_mac(data, k),
228                        _ => blake2_mac(data, k)
229                    }
230                },
231                None => blake2_mac(data, k)
232            }
233        },
234        None => {
235            match algorithm {
236                Some(alg) => {
237                    match alg {
238                        "blake2" => blake2_hash(data),
239                        _ => blake2_hash(data)
240                    }
241                },
242                None => blake2_hash(data)
243            }
244        }
245    }
246}
247
248
249#[cfg(feature = "auth_verify")]
250pub fn verify_auth(data: &[u8], tag: &[u8], key: Option<&[u8]>, algorithm: Option<&str>) -> bool {
251    match key {
252        Some(k) => {
253            if k.len() == 0 { return false; } // Bad key length
254            match algorithm {
255                Some(alg) => {
256                    match alg {
257                        "blake2" => blake2_verify_mac(data, tag, k),
258                        _ => blake2_verify_mac(data, tag, k)
259                    }
260                },
261                None => blake2_verify_mac(data, tag, k)
262            }
263        },
264        None => {
265            match algorithm {
266                Some(alg) => {
267                    match alg {
268                        "blake2" => blake2_hash(data).as_slice() == tag,
269                        _ => blake2_hash(data).as_slice() == tag
270                    }
271                },
272                None => blake2_hash(data).as_slice() == tag
273            }
274        }
275    }
276}
277
278
279#[cfg(feature = "hash")]
280pub fn create_salted_hash(data: &[u8], generator: &mut RandomGenerator, algorithm: Option<&str>) -> (Vec<u8>, Vec<u8>) {
281    let salt = generator.get_random_string(16).as_bytes().to_vec();
282    let mut input = data.to_vec();
283    input.append(&mut salt.to_vec());
284
285    match algorithm {
286        Some(alg) => {
287            match alg {
288                "paranoid_hash" => (create_string_hash(std::str::from_utf8(input.as_slice()).unwrap()).into_bytes(), salt),
289                "blake2" => (blake2_hash(input.as_slice()), salt),
290                _ => (blake2_hash(input.as_slice()), salt)
291            }
292        },
293        None => (blake2_hash(input.as_slice()), salt)
294    }
295}
296
297
298#[cfg(feature = "hash")]
299pub fn create_hash(data: &[u8], algorithm: Option<&str>) -> Vec<u8> {
300    match algorithm {
301        Some(alg) => {
302            match alg {
303                "paranoid_hash" => create_string_hash(std::str::from_utf8(data).unwrap()).into_bytes(),
304                "blake2" => blake2_hash(data),
305                _ => blake2_hash(data)
306            }
307        },
308        None => blake2_hash(data)
309    }
310}
311
312
313#[cfg(feature = "hash")]
314pub fn verify_hash(data: &[u8], original_hash: &[u8], stored_salt: Option<&[u8]>, algorithm: Option<&str>) -> bool {
315    let mut input = data.to_vec();
316    match stored_salt {
317        None => (),
318        Some(salt) => input.append(&mut salt.to_vec())
319    }
320
321    let hash = create_hash(input.as_slice(), algorithm);
322
323    if hash.as_slice() == original_hash { true }
324    else { false }
325}
326
327
328
329#[cfg(feature = "auth_verify")]
330pub fn hex_encode(data: Vec<u8>) -> String {
331    hex::encode(data)
332}
333
334#[cfg(feature = "auth_verify")]
335pub fn hex_decode(value: String) -> Vec<u8> {
336    hex::decode(value).unwrap()
337}
338
339
340
341#[cfg(feature = "jwt_encrypt_decrypt")]
342pub fn base64_encode(data: &[u8]) -> String {
343    base64GP::URL_SAFE_NO_PAD.encode(data)
344}
345
346#[cfg(feature = "jwt_encrypt_decrypt")]
347pub fn base64_decode(value: &str) -> Vec<u8> {
348    base64GP::URL_SAFE_NO_PAD.decode(value).unwrap_or_else(|_| vec![])
349}
350
351
352#[cfg(feature = "hash")]
353pub fn create_string_hash(data: &str) -> String {
354    let mut hasher = blake2::Blake2b512::new();
355
356    hasher.update(data.as_bytes());
357    let hash = hasher.finalize();
358    String::from_utf8_lossy(&hash[..]).to_string()
359}
360
361
362#[cfg(feature = "hash")]
363fn blake2_hash(data: &[u8]) -> Vec<u8> {
364    let mut hasher = blake2::Blake2b512::new();
365
366    hasher.update(data);
367    let hash = hasher.finalize();
368    hash[..].to_vec()
369}
370
371
372#[cfg(feature = "hasher")]
373#[derive(Clone, Debug)]
374pub struct ProductOSHasher {
375    hasher: blake2::Blake2b<blake2::digest::typenum::U8>
376}
377
378#[cfg(feature = "hasher")]
379impl ProductOSHasher {
380    pub fn new() -> Self {
381        Self {
382            hasher: blake2::Blake2b::default()
383        }
384    }
385}
386
387#[cfg(feature = "hasher")]
388impl std::hash::Hasher for ProductOSHasher {
389    fn finish(&self) -> u64 {
390        u64::from_be_bytes(self.hasher.clone().finalize().into())
391    }
392
393    fn write(&mut self, bytes: &[u8]) {
394        self.hasher.update(bytes)
395    }
396}
397
398#[cfg(feature = "hasher")]
399impl std::hash::BuildHasher for ProductOSHasher {
400    type Hasher = ProductOSHasher;
401
402    fn build_hasher(&self) -> Self::Hasher {
403        ProductOSHasher::default()
404    }
405}
406
407#[cfg(feature = "hasher")]
408impl Default for ProductOSHasher {
409    fn default() -> Self {
410        ProductOSHasher::new()
411    }
412}
413
414
415
416#[cfg(feature = "mac")]
417fn blake2_mac(data: &[u8], key: &[u8]) -> Vec<u8> {
418    match blake2::Blake2bMac512::new_from_slice(key) {
419        Ok(mut mac) => {
420            mac.update(data);
421            let hash = mac.finalize_fixed();
422            hash.to_vec()
423        },
424        Err(e) => panic!("Invalid key length provided to blake2 auth: {}", e)
425    }
426}
427
428#[cfg(feature = "mac")]
429fn blake2_verify_mac(msg: &[u8], tag: &[u8], key: &[u8]) -> bool {
430    let auth = blake2_mac(msg, key);
431    auth == tag
432}
433
434
435
436
437#[cfg(feature = "jwt_auth_verify")]
438pub struct JWTGenerator {
439    issuer: String,
440    default_until: i64,
441    default_audience: String,
442    jti_length: usize,
443    random_generator: RandomGenerator,
444    time_generator: product_os_async_executor::moment::Moment
445}
446
447#[cfg(feature = "jwt_auth_verify")]
448pub trait TokenClaims<'a, T>: Clone
449{
450    fn verify(&self, verify_map: &T) -> bool;
451}
452
453#[cfg(feature = "jwt_auth_verify")]
454#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
455pub struct DefaultClaims {
456    #[serde(rename = "iss")]
457    issuer: String,
458    #[serde(rename = "sub")]
459    subject: String,
460    #[serde(rename = "aud")]
461    audience: String,
462    #[serde(rename = "jti")]
463    jwt_id: String
464}
465
466
467#[cfg(feature = "jwt_auth_verify")]
468impl DefaultClaims {
469    pub fn from_vector(vector: Vec<(String, serde_json::Value)>) -> Self {
470        let mut claims = Self {
471            issuer: "".to_string(),
472            subject: "".to_string(),
473            audience: "".to_string(),
474            jwt_id: "".to_string(),
475        };
476
477        for (claim, value) in vector.iter() {
478            let value = match value {
479                Value::Null => String::new(),
480                Value::Bool(b) => b.to_string(),
481                Value::Number(n) => n.to_string(),
482                Value::String(s) => s.to_owned(),
483                Value::Array(_) => String::new(),
484                Value::Object(_) => String::new()
485            };
486
487            match claim.as_str() {
488                "issuer" => { claims.issuer = value; }
489                "subject" => { claims.subject = value; }
490                "audience" => { claims.audience = value; }
491                "jwt_id" => { claims.jwt_id = value; }
492                _ => {}
493            }
494        }
495
496        claims
497    }
498}
499
500
501#[cfg(feature = "jwt_auth_verify")]
502impl TokenClaims<'_, DefaultClaims> for DefaultClaims {
503    fn verify(&self, verify_map: &DefaultClaims) -> bool {
504        self.issuer == verify_map.issuer && self.subject == verify_map.subject &&
505            self.audience == verify_map.audience && self.jwt_id == verify_map.jwt_id
506    }
507}
508
509
510
511#[cfg(feature = "jwt_auth_verify")]
512#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
513pub struct EmptyClaims {}
514
515#[cfg(feature = "jwt_auth_verify")]
516impl EmptyClaims {
517    pub fn new() -> Self {
518        EmptyClaims {}
519    }
520}
521
522#[cfg(feature = "jwt_auth_verify")]
523impl TokenClaims<'_, EmptyClaims> for EmptyClaims {
524    fn verify(&self, _verify_map: &EmptyClaims) -> bool {
525        todo!()
526    }
527}
528
529
530
531#[cfg(feature = "jwt_auth_verify")]
532#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
533pub struct CustomClaims {
534    claims: BTreeMap<String, String>
535}
536
537
538#[cfg(feature = "jwt_auth_verify")]
539impl CustomClaims {
540    pub fn from_vector(vector: Vec<(String, serde_json::Value)>) -> Self {
541        let mut claims = BTreeMap::new();
542
543        for (claim, value) in vector.iter() {
544            let value = match value {
545                Value::Null => String::new(),
546                Value::Bool(b) => b.to_string(),
547                Value::Number(n) => n.to_string(),
548                Value::String(s) => s.to_owned(),
549                Value::Array(_) => String::new(),
550                Value::Object(_) => String::new()
551            };
552
553            claims.insert(claim.to_owned(), value);
554        }
555
556        Self {
557            claims
558        }
559    }
560}
561
562
563#[cfg(feature = "jwt_auth_verify")]
564impl TokenClaims<'_, CustomClaims> for CustomClaims {
565    fn verify(&self, verify_map: &CustomClaims) -> bool {
566        for (verify_claim, verify_value) in verify_map.claims.iter() {
567            match self.claims.get(verify_claim.as_str()) {
568                None => { return false }
569                Some(value) => {
570                    if value.as_str() != verify_value.as_str() {
571                        return false
572                    }
573                }
574            }
575        }
576
577        return true
578    }
579}
580
581
582
583
584#[cfg(feature = "jwt_auth_verify")]
585#[derive(Debug)]
586pub enum JWTError {
587    InvalidSignature,
588    InvalidKey,
589    EncodeFailure,
590    DecodeFailure,
591    InvalidClaims,
592    InvalidNonce
593}
594
595#[cfg(feature = "jwt_auth_verify")]
596impl JWTGenerator where {
597    pub fn new(gen: Option<product_os_random::RNG>, func: Option<fn() -> chrono::DateTime<chrono::Utc>>, issuer: String, default_until: i64, default_audience: String, jti_length: usize) -> Self {
598        let time_gen = product_os_async_executor::moment::Moment::new(func);
599
600        Self {
601            issuer,
602            default_until,
603            default_audience,
604            jti_length,
605            random_generator: RandomGenerator::new(gen),
606            time_generator: time_gen
607        }
608    }
609
610    pub fn get_default_until(&self) -> &i64 {
611        &self.default_until
612    }
613
614    pub fn get_default_audience(&self) -> String {
615        self.default_audience.to_owned()
616    }
617
618    pub fn generate_default_claims(&self, subject: String, audience: Option<String>, jwt_id: String) -> DefaultClaims {
619        let audience = match audience {
620            Some(a) => a,
621            None => self.default_audience.to_owned()
622        };
623
624        DefaultClaims {
625            issuer: self.issuer.to_owned(),
626            subject,
627            audience,
628            jwt_id
629        }
630    }
631
632    /*
633        iss (issuer): Issuer of the JWT
634        sub (subject): Subject of the JWT (the user)
635        aud (audience): Recipient for which the JWT is intended
636        exp (expiration time): Time after which the JWT expires
637        nbf (not before time): Time before which the JWT must not be accepted for processing
638        iat (issued at time): Time at which the JWT was issued; can be used to determine age of the JWT
639        jti (JWT ID): Unique identifier; can be used to prevent the JWT from being replayed (allows a token to be used only once)
640    */
641    pub fn jwt_auth<'a, T: TokenClaims<'a, T> + Serialize>(&mut self, subject: String, audience: Option<String>, until: Option<chrono::DateTime<chrono::Utc>>, custom_claims: Option<T>, custom_header: Option<Header>, jwt_secret: &[u8], encryption_key: Option<&[u8]>, #[cfg(not(feature = "jwt_encrypt_decrypt_std"))] gen: &mut Option<impl product_os_random::RngCore>) -> Result<(String, String), JWTError> {
642        let header = custom_header.unwrap_or_else(|| Header::empty());
643
644        let now = self.time_generator.now();
645
646        let time_func = self.time_generator.get_function();
647        let time_options = TimeOptions::new(chrono::Duration::seconds(5), time_func);
648
649        let until = match until {
650            None => chrono::Duration::seconds(self.default_until.to_owned()),
651            Some(u) => chrono::Duration::seconds(u.timestamp() - now.timestamp())
652        };
653
654        match encryption_key {
655            None => {
656                let jti = self.random_generator.get_random_string(self.jti_length.into());
657
658                match custom_claims {
659                    None => {
660                        let claims = Claims::new(self.generate_default_claims(subject, audience, jti.to_owned()))
661                            .set_duration_and_issuance(&time_options, until)
662                            .set_not_before(now);
663
664                        let key = Hs256Key::new(jwt_secret);
665
666                        match Hs256.token(&header, &claims, &key) {
667                            Ok(jwt) => Ok((jwt, jti)),
668                            Err(_) => Err(JWTError::EncodeFailure)
669                        }
670                    },
671                    Some(custom) => {
672                        let claims = Claims::new(custom)
673                            .set_duration_and_issuance(&time_options, until)
674                            .set_not_before(now);
675
676                        let key = Hs256Key::new(jwt_secret);
677
678                        match Hs256.token(&header, &claims, &key) {
679                            Ok(jwt) => Ok((jwt, jti)),
680                            Err(_) => Err(JWTError::EncodeFailure)
681                        }
682                    }
683                }
684            },
685            Some(enc_secret) => {
686                #[cfg(feature = "jwt_encrypt_decrypt")]
687                {
688                    let nonce = create_nonce(#[cfg(not(feature = "jwt_encrypt_decrypt_std"))] gen);
689                    let jti = base64GP::URL_SAFE_NO_PAD.encode(nonce.to_owned());
690
691                    match custom_claims {
692                        None => {
693                            let claims = Claims::new(self.generate_default_claims(subject, audience, jti.to_owned()))
694                                .set_duration_and_issuance(&time_options, until)
695                                .set_not_before(now);
696
697                            let key = Hs256Key::new(jwt_secret);
698
699                            match Hs256.token(&header, &claims, &key) {
700                                Ok(jwt) => {
701                                    match orion::hazardous::aead::xchacha20poly1305::SecretKey::from_slice(enc_secret) {
702                                        Ok(secret) => {
703                                            let mut output = vec![];
704                                            match orion::hazardous::aead::xchacha20poly1305::seal(&secret, &nonce, jwt.as_bytes(), None, &mut output) {
705                                                Ok(_) => Ok((base64GP::URL_SAFE_NO_PAD.encode(output), jti)),
706                                                Err(e) => panic!("Error encrypting value {}", e)
707                                            }
708                                        },
709                                        Err(e) => panic!("Invalid key {}", e)
710                                    }
711                                }
712                                Err(_) => Err(JWTError::EncodeFailure)
713                            }
714                        },
715                        Some(custom) => {
716                            let claims = Claims::new(custom)
717                                .set_duration_and_issuance(&time_options, until)
718                                .set_not_before(now);
719
720                            let key = Hs256Key::new(jwt_secret);
721
722                            match Hs256.token(&header, &claims, &key) {
723                                Ok(jwt) => {
724                                    match orion::hazardous::aead::xchacha20poly1305::SecretKey::from_slice(enc_secret) {
725                                        Ok(secret) => {
726                                            let mut output = vec![];
727                                            match orion::hazardous::aead::xchacha20poly1305::seal(&secret, &nonce, jwt.as_bytes(), None, &mut output) {
728                                                Ok(_) => Ok((base64GP::URL_SAFE_NO_PAD.encode(output), jti)),
729                                                Err(e) => panic!("Error encrypting value {}", e)
730                                            }
731                                        },
732                                        Err(e) => panic!("Invalid key {}", e)
733                                    }
734                                }
735                                Err(_) => Err(JWTError::EncodeFailure)
736                            }
737                        }
738                    }
739                }
740                #[cfg(not(feature = "jwt_encrypt_decrypt"))]
741                {
742                    panic!("JWT Encryption not enabled - add feature jwt_encrypt_decrypt to product_os_security");
743                }
744            }
745        }
746    }
747
748    #[cfg(feature = "jwt_auth_verify")]
749    pub fn jwt_get_token_claims<'a, T: TokenClaims<'a, T> + serde::de::DeserializeOwned>(&self, token: &str, jwt_secret: &[u8], nonce: &[u8], decryption_key: Option<&[u8]>) -> Result<(String, Token<T>), JWTError>
750    {
751        let token_string = match decryption_key {
752            None => token.to_owned(),
753            Some(dec_secret) => {
754                #[cfg(feature = "jwt_encrypt_decrypt")]
755                {
756                    match base64GP::URL_SAFE_NO_PAD.decode(token) {
757                        Ok(decoded) => {
758                            match orion::hazardous::aead::xchacha20poly1305::SecretKey::from_slice(dec_secret) {
759                                Ok(secret) => {
760                                    match orion::hazardous::aead::xchacha20poly1305::Nonce::from_slice(nonce) {
761                                        Ok(nonce) => {
762                                            let mut output = vec![];
763                                            match orion::hazardous::aead::xchacha20poly1305::open(&secret, &nonce, decoded.as_slice(), None, &mut output) {
764                                                Ok(_) => match String::from_utf8(output) {
765                                                    Ok(v) => v,
766                                                    Err(_) => return Err(JWTError::InvalidSignature)
767                                                },
768                                                Err(_) => return Err(JWTError::InvalidSignature)
769                                            }
770                                        }
771                                        Err(_) => return Err(JWTError::InvalidNonce)
772                                    }
773                                },
774                                Err(_) => return Err(JWTError::InvalidKey)
775                            }
776                        }
777                        Err(_) => return Err(JWTError::InvalidSignature)
778                    }
779                }
780                #[cfg(not(feature = "jwt_encrypt_decrypt"))]
781                {
782                    panic!("JWT Decryption not enabled - add feature jwt_encrypt_decrypt to product_os_security");
783                }
784            }
785        };
786
787        let token = match UntrustedToken::new(&token_string) {
788            Ok(ut) => ut,
789            Err(_) => return Err(JWTError::DecodeFailure)
790        };
791
792        let key = Hs256Key::new(jwt_secret);
793
794        let token_claims: Token<T> = match Hs256.validator(&key).validate(&token) {
795            Ok(claims) => claims,
796            Err(_) => return Err(JWTError::InvalidSignature)
797        };
798
799        Ok((token_string, token_claims))
800    }
801
802
803    #[cfg(feature = "jwt_auth_verify")]
804    pub fn jwt_verify_auth<'a, T: TokenClaims<'a, T> + serde::de::DeserializeOwned>(&self, verify_claims: &T, token: &str, jwt_secret: &[u8], nonce: &[u8], decryption_key: Option<&[u8]>) -> Result<(String, T), JWTError> {
805        match self.jwt_get_token_claims::<T>(token, jwt_secret, nonce, decryption_key) {
806            Ok((token_string, token_claims)) => {
807                let time_func = self.time_generator.get_function();
808                let time_options = TimeOptions::new(chrono::Duration::seconds(5), time_func);
809
810                let claims = token_claims.claims();
811
812                match claims.validate_expiration(&time_options) {
813                    Ok(_) => {}
814                    Err(_) => return Err(JWTError::InvalidClaims)
815                }
816
817                match claims.validate_maturity(&time_options) {
818                    Ok(_) => {}
819                    Err(_) => return Err(JWTError::InvalidClaims)
820                }
821
822                match claims.custom.verify(verify_claims) {
823                    true => Ok((token_string, claims.custom.to_owned())),
824                    false => return Err(JWTError::InvalidClaims)
825                }
826            }
827            Err(e) => Err(e)
828        }
829    }
830}
831
832
833#[cfg(feature = "public_private_sign_verify")]
834#[derive(Debug)]
835pub enum KeyError {
836    KeyRejected(String),
837}
838
839#[cfg(feature = "public_private_sign_verify")]
840pub fn generate_public_private_keys() -> Result<ring::pkcs8::Document, ring::error::Unspecified> {
841    let rng = ring::rand::SystemRandom::new();
842    ring::signature::Ed25519KeyPair::generate_pkcs8(&rng)
843}
844
845#[cfg(feature = "public_private_sign_verify")]
846pub fn get_public_key(key_pair: &ring::pkcs8::Document) -> Result<Vec<u8>, KeyError> {
847    match ring::signature::Ed25519KeyPair::from_pkcs8(key_pair.as_ref()) {
848        Ok(key_pair) => {
849            Ok(key_pair.public_key().as_ref().to_vec())
850        },
851        Err(_) => Err(KeyError::KeyRejected(String::from("No public key found")))
852    }
853}
854
855#[cfg(feature = "public_private_sign_verify")]
856pub fn private_key_sign(key_pair: &ring::pkcs8::Document, message: &[u8]) -> Result<ring::signature::Signature, KeyError> {
857    match ring::signature::Ed25519KeyPair::from_pkcs8(key_pair.as_ref()) {
858        Ok(key_pair) => Ok(key_pair.sign(message)),
859        Err(_) => Err(KeyError::KeyRejected(String::from("Failed to sign with key")))
860    }
861}
862
863#[cfg(feature = "public_private_sign_verify")]
864pub fn public_key_verify(public_key_bytes: &[u8], signature: &[u8], message: &[u8]) -> bool {
865    let peer_public_key = ring::signature::UnparsedPublicKey::new(&ring::signature::ED25519, public_key_bytes);
866    match peer_public_key.verify(message, signature) {
867        Ok(_) => true,
868        Err(_) => false
869    }
870}
871
872
873#[cfg(any(feature = "jwt_encrypt_decrypt", feature = "symmetric_encrypt_decrypt"))]
874pub fn create_nonce(#[cfg(not(feature = "jwt_encrypt_decrypt_std"))] gen: &mut Option<impl product_os_random::RngCore>) -> orion::hazardous::stream::xchacha20::Nonce {
875    #[cfg(feature = "jwt_encrypt_decrypt_std")] {
876        orion::hazardous::stream::xchacha20::Nonce::generate()
877    }
878    #[cfg(not(feature = "jwt_encrypt_decrypt_std"))] {
879        let bytes = product_os_random::RandomGenerator::get_random_bytes_one_time(24, gen);
880        orion::hazardous::aead::xchacha20poly1305::Nonce::from_slice(bytes.as_slice()).unwrap()
881    }
882}
883
884
885
886#[cfg(feature = "symmetric_encrypt_decrypt")]
887#[derive(Debug)]
888pub enum CryptoError {
889    Unknown(String),
890}
891
892#[cfg(feature = "symmetric_encrypt_decrypt")]
893pub fn symmetric_encrypt(key: &[u8], message: &[u8], #[cfg(not(feature = "jwt_encrypt_decrypt_std"))] gen: &mut Option<impl product_os_random::RngCore>) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {
894    match orion::hazardous::aead::xchacha20poly1305::SecretKey::from_slice(key) {
895        Ok(secret) => {
896            let nonce = create_nonce(#[cfg(not(feature = "jwt_encrypt_decrypt_std"))] gen);
897            let mut output = vec![];
898            match orion::hazardous::aead::xchacha20poly1305::seal(&secret, &nonce, message, None, &mut output) {
899                Ok(_) => Ok((output, nonce.as_ref().to_vec())),
900                Err(e) => Err(CryptoError::Unknown(e.to_string()))
901            }
902        },
903        Err(e) => panic!("Invalid key {}", e)
904    }
905}
906
907#[cfg(feature = "symmetric_encrypt_decrypt")]
908pub fn symmetric_decrypt(key: &[u8], nonce: &[u8], cipher: &[u8]) -> Result<Vec<u8>, CryptoError> {
909    match orion::hazardous::aead::xchacha20poly1305::SecretKey::from_slice(key) {
910        Ok(secret) => {
911            match orion::hazardous::aead::xchacha20poly1305::Nonce::from_slice(nonce) {
912                Ok(nonce) => {
913                    let mut output = vec![];
914                    match orion::hazardous::aead::xchacha20poly1305::open(&secret, &nonce,cipher, None, &mut output) {
915                        Ok(_) => Ok(output),
916                        Err(e) => Err(CryptoError::Unknown(e.to_string()))
917                    }
918                }
919                Err(e) => Err(CryptoError::Unknown(e.to_string()))
920            }
921        },
922        Err(e) => panic!("Invalid key {}", e)
923    }
924}
925
926
927
928#[cfg(feature = "public_private_encrypt_decrypt")]
929pub struct RSA {
930    bit_count: usize,
931    private_key: Vec<u8>,
932    public_key: Vec<u8>,
933    rng: product_os_random::OsRng
934}
935
936
937#[cfg(feature = "public_private_encrypt_decrypt")]
938impl RSA {
939    pub fn new() -> Self {
940        let bit_count = 2048;
941
942        let rng = product_os_random::OsRng::default();
943        let private_key = vec!();
944
945        let public_key = vec!();
946
947        Self {
948            bit_count,
949            private_key,
950            public_key,
951            rng,
952        }
953    }
954
955    fn generate_keys(&self) -> (Vec<u8>, Vec<u8>) {
956        let private_key = vec!();
957
958        let public_key = vec!();
959
960        (private_key, public_key)
961    }
962
963    pub fn generate_new_keys(&mut self) -> Vec<u8> {
964        todo!()
965    }
966
967    pub fn get_public_key(&self) -> Vec<u8> {
968        todo!()
969    }
970
971    pub fn import_public_key(&mut self, _public_key: &[u8]) {
972        todo!()
973    }
974
975    pub fn self_encrypt(&self, _data: &[u8]) -> Vec<u8> {
976        todo!()
977    }
978
979    pub fn encrypt(_public_key: &[u8], _data: &[u8]) -> Vec<u8> {
980        todo!()
981    }
982
983    pub fn decrypt(&self, _cipher: &[u8]) -> Vec<u8> {
984        todo!()
985    }
986}
987
988
989
990
991
992#[cfg(feature = "diffie_hellman_key_store")]
993pub struct DHKeyStore {
994    keys: BTreeMap<String, [u8; 32]>,
995    sessions: BTreeMap<String, x25519_dalek::EphemeralSecret>,
996}
997
998#[cfg(feature = "diffie_hellman_key_store")]
999impl DHKeyStore {
1000    pub fn new() -> Self {
1001        let keys = BTreeMap::new();
1002        let sessions = BTreeMap::new();
1003
1004        Self {
1005            keys,
1006            sessions
1007        }
1008    }
1009
1010
1011    pub fn create_session(&mut self, #[cfg(all(feature = "custom", not(feature = "thread_send")))] crypto_rng: impl product_os_random::RngCrypto + 'static) -> (String, [u8; 32]) {
1012        let identifier = uuid::Uuid::new_v4().to_string();
1013
1014        let secret =
1015        {
1016            #[cfg(feature = "thread_send")]
1017            {
1018                x25519_dalek::EphemeralSecret::random_from_rng(product_os_random::CryptoRNG::Std(product_os_random::StdRng::from_entropy()))
1019            }
1020            #[cfg(all(feature = "custom", not(feature = "thread_send")))]
1021            {
1022                x25519_dalek::EphemeralSecret::random_from_rng(product_os_random::CustomCryptoRng::new(crypto_rng))
1023            }
1024        };
1025
1026        let key = x25519_dalek::PublicKey::from(&secret);
1027        self.sessions.insert(identifier.to_owned(), secret);
1028        (identifier, key.to_bytes())
1029    }
1030
1031    pub fn generate_key(&mut self, session_identifier: &str, remote_public_key: &[u8], association: String, remote_session_identifier: Option<String>) {
1032        if self.sessions.contains_key(session_identifier) {
1033            match self.sessions.remove(session_identifier) {
1034                Some(session) => {
1035                    let remote_public_key_bytes: [u8; 32] = remote_public_key.try_into().unwrap_or_else(|_| [0; 32]);
1036
1037                    let remote_key = x25519_dalek::PublicKey::from(remote_public_key_bytes);
1038                    let key= session.diffie_hellman(&remote_key);
1039
1040                    let ikm = key.as_bytes();
1041                    let salt = None;
1042                    let info = match remote_session_identifier {
1043                        None => session_identifier.to_string().into_bytes(),
1044                        Some(rsi) => rsi.into_bytes()
1045                    };
1046
1047                    let mut output_key = [0u8; 32];
1048                    let key_derive = hkdf::Hkdf::<sha2::Sha512>::new(salt, ikm);
1049                    match key_derive.expand(info.as_slice(), &mut output_key) {
1050                        Ok(_) => self.keys.insert(association, output_key),
1051                        Err(e) => panic!("{}", e)
1052                    };
1053                },
1054                None => ()
1055            }
1056        }
1057    }
1058
1059    pub fn get_key(&self, association: &str) -> Option<&[u8]> {
1060        match self.keys.get(association) {
1061            Some(keys) => {
1062                Some(keys)
1063            },
1064            None => None
1065        }
1066    }
1067}
1068
1069
1070
1071
1072
1073#[cfg(feature = "diffie_hellman_client_server_key_store")]
1074#[derive(Debug)]
1075pub enum DHClientServerSessionKind {
1076    Client,
1077    Server
1078}
1079
1080#[cfg(feature = "diffie_hellman_client_server_key_store")]
1081pub struct DHClientServerKeyStore {
1082    keys: BTreeMap<String, orion::kex::SessionKeys>,
1083    client_sessions: BTreeMap<String, orion::kex::EphemeralClientSession>,
1084    server_sessions: BTreeMap<String, orion::kex::EphemeralServerSession>
1085}
1086
1087
1088#[cfg(feature = "diffie_hellman_client_server_key_store")]
1089impl DHClientServerKeyStore {
1090    pub fn new() -> Self {
1091        let keys = BTreeMap::new();
1092        let client_sessions = BTreeMap::new();
1093        let server_sessions = BTreeMap::new();
1094
1095        Self {
1096            keys,
1097            client_sessions,
1098            server_sessions
1099        }
1100    }
1101
1102    pub fn create_session(&mut self, kind: &DHClientServerSessionKind) -> (String, [u8; 32]) {
1103        let identifier = uuid::Uuid::new_v4().to_string();
1104
1105        match kind {
1106            DHClientServerSessionKind::Client => {
1107                let session = orion::kex::EphemeralClientSession::new().unwrap();
1108                let key = session.public_key().to_owned();
1109                self.client_sessions.insert(identifier.to_owned(), session);
1110                (identifier, key.to_bytes())
1111            }
1112            DHClientServerSessionKind::Server => {
1113                let session = orion::kex::EphemeralServerSession::new().unwrap();
1114                let key = session.public_key().to_owned();
1115                self.server_sessions.insert(identifier.to_owned(), session);
1116                (identifier, key.to_bytes())
1117            }
1118        }
1119    }
1120
1121    pub fn generate_keys(&mut self, session_identifier: &str, remote_public_key: &[u8], association: String) {
1122        let identifier = session_identifier;
1123
1124        if self.client_sessions.contains_key(identifier) {
1125            match self.client_sessions.remove(session_identifier) {
1126                Some(session) => {
1127                    let remote_key = orion::kex::PublicKey::from_slice(remote_public_key).unwrap();
1128                    match session.establish_with_server(&remote_key) {
1129                        Ok(keys) => {
1130                            self.keys.insert(association, keys);
1131                        },
1132                        Err(_) => ()
1133                    }
1134                },
1135                None => ()
1136            }
1137        }
1138        else if self.server_sessions.contains_key(identifier) {
1139            match self.server_sessions.remove(session_identifier) {
1140                Some(session) => {
1141                    let remote_key = orion::kex::PublicKey::from_slice(remote_public_key).unwrap();
1142                    match session.establish_with_client(&remote_key) {
1143                        Ok(keys) => {
1144                            self.keys.insert(association, keys);
1145                        },
1146                        Err(_) => ()
1147                    }
1148                },
1149                None => ()
1150            }
1151        }
1152    }
1153
1154    pub fn get_receiving_key(&self, association: &str) -> Option<&[u8]> {
1155        match self.keys.get(association) {
1156            Some(keys) => {
1157                Some(keys.receiving().unprotected_as_bytes())
1158            },
1159            None => None
1160        }
1161    }
1162
1163    pub fn get_sending_key(&self, association: &str) -> Option<&[u8]> {
1164        match self.keys.get(association) {
1165            Some(keys) => {
1166                Some(keys.transport().unprotected_as_bytes())
1167            },
1168            None => None
1169        }
1170    }
1171}
1172
1173
1174
1175
1176#[cfg(feature = "time_otp")]
1177struct TimeOTP {
1178    step: u64,
1179    digits: u32,
1180    time_generator: product_os_async_executor::moment::Moment
1181}
1182
1183#[cfg(feature = "time_otp")]
1184impl TimeOTP {
1185    pub fn new(step: Option<u16>, digits: Option<u8>, func: Option<fn() -> chrono::DateTime<chrono::Utc>>) -> Self {
1186        Self {
1187            step: match step {
1188                None => 30,
1189                Some(s) => u64::try_from(s).unwrap_or_else(|_| 0)
1190            },
1191            digits: match digits {
1192                None => 6,
1193                Some(d) => u32::try_from(d).unwrap_or_else(|_| 0)
1194            },
1195            time_generator: product_os_async_executor::moment::Moment::new(func)
1196        }
1197    }
1198
1199    pub fn generate_time_otp(&self, secret: &[u8]) -> String {
1200        let now = self.time_generator.now();
1201
1202        let seconds = now.timestamp().unsigned_abs();
1203        TimeOTP::totp_custom(self.step.to_owned(), self.digits.to_owned(), secret, seconds)
1204    }
1205
1206    pub fn verify_time_otp(&self, secret: &[u8], code: &str) -> bool {
1207        let now = self.time_generator.now();
1208
1209        let seconds = now.timestamp().unsigned_abs();
1210        let totp = TimeOTP::totp_custom(self.step.to_owned(), self.digits.to_owned(), secret, seconds);
1211        code == totp.as_str()
1212    }
1213
1214    pub const DEFAULT_STEP: u64 = 30;
1215
1216    pub const DEFAULT_DIGITS: u32 = 8;
1217
1218    pub fn totp(secret: &[u8], time: u64) -> String {
1219        TimeOTP::totp_custom(TimeOTP::DEFAULT_STEP, TimeOTP::DEFAULT_DIGITS, secret, time)
1220    }
1221
1222    pub fn totp_custom(step: u64, digits: u32, secret: &[u8], time: u64) -> String {
1223        // Hash the secret and the time together.
1224        let mac = blake2_mac(&(time / step).to_be_bytes(), secret);
1225        let hash = mac.as_slice();
1226        /*
1227        let mut mac = <Hmac<H> as Mac>::new_from_slice(secret).unwrap();
1228        <Hmac<H> as Update>::update(&mut mac, &to_bytes(time / step));
1229        let hash: &[u8] = &mac.finalize().into_bytes();
1230        */
1231
1232        // Magic from the RFC.
1233        let offset: usize = (hash.last().unwrap() & 0xf) as usize;
1234        let binary: u64 = (((hash[offset].to_owned() & 0x7f) as u64) << 24)
1235            | ((hash[offset.to_owned() + 1].to_owned() as u64) << 16)
1236            | ((hash[offset.to_owned() + 2].to_owned() as u64) << 8)
1237            | (hash[offset.to_owned() + 3].to_owned() as u64);
1238
1239        format!("{:01$}", binary % (10_u64.pow(digits)), digits as usize)
1240    }
1241
1242    fn num_as_bytes(n: u64) -> [u8; 8] {
1243        let mask = 0x00000000000000ff;
1244        let mut bytes: [u8; 8] = [0; 8];
1245        (0..8).for_each(|i| bytes[7 - i] = (mask & (n >> (i.to_owned() * 8))) as u8);
1246        bytes
1247    }
1248}
1249
1250
1251
1252#[cfg(feature = "password_hash")]
1253pub fn password_hash(password: &[u8], #[cfg(all(feature = "custom", not(feature = "thread_send")))] crypto_rng: impl product_os_random::RngCrypto + 'static) -> Result<Vec<u8>, argon2::password_hash::errors::Error> {
1254    let argon2 = argon2::Argon2::new(argon2::Algorithm::Argon2id, argon2::Version::V0x13, argon2::Params::new(15000, 2, 1, None).unwrap());
1255    let salt = {
1256        #[cfg(feature = "thread_send")]
1257        {
1258            argon2::password_hash::SaltString::generate(product_os_random::CryptoRNG::Std(product_os_random::StdRng::from_entropy()))
1259        }
1260        #[cfg(all(feature = "custom", not(feature = "thread_send")))]
1261        {
1262            argon2::password_hash::SaltString::generate(product_os_random::CustomCryptoRng::new(crypto_rng))
1263        }
1264    };
1265
1266    let password_hash = match argon2.hash_password(password, &salt) {
1267        Ok(res) => res,
1268        Err(e) => return Err(e)
1269    };
1270
1271    Ok(password_hash.to_string().as_bytes().to_vec())
1272}
1273
1274#[cfg(feature = "password_hash")]
1275pub fn password_verify(hash: &[u8], input: &[u8]) -> bool {
1276    let hash_str = String::from_utf8_lossy(hash);
1277    match argon2::PasswordHash::new(hash_str.as_ref()) {
1278        Ok(password_hash) => {
1279            match argon2::Argon2::default().verify_password( input, &password_hash) {
1280                Ok(_) => true,
1281                Err(_) => false
1282            }
1283        }
1284        Err(_) => false
1285    }
1286}
1287
1288
1289#[cfg(feature = "string_safe")]
1290pub fn encode_uri_component(value: &str) -> String {
1291    product_os_urlencoding::encode(value).to_string()
1292}
1293
1294#[cfg(feature = "string_safe")]
1295pub fn decode_uri_component(value: &str) -> String {
1296    product_os_urlencoding::decode(value).unwrap().to_string()
1297}