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([]); } match algorithm {
224 Some(alg) => {
225 match alg {
226 "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; } 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 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 let mac = blake2_mac(&(time / step).to_be_bytes(), secret);
1225 let hash = mac.as_slice();
1226 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}