ncryptf/
signature.rs

1extern crate base64;
2use base64::{engine::general_purpose, Engine as _};
3use chrono::{offset::Utc, DateTime};
4
5use dryoc::generichash::GenericHash;
6use dryoc::classic::crypto_sign::crypto_sign_keypair;
7
8use crate::Keypair;
9
10/// Represents a signature and provides utility methods for validating signatures on a request.
11pub struct Signature;
12
13impl Signature {
14    /// Derives a signature from the given parameters
15    pub fn derive(
16        method: String,
17        uri: String,
18        salt: Vec<u8>,
19        datetime: DateTime<Utc>,
20        payload: String,
21        version: Option<i8>,
22    ) -> String {
23        let v = match version {
24            Some(v) => Some(v),
25            None => Some(crate::NCRYPTF_CURRENT_VERSION),
26        };
27
28        let hash = Self::get_signature_hash(payload, salt.clone(), v);
29        let b64s = general_purpose::STANDARD.encode(salt);
30        let ts = datetime.format("%a, %d %b %Y %H:%M:%S %z").to_string();
31
32        return format!("{}\n{}+{}\n{}\n{}", hash, method, uri, ts, b64s);
33    }
34
35    /// Generates a new random signature
36    pub fn new() -> Keypair {
37        let (pk, sk) = crypto_sign_keypair();
38
39        return Keypair {
40            secret_key: sk.to_vec(),
41            public_key: pk.to_vec(),
42        };
43    }
44
45    /// Generates a signature hash given a salt and data
46    pub fn get_signature_hash(data: String, salt: Vec<u8>, version: Option<i8>) -> String {
47        match version {
48            Some(2) => {
49                let salt_key: &[u8; 32] = &salt.try_into().unwrap();
50                let input = data.as_bytes();
51                
52                let hash: [u8; 64] = GenericHash::hash(input, Some(salt_key))
53                    .expect("Failed to compute generic hash");
54
55                return general_purpose::STANDARD.encode(&hash);
56            }
57            _ => {
58                return sha256::digest(data);
59            }
60        }
61    }
62}