1
//! Encryption and secret management.
2
//!
3
//! BonsaiDb's vault is the core of encryption and secret management. To offer
4
//! this security, BonsaiDb relies on external [`VaultKeyStorage`] to provide
5
//! the key needed to decrypt the master keys. After the master keys have been
6
//! decrypted, the vault is able to function without [`VaultKeyStorage`]. This
7
//! design ensures that if a copy of a database was stolen, the data that is
8
//! stored at-rest cannot be decrypted without gaining access to
9
//! [`VaultKeyStorage`].
10
//!
11
//! ## At-Rest Encryption
12
//!
13
//! At-rest encryption only ensures that if the database files are stolen that
14
//! an attacker cannot access the data without the encryption key. BonsaiDb
15
//! will regularly decrypt data to process it, and while the data is in-memory,
16
//! it is subject to the security of the machine running it. If using BonsaiDb
17
//! over a network, the network transport layer's encryption is what ensures
18
//! your data's safety.
19
//!
20
//! ## Security Best Practices
21
//!
22
//! ### Vault Key Storage
23
//!
24
//! In most situations, do not use [`LocalVaultKeyStorage`] in a production
25
//! environment. If you store the vault keys on the same disk as the database,
26
//! it's similar to hiding a key to your house under your doormat. It might stop
27
//! the casual person from entering your house, but give any attacker a few
28
//! minutes, and they'll find the key.
29
//!
30
//! Instead, you should use a storage location that provides authentication and
31
//! encryption. Our recommendation for production enviroments is to find an
32
//! Amazon S3-compatible storage service and use
33
//! [`S3VaultKeyStorage`](https://dev.bonsaidb.io/main/docs/bonsaidb_keystorage_s3/struct.S3VaultKeyStorage.html).
34
//! Eventually, other BonsaiDb servers will be able to operate as key storage
35
//! for each other.
36
//!
37
//! ## Encryption Algorithms Used
38
//!
39
//! BonsaiDb uses the [`hpke`](https://github.com/rozbb/rust-hpke) crate to
40
//! provide Hybrid Public Key Encryption (HPKE) when public key encryption is
41
//! being used. This is currently only utilized for encrypting the master keys
42
//! with the vault key. Our HPKE uses `P256+HKDF-SHA256+ChaCha20Poly1305`.
43
//! Long term, we plan to offer public key encryption APIs on top of these same
44
//! choices.
45
//!
46
//! For at-rest data encryption, the [`AEAD`
47
//! `XChaCha20Poly1305`](https://github.com/RustCrypto/AEADs) implementation is
48
//! used directly. This variant of `ChaCha20Poly1305` extends the nonce from 12
49
//! bytes to 24 bytes, which allows for random nonces to be used.
50

            
51
use std::borrow::Cow;
52
use std::collections::HashMap;
53
use std::fmt::{Debug, Display};
54
use std::fs::{self, File};
55
use std::io::{Read, Write};
56
use std::path::{Path, PathBuf};
57
use std::sync::Arc;
58

            
59
use bonsaidb_core::arc_bytes::serde::Bytes;
60
use bonsaidb_core::document::KeyId;
61
use bonsaidb_core::permissions::bonsai::{encryption_key_resource_name, EncryptionKeyAction};
62
use bonsaidb_core::permissions::Permissions;
63
use chacha20poly1305::aead::generic_array::GenericArray;
64
use chacha20poly1305::aead::{Aead, Payload};
65
use chacha20poly1305::{KeyInit, XChaCha20Poly1305};
66
use hpke::aead::{AeadTag, ChaCha20Poly1305};
67
use hpke::kdf::HkdfSha256;
68
use hpke::{self, Deserializable, Kem as KemTrait, OpModeS, Serializable};
69
use lockedbox::LockedBox;
70
use rand::{thread_rng, Rng};
71
use serde::{Deserialize, Serialize};
72
use zeroize::{Zeroize, Zeroizing};
73

            
74
use crate::hpke_util::{
75
    serde_encapped_key, serde_privkey, serde_pubkey, VaultP256EncappedKey, VaultP256Kem,
76
    VaultP256PrivateKey, VaultP256PublicKey,
77
};
78

            
79
/// A private encryption key.
80
25625
#[derive(Serialize, Deserialize)]
81
pub enum KeyPair {
82
    /// A P256 keypair.
83
    P256 {
84
        /// The private key.
85
        #[serde(with = "serde_privkey")]
86
        private: VaultP256PrivateKey,
87
        /// The public key.
88
        #[serde(with = "serde_pubkey")]
89
        public: VaultP256PublicKey,
90
    },
91
}
92

            
93
impl KeyPair {
94
    /// Serializes the private key into bytes.
95
72
    pub fn to_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
96
72
        Ok(Zeroizing::new(bincode::serialize(self)?))
97
72
    }
98

            
99
    /// Deserializes the private key.
100
144
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
101
144
        bincode::deserialize(bytes).map_err(Error::from)
102
144
    }
103
}
104

            
105
/// A public key corresponding to a [`KeyPair`].
106
36048
#[derive(Serialize, Deserialize)]
107
pub enum PublicKey {
108
    /// A P256 public key.
109
    #[serde(with = "serde_pubkey")]
110
    P256(VaultP256PublicKey),
111
}
112

            
113
impl PublicKey {
114
    /// Serializes the public key into bytes.
115
9012
    pub fn to_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
116
9012
        Ok(Zeroizing::new(bincode::serialize(self)?))
117
9012
    }
118

            
119
    /// Deserializes the public key.
120
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
121
        bincode::deserialize(bytes).map_err(Error::from)
122
    }
123
}
124

            
125
impl<'a> From<&'a KeyPair> for PublicKey {
126
5125
    fn from(key: &'a KeyPair) -> Self {
127
5125
        match key {
128
5125
            KeyPair::P256 { public, .. } => PublicKey::P256(public.clone()),
129
5125
        }
130
5125
    }
131
}
132

            
133
use crate::storage::StorageId;
134

            
135
pub(crate) struct Vault {
136
    _vault_public_key: PublicKey,
137
    master_keys: HashMap<u32, EncryptionKey>,
138
    current_master_key_id: u32,
139
    master_key_storage: Arc<dyn AnyVaultKeyStorage>,
140
}
141

            
142
impl Debug for Vault {
143
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144
        f.debug_struct("Vault")
145
            .field("master_keys", &self.master_keys)
146
            .field("current_master_key_id", &self.current_master_key_id)
147
            .field("master_key_storage", &self.master_key_storage)
148
            .finish_non_exhaustive()
149
    }
150
}
151

            
152
/// Errors relating to encryption and/or secret storage.
153
238196
#[derive(thiserror::Error, Debug)]
154
pub enum Error {
155
    /// An error occurred during encryption or decryption.
156
    #[error("error with encryption: {0}")]
157
    Encryption(String),
158
    /// An error occurred within the vault key storage.
159
    #[error("error from vault key storage: {0}")]
160
    VaultKeyStorage(String),
161
    /// An error occurred initializing the vault.
162
    #[error("error occurred while initializing: {0}")]
163
    Initializing(String),
164
    /// A previously initialized vault was found, but the vault key storage
165
    /// doesn't contain the key.
166
    #[error("vault key not found")]
167
    VaultKeyNotFound,
168
}
169

            
170
impl From<chacha20poly1305::aead::Error> for Error {
171
1
    fn from(err: chacha20poly1305::aead::Error) -> Self {
172
1
        Self::Encryption(err.to_string())
173
1
    }
174
}
175

            
176
impl From<hpke::HpkeError> for Error {
177
    fn from(err: hpke::HpkeError) -> Self {
178
        Self::Encryption(err.to_string())
179
    }
180
}
181

            
182
impl From<bincode::Error> for Error {
183
    fn from(err: bincode::Error) -> Self {
184
        Self::Initializing(err.to_string())
185
    }
186
}
187

            
188
impl Vault {
189
5197
    pub fn initialize(
190
5197
        server_id: StorageId,
191
5197
        server_directory: &Path,
192
5197
        master_key_storage: Arc<dyn AnyVaultKeyStorage>,
193
5197
    ) -> Result<Self, Error> {
194
5197
        let master_keys_path = server_directory.join("master-keys");
195
5197
        if master_keys_path.exists() {
196
691
            Self::unseal(&master_keys_path, server_id, master_key_storage)
197
        } else {
198
4506
            Self::initialize_vault_key_storage(&master_keys_path, server_id, master_key_storage)
199
        }
200
5197
    }
201

            
202
4506
    fn initialize_vault_key_storage(
203
4506
        master_keys_path: &Path,
204
4506
        server_id: StorageId,
205
4506
        master_key_storage: Arc<dyn AnyVaultKeyStorage>,
206
4506
    ) -> Result<Self, Error> {
207
4506
        let master_key = EncryptionKey::random();
208
4506
        let (private, public) = VaultP256Kem::gen_keypair(&mut thread_rng());
209
4506

            
210
4506
        master_key_storage
211
4506
            .set_vault_key_for(
212
4506
                server_id,
213
4506
                KeyPair::P256 {
214
4506
                    private,
215
4506
                    public: public.clone(),
216
4506
                },
217
4506
            )
218
4506
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))?;
219
4506
        let mut master_keys = HashMap::new();
220
4506
        master_keys.insert(0_u32, master_key);
221
        // Beacuse this is such a critical step, let's verify that we can
222
        // retrieve the key before we store the sealing key.
223
4506
        let retrieved = master_key_storage
224
4506
            .vault_key_for(server_id)
225
4506
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))?;
226
4506
        let expected_public_key_bytes = PublicKey::P256(public.clone()).to_bytes().unwrap();
227
4506
        let retrieved_key_matches = retrieved
228
4506
            .map(|r| PublicKey::from(&r).to_bytes().ok() == Some(expected_public_key_bytes))
229
4506
            .unwrap_or_default();
230
4506
        if retrieved_key_matches {
231
4506
            let mut serialized_master_keys = bincode::serialize(&master_keys)?;
232

            
233
4506
            let (encapsulated_key, aead_tag) = hpke::single_shot_seal_in_place_detached::<
234
4506
                ChaCha20Poly1305,
235
4506
                HkdfSha256,
236
4506
                VaultP256Kem,
237
4506
                _,
238
4506
            >(
239
4506
                &OpModeS::Base,
240
4506
                &public,
241
4506
                b"",
242
4506
                &mut serialized_master_keys,
243
4506
                b"",
244
4506
                &mut thread_rng(),
245
4506
            )?;
246
4506
            let mut tag = [0_u8; 16];
247
4506
            tag.copy_from_slice(&aead_tag.to_bytes());
248

            
249
4506
            let encrypted_master_keys_payload = bincode::serialize(&HpkePayload {
250
4506
                encryption: PublicKeyEncryption::DhP256HkdfSha256ChaCha20,
251
4506
                payload: Bytes::from(serialized_master_keys),
252
4506
                encapsulated_key,
253
4506
                tag,
254
4506
            })?;
255

            
256
4506
            File::create(master_keys_path)
257
4506
                .and_then(move |mut file| file.write_all(&encrypted_master_keys_payload))
258
4506
                .map_err(|err| Error::Initializing(format!("error saving vault key: {err:?}")))?;
259

            
260
4506
            Ok(Self {
261
4506
                _vault_public_key: PublicKey::P256(public),
262
4506
                master_keys,
263
4506
                current_master_key_id: 0,
264
4506
                master_key_storage,
265
4506
            })
266
        } else {
267
            Err(Error::VaultKeyStorage(String::from(
268
                "vault key storage failed to return the same stored key during initialization",
269
            )))
270
        }
271
4506
    }
272

            
273
691
    fn unseal(
274
691
        master_keys_path: &Path,
275
691
        server_id: StorageId,
276
691
        master_key_storage: Arc<dyn AnyVaultKeyStorage>,
277
691
    ) -> Result<Self, Error> {
278
        // The vault has been initilized previously. Do not overwrite this file voluntarily.
279
691
        let encrypted_master_keys = std::fs::read(master_keys_path)
280
691
            .map_err(|err| Error::Initializing(format!("error reading master keys: {err:?}")))?;
281
691
        let mut encrypted_master_keys =
282
691
            bincode::deserialize::<HpkePayload>(&encrypted_master_keys)?;
283
691
        let PublicKeyEncryption::DhP256HkdfSha256ChaCha20 = &encrypted_master_keys.encryption;
284
691
        if let Some(vault_key) = master_key_storage
285
691
            .vault_key_for(server_id)
286
691
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))?
287
        {
288
619
            let master_keys = match &vault_key {
289
619
                KeyPair::P256 { private, .. } => {
290
619
                    let mut decryption_context =
291
619
                        hpke::setup_receiver::<ChaCha20Poly1305, HkdfSha256, VaultP256Kem>(
292
619
                            &hpke::OpModeR::Base,
293
619
                            private,
294
619
                            &encrypted_master_keys.encapsulated_key,
295
619
                            b"",
296
619
                        )
297
619
                        .unwrap();
298
619

            
299
619
                    decryption_context
300
619
                        .open_in_place_detached(
301
619
                            &mut encrypted_master_keys.payload.0,
302
619
                            b"",
303
619
                            &AeadTag::<ChaCha20Poly1305>::from_bytes(&encrypted_master_keys.tag)
304
619
                                .unwrap(),
305
619
                        )
306
619
                        .unwrap();
307
619

            
308
619
                    bincode::deserialize::<HashMap<u32, EncryptionKey>>(
309
619
                        &encrypted_master_keys.payload,
310
619
                    )?
311
                }
312
            };
313

            
314
619
            let current_master_key_id = *master_keys.keys().max().unwrap();
315
619
            Ok(Self {
316
619
                _vault_public_key: PublicKey::from(&vault_key),
317
619
                master_keys,
318
619
                current_master_key_id,
319
619
                master_key_storage,
320
619
            })
321
        } else {
322
72
            Err(Error::VaultKeyNotFound)
323
        }
324
691
    }
325

            
326
87976
    fn current_master_key(&self) -> &EncryptionKey {
327
87976
        self.master_keys.get(&self.current_master_key_id).unwrap()
328
87976
    }
329

            
330
72318
    pub fn encrypt_payload(
331
72318
        &self,
332
72318
        key_id: &KeyId,
333
72318
        payload: &[u8],
334
72318
        permissions: Option<&Permissions>,
335
72318
    ) -> Result<Vec<u8>, crate::Error> {
336
72318
        if let Some(permissions) = permissions {
337
1
            permissions.check(
338
1
                encryption_key_resource_name(key_id),
339
1
                &EncryptionKeyAction::Encrypt,
340
1
            )?;
341
72317
        }
342

            
343
72317
        let (key, version) = match key_id {
344
72317
            KeyId::Master => (self.current_master_key(), self.current_master_key_id),
345
            KeyId::Id(_) => todo!(),
346
            KeyId::None => unreachable!(),
347
        };
348
72317
        let payload = key.encrypt_payload(key_id.clone(), version, payload);
349
72317
        Ok(payload.to_vec())
350
72318
    }
351

            
352
253856
    pub fn decrypt_payload(
353
253856
        &self,
354
253856
        payload: &[u8],
355
253856
        permissions: Option<&Permissions>,
356
253856
    ) -> Result<Vec<u8>, crate::Error> {
357
253856
        if let Ok(payload) = VaultPayload::from_slice(payload).map_err(|err| {
358
238196
            Error::Encryption(format!("error deserializing encrypted payload: {err:?}"))
359
253856
        }) {
360
15660
            self.decrypt(&payload, permissions)
361
        } else {
362
            // If we can't parse it as a VaultPayload, it might have been stored
363
            // decrypted originally.
364
238196
            Ok(payload.to_vec())
365
        }
366
253856
    }
367

            
368
15660
    fn decrypt(
369
15660
        &self,
370
15660
        payload: &VaultPayload<'_>,
371
15660
        permissions: Option<&Permissions>,
372
15660
    ) -> Result<Vec<u8>, crate::Error> {
373
15660
        if let Some(permissions) = permissions {
374
1
            permissions.check(
375
1
                encryption_key_resource_name(&payload.key_id),
376
1
                &EncryptionKeyAction::Decrypt,
377
1
            )?;
378
15659
        }
379

            
380
        // TODO handle key version
381
15659
        let key = match &payload.key_id {
382
15659
            KeyId::Master => self.current_master_key(),
383
            KeyId::Id(_) => todo!(),
384
            KeyId::None => unreachable!(),
385
        };
386
15659
        Ok(key.decrypt_payload(payload)?)
387
15660
    }
388
}
389

            
390
/// Stores encrypted keys for a vault.
391
pub trait VaultKeyStorage: Send + Sync + Debug + 'static {
392
    /// The error type that the functions return.
393
    type Error: Display;
394
    /// Store a key. Each server id should have unique storage.
395
    fn set_vault_key_for(&self, storage_id: StorageId, key: KeyPair) -> Result<(), Self::Error>;
396

            
397
    /// Retrieve all previously stored vault key for a given storage id.
398
    fn vault_key_for(&self, storage_id: StorageId) -> Result<Option<KeyPair>, Self::Error>;
399
}
400

            
401
struct EncryptionKey(LockedBox<[u8; 32]>);
402

            
403
impl EncryptionKey {
404
4508
    pub fn new(secret: [u8; 32]) -> Self {
405
4508
        Self(LockedBox::new(secret))
406
4508
    }
407

            
408
87976
    pub fn key(&self) -> &[u8] {
409
87976
        &*self.0
410
87976
    }
411

            
412
4508
    pub fn random() -> Self {
413
4508
        Self::new(thread_rng().gen())
414
4508
    }
415

            
416
72317
    pub fn encrypt_payload(
417
72317
        &self,
418
72317
        key_id: KeyId,
419
72317
        key_version: u32,
420
72317
        payload: &[u8],
421
72317
    ) -> VaultPayload<'static> {
422
72317
        let mut rng = thread_rng();
423
72317
        let nonce: [u8; 24] = rng.gen();
424
72317
        self.encrypt_payload_with_nonce(key_id, key_version, payload, &nonce)
425
72317
    }
426

            
427
72317
    pub fn encrypt_payload_with_nonce(
428
72317
        &self,
429
72317
        key_id: KeyId,
430
72317
        key_version: u32,
431
72317
        payload: &[u8],
432
72317
        nonce: &[u8],
433
72317
    ) -> VaultPayload<'static> {
434
72317
        let encrypted = XChaCha20Poly1305::new(GenericArray::from_slice(self.key()))
435
72317
            .encrypt(
436
72317
                GenericArray::from_slice(nonce),
437
72317
                Payload {
438
72317
                    msg: payload,
439
72317
                    aad: b"",
440
72317
                },
441
72317
            )
442
72317
            .unwrap();
443
72317
        VaultPayload {
444
72317
            key_id,
445
72317
            encryption: Encryption::XChaCha20Poly1305,
446
72317
            payload: Cow::Owned(encrypted),
447
72317
            nonce: Cow::Owned(nonce.to_vec()),
448
72317
            key_version,
449
72317
        }
450
72317
    }
451

            
452
15659
    pub fn decrypt_payload(&self, payload: &VaultPayload<'_>) -> Result<Vec<u8>, Error> {
453
        // This is a no-op, but it will cause a compiler error if we introduce additional encryption methods
454
15659
        let encrypted = match payload.encryption {
455
15659
            Encryption::XChaCha20Poly1305 => {
456
15659
                XChaCha20Poly1305::new(GenericArray::from_slice(self.key())).decrypt(
457
15659
                    GenericArray::from_slice(&payload.nonce),
458
15659
                    Payload {
459
15659
                        msg: &payload.payload,
460
15659
                        aad: b"",
461
15659
                    },
462
15659
                )?
463
            }
464
        };
465
15658
        Ok(encrypted)
466
15659
    }
467
}
468

            
469
impl Drop for EncryptionKey {
470
4983
    fn drop(&mut self) {
471
4983
        self.0.zeroize();
472
4983
    }
473
}
474

            
475
impl Debug for EncryptionKey {
476
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
477
        f.debug_struct("PrivateKey").finish_non_exhaustive()
478
    }
479
}
480

            
481
impl Serialize for EncryptionKey {
482
9012
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
483
9012
    where
484
9012
        S: serde::Serializer,
485
9012
    {
486
9012
        self.0.serialize(serializer)
487
9012
    }
488
}
489

            
490
impl<'de> Deserialize<'de> for EncryptionKey {
491
619
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
492
619
    where
493
619
        D: serde::Deserializer<'de>,
494
619
    {
495
619
        Ok(Self(LockedBox::new(<[u8; 32]>::deserialize(deserializer)?)))
496
619
    }
497
}
498

            
499
/// A [`VaultKeyStorage`] trait that wraps the Error type before returning. This
500
/// type is used to allow the Vault to operate without any generic parameters.
501
/// This trait is auto-implemented for all [`VaultKeyStorage`] implementors.
502
pub trait AnyVaultKeyStorage: Send + Sync + Debug + 'static {
503
    /// Retrieve all previously stored master keys for a given storage id.
504
    fn vault_key_for(&self, storage_id: StorageId) -> Result<Option<KeyPair>, Error>;
505

            
506
    /// Store a key. Each server id should have unique storage. The keys are
507
    /// uniquely encrypted per storage id and can only be decrypted by keys
508
    /// contained in the storage itself.
509
    fn set_vault_key_for(&self, storage_id: StorageId, key: KeyPair) -> Result<(), Error>;
510
}
511

            
512
impl<T> AnyVaultKeyStorage for T
513
where
514
    T: VaultKeyStorage + 'static,
515
{
516
4987
    fn vault_key_for(&self, server_id: StorageId) -> Result<Option<KeyPair>, Error> {
517
4987
        VaultKeyStorage::vault_key_for(self, server_id)
518
4987
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))
519
4987
    }
520

            
521
4436
    fn set_vault_key_for(&self, server_id: StorageId, key: KeyPair) -> Result<(), Error> {
522
4436
        VaultKeyStorage::set_vault_key_for(self, server_id, key)
523
4436
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))
524
4436
    }
525
}
526

            
527
/// Stores vault key locally on disk. This is in general considered insecure,
528
/// and shouldn't be used without careful consideration.
529
///
530
/// The primary goal of encryption within BonsaiDb is to offer limited
531
/// encryption at-rest. Within these goals, the primary attack vector being
532
/// protected against is an attacker being able to copy the data off of the
533
/// disks, either by physically gaining access to the drives or having
534
/// filesystem access. By storing the vault key on the same physical media, the
535
/// encryption should be considered insecure because if you can gain access to
536
/// the data, you have access to the keys as well.
537
///
538
/// For production environments, it is much more secure to store the vault key
539
/// in a separate location. We recommand any S3-compatible backend.
540
#[derive(Debug, Clone)]
541
pub struct LocalVaultKeyStorage {
542
    directory: PathBuf,
543
}
544

            
545
impl LocalVaultKeyStorage {
546
    /// Creates a new file-based vaultr key storage, storing files within
547
    /// `path`. The path provided shouod be a directory. If it doesn't exist, it
548
    /// will be created.
549
4981
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Self, std::io::Error> {
550
4981
        let directory = path.as_ref().to_owned();
551
4981
        if !directory.exists() {
552
4433
            fs::create_dir_all(&directory)?;
553
548
        }
554
4981
        Ok(Self { directory })
555
4981
    }
556
}
557

            
558
/// Errors from local vault key storage.
559
#[derive(thiserror::Error, Debug)]
560
pub enum LocalVaultKeyStorageError {
561
    /// An error interacting with the filesystem.
562
    #[error("io error: {0}")]
563
    Io(#[from] std::io::Error),
564

            
565
    /// An error serializing or deserializing the keys.
566
    #[error("serialization error: {0}")]
567
    Serialization(#[from] bincode::Error),
568

            
569
    /// The file was not the correct size.
570
    #[error("file was not the correct size")]
571
    InvalidFile,
572
}
573

            
574
impl VaultKeyStorage for LocalVaultKeyStorage {
575
    type Error = LocalVaultKeyStorageError;
576

            
577
4981
    fn vault_key_for(&self, server_id: StorageId) -> Result<Option<KeyPair>, Self::Error> {
578
4981
        let server_file = self.directory.join(server_id.to_string());
579
4981
        if !server_file.exists() {
580
            return Ok(None);
581
4981
        }
582
4981
        let mut contents = File::open(server_file).and_then(|mut f| {
583
4981
            let mut bytes = Vec::new();
584
4981
            f.read_to_end(&mut bytes).map(|_| bytes)
585
4981
        })?;
586

            
587
4981
        let key = bincode::deserialize::<KeyPair>(&contents)?;
588
4981
        contents.zeroize();
589
4981

            
590
4981
        Ok(Some(key))
591
4981
    }
592

            
593
4434
    fn set_vault_key_for(&self, server_id: StorageId, key: KeyPair) -> Result<(), Self::Error> {
594
4434
        let server_file = self.directory.join(server_id.to_string());
595
4434
        let bytes = bincode::serialize(&key)?;
596
4434
        File::create(server_file).and_then(|mut file| file.write_all(&bytes))?;
597
4434
        Ok(())
598
4434
    }
599
}
600

            
601
492052
#[derive(Serialize, Deserialize)]
602
struct VaultPayload<'a> {
603
    // TODO make key_id be the additional data
604
    key_id: KeyId,
605
    key_version: u32,
606
    encryption: Encryption,
607
    payload: Cow<'a, [u8]>,
608
    nonce: Cow<'a, [u8]>,
609
}
610

            
611
impl<'a> VaultPayload<'a> {
612
253856
    fn from_slice(bytes: &'a [u8]) -> Result<Self, Error> {
613
253856
        bincode::deserialize(bytes).map_err(|err| {
614
238196
            Error::Encryption(format!("error deserializing encrypted payload: {err:?}"))
615
253856
        })
616
253856
    }
617

            
618
72317
    fn to_vec(&self) -> Vec<u8> {
619
72317
        bincode::serialize(self).unwrap()
620
72317
    }
621
}
622

            
623
9012
#[derive(Serialize, Deserialize)]
624
struct HpkePayload {
625
    encryption: PublicKeyEncryption,
626
    payload: Bytes,
627
    tag: [u8; 16],
628
    #[serde(with = "serde_encapped_key")]
629
    encapsulated_key: VaultP256EncappedKey,
630
}
631

            
632
643375
#[derive(Serialize, Deserialize)]
633
enum Encryption {
634
    XChaCha20Poly1305,
635
}
636

            
637
9012
#[derive(Serialize, Deserialize)]
638
enum PublicKeyEncryption {
639
    DhP256HkdfSha256ChaCha20,
640
}
641

            
642
#[cfg(test)]
643
mod tests {
644
    use super::*;
645

            
646
    #[derive(Debug)]
647
    struct NullKeyStorage;
648
    impl VaultKeyStorage for NullKeyStorage {
649
        type Error = anyhow::Error;
650

            
651
        fn set_vault_key_for(
652
            &self,
653
            _storage_id: StorageId,
654
            _key: KeyPair,
655
        ) -> Result<(), Self::Error> {
656
            unreachable!()
657
        }
658

            
659
        fn vault_key_for(&self, _storage_id: StorageId) -> Result<Option<KeyPair>, Self::Error> {
660
            unreachable!()
661
        }
662
    }
663

            
664
2
    fn random_null_vault() -> Vault {
665
2
        let mut master_keys = HashMap::new();
666
2
        master_keys.insert(0, EncryptionKey::random());
667
2

            
668
2
        let (_, public_key) = <VaultP256Kem as KemTrait>::gen_keypair(&mut thread_rng());
669
2

            
670
2
        Vault {
671
2
            _vault_public_key: PublicKey::P256(public_key),
672
2
            master_keys,
673
2
            current_master_key_id: 0,
674
2
            master_key_storage: Arc::new(NullKeyStorage),
675
2
        }
676
2
    }
677

            
678
1
    #[test]
679
1
    fn vault_encryption_test() {
680
1
        let vault = random_null_vault();
681
1
        let encrypted = vault
682
1
            .encrypt_payload(&KeyId::Master, b"hello", None)
683
1
            .unwrap();
684
1
        let decrypted = vault.decrypt_payload(&encrypted, None).unwrap();
685
1

            
686
1
        assert_eq!(decrypted, b"hello");
687
1
    }
688

            
689
1
    #[test]
690
1
    fn vault_permissions_test() {
691
1
        let vault = random_null_vault();
692
1
        assert!(matches!(
693
1
            vault.encrypt_payload(&KeyId::Master, b"hello", Some(&Permissions::default()),),
694
            Err(crate::Error::Core(bonsaidb_core::Error::PermissionDenied(
695
                _
696
            )))
697
        ));
698
1
        let encrypted = vault
699
1
            .encrypt_payload(&KeyId::Master, b"hello", None)
700
1
            .unwrap();
701
1
        assert!(matches!(
702
1
            vault.decrypt_payload(&encrypted, Some(&Permissions::default())),
703
            Err(crate::Error::Core(bonsaidb_core::Error::PermissionDenied(
704
                _
705
            )))
706
        ));
707
1
    }
708
}