ffsend_api/crypto/
key_set.rs

1use url::Url;
2
3use super::hkdf::{derive_auth_key, derive_file_key, derive_meta_key};
4use super::{b64, rand_bytes};
5use crate::api::url::UrlBuilder;
6use crate::file::remote_file::RemoteFile;
7
8/// The length of an input vector.
9const KEY_NONCE_LEN: usize = 12;
10
11pub struct KeySet {
12    /// A secret.
13    secret: Vec<u8>,
14
15    /// Nonce.
16    nonce: [u8; KEY_NONCE_LEN],
17
18    /// A derived file encryption key.
19    file_key: Option<Vec<u8>>,
20
21    /// A derived authentication key.
22    auth_key: Option<Vec<u8>>,
23
24    /// A derived metadata key.
25    meta_key: Option<Vec<u8>>,
26}
27
28impl KeySet {
29    /// Construct a new key, with the given `secret` and `nonce`.
30    pub fn new(secret: Vec<u8>, nonce: [u8; 12]) -> Self {
31        Self {
32            secret,
33            nonce,
34            file_key: None,
35            auth_key: None,
36            meta_key: None,
37        }
38    }
39
40    /// Create a key set from the given file ID and secret.
41    /// This method may be used to create a key set based on a share URL.
42    // TODO: add a parameter for the password and URL
43    // TODO: return a result?
44    // TODO: supply a client instance as parameter
45    pub fn from(file: &RemoteFile, password: Option<&String>) -> Self {
46        // Create a new key set instance
47        let mut set = Self::new(file.secret_raw().clone(), [0; 12]);
48
49        // Derive all keys
50        set.derive();
51
52        // Derive a pasworded key
53        if let Some(password) = password {
54            set.derive_auth_password(password, &UrlBuilder::download(&file, true));
55        }
56
57        set
58    }
59
60    /// Generate a secure new key.
61    ///
62    /// If `derive` is `true`, file, authentication and metadata keys will be
63    /// derived from the generated secret.
64    pub fn generate(derive: bool) -> Self {
65        // Allocate two keys
66        let mut secret = vec![0u8; 16];
67        let mut iv = [0u8; 12];
68
69        // Generate the secrets
70        rand_bytes(&mut secret).expect("failed to generate crypto secure random secret");
71        rand_bytes(&mut iv).expect("failed to generate crypto secure random input vector");
72
73        // Create the key
74        let mut key = Self::new(secret, iv);
75
76        // Derive
77        if derive {
78            key.derive();
79        }
80
81        key
82    }
83
84    /// Derive a file, authentication and metadata key.
85    // TODO: add support for deriving with a password and URL
86    pub fn derive(&mut self) {
87        self.file_key = Some(derive_file_key(&self.secret));
88        self.auth_key = Some(derive_auth_key(&self.secret, None, None));
89        self.meta_key = Some(derive_meta_key(&self.secret));
90    }
91
92    /// Derive an authentication key, with the given password and file URL.
93    /// This method does not derive a (new) file and metadata key.
94    pub fn derive_auth_password(&mut self, pass: &str, url: &Url) {
95        self.auth_key = Some(derive_auth_key(&self.secret, Some(pass), Some(url)));
96    }
97
98    /// Get the secret key.
99    pub fn secret(&self) -> &[u8] {
100        &self.secret
101    }
102
103    /// Get the secret key as URL-safe base64 encoded string.
104    pub fn secret_encoded(&self) -> String {
105        b64::encode(self.secret())
106    }
107
108    /// Get the nonce.
109    pub fn nonce(&self) -> &[u8] {
110        &self.nonce
111    }
112
113    /// Set the input vector.
114    pub fn set_nonce(&mut self, nonce: [u8; KEY_NONCE_LEN]) {
115        self.nonce = nonce;
116    }
117
118    /// Get the file encryption key, if derived.
119    pub fn file_key(&self) -> Option<&Vec<u8>> {
120        self.file_key.as_ref()
121    }
122
123    /// Get the authentication encryption key, if derived.
124    pub fn auth_key(&self) -> Option<&Vec<u8>> {
125        self.auth_key.as_ref()
126    }
127
128    /// Get the authentication encryption key, if derived,
129    /// as URL-safe base64 encoded string.
130    pub fn auth_key_encoded(&self) -> Option<String> {
131        self.auth_key().map(|key| b64::encode(key))
132    }
133
134    /// Get the metadata encryption key, if derived.
135    pub fn meta_key(&self) -> Option<&Vec<u8>> {
136        self.meta_key.as_ref()
137    }
138}