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::{
52
    borrow::Cow,
53
    collections::HashMap,
54
    fmt::{Debug, Display},
55
    path::{Path, PathBuf},
56
    sync::Arc,
57
};
58

            
59
use async_trait::async_trait;
60
use bonsaidb_core::{
61
    arc_bytes::serde::Bytes,
62
    document::KeyId,
63
    permissions::{
64
        bonsai::{encryption_key_resource_name, EncryptionKeyAction},
65
        Permissions,
66
    },
67
};
68
use chacha20poly1305::{
69
    aead::{generic_array::GenericArray, Aead, NewAead, Payload},
70
    XChaCha20Poly1305,
71
};
72
use futures::TryFutureExt;
73
use hpke::{
74
    self,
75
    aead::{AeadTag, ChaCha20Poly1305},
76
    kdf::HkdfSha256,
77
    kem::DhP256HkdfSha256,
78
    Deserializable, Kem, OpModeS, Serializable,
79
};
80
use rand::{thread_rng, Rng};
81
use serde::{Deserialize, Serialize};
82
use tokio::{
83
    fs::{self, File},
84
    io::{AsyncReadExt, AsyncWriteExt},
85
};
86
use zeroize::{Zeroize, Zeroizing};
87

            
88
/// A private encryption key.
89
8097
#[derive(Serialize, Deserialize)]
90
pub enum KeyPair {
91
    /// A P256 keypair.
92
    P256 {
93
        /// The private key.
94
        private: <DhP256HkdfSha256 as Kem>::PrivateKey,
95
        /// The public key.
96
        public: <DhP256HkdfSha256 as Kem>::PublicKey,
97
    },
98
}
99

            
100
impl KeyPair {
101
    /// Serializes the private key into bytes.
102
26
    pub fn to_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
103
26
        Ok(Zeroizing::new(bincode::serialize(self)?))
104
26
    }
105

            
106
    /// Deserializes the private key.
107
52
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
108
52
        bincode::deserialize(bytes).map_err(Error::from)
109
52
    }
110
}
111

            
112
/// A public key corresponding to a [`KeyPair`].
113
9524
#[derive(Serialize, Deserialize)]
114
pub enum PublicKey {
115
    /// A P256 public key.
116
    P256(<DhP256HkdfSha256 as Kem>::PublicKey),
117
}
118

            
119
impl PublicKey {
120
    /// Serializes the public key into bytes.
121
4762
    pub fn to_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
122
4762
        Ok(Zeroizing::new(bincode::serialize(self)?))
123
4762
    }
124

            
125
    /// Deserializes the public key.
126
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
127
        bincode::deserialize(bytes).map_err(Error::from)
128
    }
129
}
130

            
131
impl<'a> From<&'a KeyPair> for PublicKey {
132
2699
    fn from(key: &'a KeyPair) -> Self {
133
2699
        match key {
134
2699
            KeyPair::P256 { public, .. } => PublicKey::P256(public.clone()),
135
2699
        }
136
2699
    }
137
}
138

            
139
use crate::storage::StorageId;
140

            
141
pub(crate) struct Vault {
142
    _vault_public_key: PublicKey,
143
    master_keys: HashMap<u32, EncryptionKey>,
144
    current_master_key_id: u32,
145
    master_key_storage: Arc<dyn AnyVaultKeyStorage>,
146
}
147

            
148
impl Debug for Vault {
149
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150
        f.debug_struct("Vault")
151
            .field("master_keys", &self.master_keys)
152
            .field("current_master_key_id", &self.current_master_key_id)
153
            .field("master_key_storage", &self.master_key_storage)
154
            .finish_non_exhaustive()
155
    }
156
}
157

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

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

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

            
188
impl From<bincode::Error> for Error {
189
    fn from(err: bincode::Error) -> Self {
190
        Self::Initializing(err.to_string())
191
    }
192
}
193

            
194
impl Vault {
195
2725
    pub async fn initialize(
196
2725
        server_id: StorageId,
197
2725
        server_directory: &Path,
198
2725
        master_key_storage: Arc<dyn AnyVaultKeyStorage>,
199
2725
    ) -> Result<Self, Error> {
200
175
        let master_keys_path = server_directory.join("master-keys");
201
175
        if master_keys_path.exists() {
202
137
            Self::unseal(&master_keys_path, server_id, master_key_storage).await
203
        } else {
204
1183
            Self::initialize_vault_key_storage(&master_keys_path, server_id, master_key_storage)
205
1183
                .await
206
        }
207
175
    }
208

            
209
2381
    async fn initialize_vault_key_storage(
210
2381
        master_keys_path: &Path,
211
2381
        server_id: StorageId,
212
2381
        master_key_storage: Arc<dyn AnyVaultKeyStorage>,
213
2381
    ) -> Result<Self, Error> {
214
156
        let master_key = EncryptionKey::random();
215
156
        let (private, public) = DhP256HkdfSha256::gen_keypair(&mut thread_rng());
216
156

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

            
242
156
            let (encapsulated_key, aead_tag) = hpke::single_shot_seal_in_place_detached::<
243
156
                ChaCha20Poly1305,
244
156
                HkdfSha256,
245
156
                DhP256HkdfSha256,
246
156
                _,
247
156
            >(
248
156
                &OpModeS::Base,
249
156
                &public,
250
156
                b"",
251
156
                &mut serialized_master_keys,
252
156
                b"",
253
156
                &mut thread_rng(),
254
156
            )?;
255
156
            let mut tag = [0_u8; 16];
256
156
            tag.copy_from_slice(&aead_tag.to_bytes());
257

            
258
156
            let encrypted_master_keys_payload = bincode::serialize(&HpkePayload {
259
156
                encryption: PublicKeyEncryption::DhP256HkdfSha256ChaCha20,
260
156
                payload: Bytes::from(serialized_master_keys),
261
156
                encapsulated_key,
262
156
                tag,
263
156
            })?;
264

            
265
156
            File::create(master_keys_path)
266
156
                .and_then(|mut file| async move {
267
156
                    file.write_all(&encrypted_master_keys_payload).await?;
268
156
                    file.shutdown().await
269
200
                })
270
194
                .await
271
156
                .map_err(|err| Error::Initializing(format!("error saving vault key: {:?}", err)))?;
272

            
273
156
            Ok(Self {
274
156
                _vault_public_key: PublicKey::P256(public),
275
156
                master_keys,
276
156
                current_master_key_id: 0,
277
156
                master_key_storage,
278
156
            })
279
        } else {
280
            Err(Error::VaultKeyStorage(String::from(
281
                "vault key storage failed to return the same stored key during initialization",
282
            )))
283
        }
284
156
    }
285

            
286
344
    async fn unseal(
287
344
        master_keys_path: &Path,
288
344
        server_id: StorageId,
289
344
        master_key_storage: Arc<dyn AnyVaultKeyStorage>,
290
344
    ) -> Result<Self, Error> {
291
        // The vault has been initilized previously. Do not overwrite this file voluntarily.
292
19
        let encrypted_master_keys = tokio::fs::read(master_keys_path)
293
18
            .await
294
19
            .map_err(|err| Error::Initializing(format!("error reading master keys: {:?}", err)))?;
295
19
        let mut encrypted_master_keys =
296
19
            bincode::deserialize::<HpkePayload>(&encrypted_master_keys)?;
297
19
        let PublicKeyEncryption::DhP256HkdfSha256ChaCha20 = &encrypted_master_keys.encryption;
298
19
        if let Some(vault_key) = master_key_storage
299
119
            .vault_key_for(server_id)
300
119
            .await
301
19
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))?
302
        {
303
18
            let master_keys = match &vault_key {
304
18
                KeyPair::P256 { private, .. } => {
305
18
                    let mut decryption_context =
306
18
                        hpke::setup_receiver::<ChaCha20Poly1305, HkdfSha256, DhP256HkdfSha256>(
307
18
                            &hpke::OpModeR::Base,
308
18
                            private,
309
18
                            &encrypted_master_keys.encapsulated_key,
310
18
                            b"",
311
18
                        )
312
18
                        .unwrap();
313
18

            
314
18
                    decryption_context
315
18
                        .open_in_place_detached(
316
18
                            &mut encrypted_master_keys.payload.0,
317
18
                            b"",
318
18
                            &AeadTag::<ChaCha20Poly1305>::from_bytes(&encrypted_master_keys.tag)
319
18
                                .unwrap(),
320
18
                        )
321
18
                        .unwrap();
322
18

            
323
18
                    bincode::deserialize::<HashMap<u32, EncryptionKey>>(
324
18
                        &encrypted_master_keys.payload,
325
18
                    )?
326
                }
327
            };
328

            
329
18
            let current_master_key_id = *master_keys.keys().max().unwrap();
330
18
            Ok(Self {
331
18
                _vault_public_key: PublicKey::from(&vault_key),
332
18
                master_keys,
333
18
                current_master_key_id,
334
18
                master_key_storage,
335
18
            })
336
        } else {
337
1
            Err(Error::VaultKeyNotFound)
338
        }
339
19
    }
340

            
341
49552
    fn current_master_key(&self) -> &EncryptionKey {
342
49552
        self.master_keys.get(&self.current_master_key_id).unwrap()
343
49552
    }
344

            
345
41226
    pub fn encrypt_payload(
346
41226
        &self,
347
41226
        key_id: &KeyId,
348
41226
        payload: &[u8],
349
41226
        permissions: Option<&Permissions>,
350
41226
    ) -> Result<Vec<u8>, crate::Error> {
351
41226
        if let Some(permissions) = permissions {
352
1
            permissions.check(
353
1
                encryption_key_resource_name(key_id),
354
1
                &EncryptionKeyAction::Encrypt,
355
1
            )?;
356
41225
        }
357

            
358
41225
        let (key, version) = match key_id {
359
41225
            KeyId::Master => (self.current_master_key(), self.current_master_key_id),
360
            KeyId::Id(_) => todo!(),
361
            KeyId::None => unreachable!(),
362
        };
363
41225
        let payload = key.encrypt_payload(key_id.clone(), version, payload);
364
41225
        Ok(payload.to_vec())
365
41226
    }
366

            
367
    pub fn decrypt_payload(
368
        &self,
369
        payload: &[u8],
370
        permissions: Option<&Permissions>,
371
    ) -> Result<Vec<u8>, crate::Error> {
372
155351
        if let Ok(payload) = VaultPayload::from_slice(payload).map_err(|err| {
373
147023
            Error::Encryption(format!("error deserializing encrypted payload: {:?}", err))
374
155351
        }) {
375
8328
            self.decrypt(&payload, permissions)
376
        } else {
377
            // If we can't parse it as a VaultPayload, it might have been stored
378
            // decrypted originally.
379
147023
            Ok(payload.to_vec())
380
        }
381
155351
    }
382

            
383
8328
    fn decrypt(
384
8328
        &self,
385
8328
        payload: &VaultPayload<'_>,
386
8328
        permissions: Option<&Permissions>,
387
8328
    ) -> Result<Vec<u8>, crate::Error> {
388
8328
        if let Some(permissions) = permissions {
389
1
            permissions.check(
390
1
                encryption_key_resource_name(&payload.key_id),
391
1
                &EncryptionKeyAction::Decrypt,
392
1
            )?;
393
8327
        }
394

            
395
        // TODO handle key version
396
8327
        let key = match &payload.key_id {
397
8327
            KeyId::Master => self.current_master_key(),
398
            KeyId::Id(_) => todo!(),
399
            KeyId::None => unreachable!(),
400
        };
401
8327
        Ok(key.decrypt_payload(payload)?)
402
8328
    }
403
}
404

            
405
/// Stores encrypted keys for a vault.
406
#[async_trait]
407
pub trait VaultKeyStorage: Send + Sync + Debug + 'static {
408
    /// The error type that the functions return.
409
    type Error: Display;
410
    /// Store a key. Each server id should have unique storage.
411
    async fn set_vault_key_for(
412
        &self,
413
        storage_id: StorageId,
414
        key: KeyPair,
415
    ) -> Result<(), Self::Error>;
416

            
417
    /// Retrieve all previously stored vault key for a given storage id.
418
    async fn vault_key_for(&self, storage_id: StorageId) -> Result<Option<KeyPair>, Self::Error>;
419
}
420

            
421
313
#[derive(Serialize, Deserialize)]
422
struct EncryptionKey([u8; 32], #[serde(skip)] Option<region::LockGuard>);
423

            
424
impl EncryptionKey {
425
2383
    pub fn new(secret: [u8; 32]) -> Self {
426
2383
        let mut new_key = Self(secret, None);
427
2383
        new_key.lock_memory();
428
2383
        new_key
429
2383
    }
430

            
431
4766
    pub fn key(&self) -> &[u8] {
432
4766
        &self.0
433
4766
    }
434

            
435
2383
    pub fn lock_memory(&mut self) {
436
2383
        if self.1.is_none() {
437
2383
            match region::lock(self.key().as_ptr(), self.key().len()) {
438
2383
                Ok(guard) => self.1 = Some(guard),
439
                Err(err) => log::error!("Security Warning: Unable to lock memory {:?}", err),
440
            }
441
        }
442
2383
    }
443

            
444
2383
    pub fn random() -> Self {
445
2383
        Self::new(thread_rng().gen())
446
2383
    }
447

            
448
41225
    pub fn encrypt_payload(
449
41225
        &self,
450
41225
        key_id: KeyId,
451
41225
        key_version: u32,
452
41225
        payload: &[u8],
453
41225
    ) -> VaultPayload<'static> {
454
41225
        let mut rng = thread_rng();
455
41225
        let nonce: [u8; 24] = rng.gen();
456
41225
        self.encrypt_payload_with_nonce(key_id, key_version, payload, &nonce)
457
41225
    }
458

            
459
41225
    pub fn encrypt_payload_with_nonce(
460
41225
        &self,
461
41225
        key_id: KeyId,
462
41225
        key_version: u32,
463
41225
        payload: &[u8],
464
41225
        nonce: &[u8],
465
41225
    ) -> VaultPayload<'static> {
466
41225
        let encrypted = XChaCha20Poly1305::new(GenericArray::from_slice(&self.0))
467
41225
            .encrypt(
468
41225
                GenericArray::from_slice(nonce),
469
41225
                Payload {
470
41225
                    msg: payload,
471
41225
                    aad: b"",
472
41225
                },
473
41225
            )
474
41225
            .unwrap();
475
41225
        VaultPayload {
476
41225
            key_id,
477
41225
            encryption: Encryption::XChaCha20Poly1305,
478
41225
            payload: Cow::Owned(encrypted),
479
41225
            nonce: Cow::Owned(nonce.to_vec()),
480
41225
            key_version,
481
41225
        }
482
41225
    }
483

            
484
8327
    pub fn decrypt_payload(&self, payload: &VaultPayload<'_>) -> Result<Vec<u8>, Error> {
485
        // This is a no-op, but it will cause a compiler error if we introduce additional encryption methods
486
8327
        let encrypted = match payload.encryption {
487
8327
            Encryption::XChaCha20Poly1305 => {
488
8327
                XChaCha20Poly1305::new(GenericArray::from_slice(&self.0)).decrypt(
489
8327
                    GenericArray::from_slice(&payload.nonce),
490
8327
                    Payload {
491
8327
                        msg: &payload.payload,
492
8327
                        aad: b"",
493
8327
                    },
494
8327
                )?
495
            }
496
        };
497
8326
        Ok(encrypted)
498
8327
    }
499
}
500

            
501
impl Drop for EncryptionKey {
502
2507
    fn drop(&mut self) {
503
2507
        self.0.zeroize();
504
2507
    }
505
}
506

            
507
impl Debug for EncryptionKey {
508
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
509
        f.debug_struct("PrivateKey").finish_non_exhaustive()
510
    }
511
}
512

            
513
/// A [`VaultKeyStorage`] trait that wraps the Error type before returning. This
514
/// type is used to allow the Vault to operate without any generic parameters.
515
/// This trait is auto-implemented for all [`VaultKeyStorage`] implementors.
516
#[async_trait]
517
pub trait AnyVaultKeyStorage: Send + Sync + Debug + 'static {
518
    /// Retrieve all previously stored master keys for a given storage id.
519
    async fn vault_key_for(&self, storage_id: StorageId) -> Result<Option<KeyPair>, Error>;
520

            
521
    /// Store a key. Each server id should have unique storage. The keys are
522
    /// uniquely encrypted per storage id and can only be decrypted by keys
523
    /// contained in the storage itself.
524
    async fn set_vault_key_for(&self, storage_id: StorageId, key: KeyPair) -> Result<(), Error>;
525
}
526

            
527
#[async_trait]
528
impl<T> AnyVaultKeyStorage for T
529
where
530
    T: VaultKeyStorage + 'static,
531
{
532
175
    async fn vault_key_for(&self, server_id: StorageId) -> Result<Option<KeyPair>, Error> {
533
814
        VaultKeyStorage::vault_key_for(self, server_id)
534
814
            .await
535
175
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))
536
350
    }
537

            
538
156
    async fn set_vault_key_for(&self, server_id: StorageId, key: KeyPair) -> Result<(), Error> {
539
294
        VaultKeyStorage::set_vault_key_for(self, server_id, key)
540
294
            .await
541
156
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))
542
312
    }
543
}
544

            
545
/// Stores vault key locally on disk. This is in general considered insecure,
546
/// and shouldn't be used without careful consideration.
547
///
548
/// The primary goal of encryption within BonsaiDb is to offer limited
549
/// encryption at-rest. Within these goals, the primary attack vector being
550
/// protected against is an attacker being able to copy the data off of the
551
/// disks, either by physically gaining access to the drives or having
552
/// filesystem access. By storing the vault key on the same physical media, the
553
/// encryption should be considered insecure because if you can gain access to
554
/// the data, you have access to the keys as well.
555
///
556
/// For production environments, it is much more secure to store the vault key
557
/// in a separate location. We recommand any S3-compatible backend.
558
#[derive(Debug, Clone)]
559
pub struct LocalVaultKeyStorage {
560
    directory: PathBuf,
561
}
562

            
563
impl LocalVaultKeyStorage {
564
    /// Creates a new file-based vaultr key storage, storing files within
565
    /// `path`. The path provided shouod be a directory. If it doesn't exist, it
566
    /// will be created.
567
172
    pub async fn new<P: AsRef<Path>>(path: P) -> Result<Self, tokio::io::Error> {
568
172
        let directory = path.as_ref().to_owned();
569
172
        if !directory.exists() {
570
154
            fs::create_dir_all(&directory).await?;
571
18
        }
572
171
        Ok(Self { directory })
573
171
    }
574
}
575

            
576
/// Errors from local vault key storage.
577
#[derive(thiserror::Error, Debug)]
578
pub enum LocalVaultKeyStorageError {
579
    /// An error interacting with the filesystem.
580
    #[error("io error: {0}")]
581
    Io(#[from] tokio::io::Error),
582

            
583
    /// An error serializing or deserializing the keys.
584
    #[error("serialization error: {0}")]
585
    Serialization(#[from] bincode::Error),
586

            
587
    /// The file was not the correct size.
588
    #[error("file was not the correct size")]
589
    InvalidFile,
590
}
591

            
592
#[async_trait]
593
impl VaultKeyStorage for LocalVaultKeyStorage {
594
    type Error = LocalVaultKeyStorageError;
595

            
596
2647
    async fn vault_key_for(&self, server_id: StorageId) -> Result<Option<KeyPair>, Self::Error> {
597
2647
        let server_file = self.directory.join(server_id.to_string());
598
2647
        if !server_file.exists() {
599
            return Ok(None);
600
2647
        }
601
2647
        let mut contents = File::open(server_file)
602
2647
            .and_then(|mut f| async move {
603
2647
                let mut bytes = Vec::new();
604
9629
                f.read_to_end(&mut bytes).await.map(|_| bytes)
605
12110
            })
606
12110
            .await?;
607

            
608
2647
        let key = bincode::deserialize::<KeyPair>(&contents)?;
609
2647
        contents.zeroize();
610
2647

            
611
2647
        Ok(Some(key))
612
5294
    }
613

            
614
2355
    async fn set_vault_key_for(
615
2355
        &self,
616
2355
        server_id: StorageId,
617
2355
        key: KeyPair,
618
2355
    ) -> Result<(), Self::Error> {
619
2355
        let server_file = self.directory.join(server_id.to_string());
620
2355
        let bytes = bincode::serialize(&key)?;
621
2355
        File::create(server_file)
622
2355
            .and_then(|mut file| async move {
623
2355
                file.write_all(&bytes).await?;
624
2355
                file.shutdown().await
625
4250
            })
626
4250
            .await?;
627
2355
        Ok(())
628
4710
    }
629
}
630

            
631
155351
#[derive(Serialize, Deserialize)]
632
struct VaultPayload<'a> {
633
    // TODO make key_id be the additional data
634
    key_id: KeyId,
635
    key_version: u32,
636
    encryption: Encryption,
637
    payload: Cow<'a, [u8]>,
638
    nonce: Cow<'a, [u8]>,
639
}
640

            
641
impl<'a> VaultPayload<'a> {
642
155351
    fn from_slice(bytes: &'a [u8]) -> Result<Self, Error> {
643
155351
        bincode::deserialize(bytes).map_err(|err| {
644
147023
            Error::Encryption(format!("error deserializing encrypted payload: {:?}", err))
645
155351
        })
646
155351
    }
647

            
648
41225
    fn to_vec(&self) -> Vec<u8> {
649
41225
        bincode::serialize(self).unwrap()
650
41225
    }
651
}
652

            
653
313
#[derive(Serialize, Deserialize)]
654
struct HpkePayload {
655
    encryption: PublicKeyEncryption,
656
    payload: Bytes,
657
    tag: [u8; 16],
658
    encapsulated_key: <DhP256HkdfSha256 as Kem>::EncappedKey,
659
}
660

            
661
287935
#[derive(Serialize, Deserialize)]
662
enum Encryption {
663
    XChaCha20Poly1305,
664
}
665

            
666
320
#[derive(Serialize, Deserialize)]
667
enum PublicKeyEncryption {
668
    DhP256HkdfSha256ChaCha20,
669
}
670

            
671
#[cfg(test)]
672
mod tests {
673
    use super::*;
674

            
675
    #[derive(Debug)]
676
    struct NullKeyStorage;
677
    #[async_trait]
678
    impl VaultKeyStorage for NullKeyStorage {
679
        type Error = anyhow::Error;
680

            
681
        async fn set_vault_key_for(
682
            &self,
683
            _storage_id: StorageId,
684
            _key: KeyPair,
685
        ) -> Result<(), Self::Error> {
686
            unreachable!()
687
        }
688

            
689
        async fn vault_key_for(
690
            &self,
691
            _storage_id: StorageId,
692
        ) -> Result<Option<KeyPair>, Self::Error> {
693
            unreachable!()
694
        }
695
    }
696

            
697
2
    fn random_null_vault() -> Vault {
698
2
        let mut master_keys = HashMap::new();
699
2
        master_keys.insert(0, EncryptionKey::random());
700
2

            
701
2
        let (_, public_key) = <DhP256HkdfSha256 as Kem>::gen_keypair(&mut thread_rng());
702
2

            
703
2
        Vault {
704
2
            _vault_public_key: PublicKey::P256(public_key),
705
2
            master_keys,
706
2
            current_master_key_id: 0,
707
2
            master_key_storage: Arc::new(NullKeyStorage),
708
2
        }
709
2
    }
710

            
711
1
    #[test]
712
1
    fn vault_encryption_test() {
713
1
        let vault = random_null_vault();
714
1
        let encrypted = vault
715
1
            .encrypt_payload(&KeyId::Master, b"hello", None)
716
1
            .unwrap();
717
1
        let decrypted = vault.decrypt_payload(&encrypted, None).unwrap();
718
1

            
719
1
        assert_eq!(decrypted, b"hello");
720
1
    }
721

            
722
1
    #[test]
723
1
    fn vault_permissions_test() {
724
1
        let vault = random_null_vault();
725
1
        assert!(matches!(
726
1
            vault.encrypt_payload(&KeyId::Master, b"hello", Some(&Permissions::default()),),
727
            Err(crate::Error::Core(bonsaidb_core::Error::PermissionDenied(
728
                _
729
            )))
730
        ));
731
1
        let encrypted = vault
732
1
            .encrypt_payload(&KeyId::Master, b"hello", None)
733
1
            .unwrap();
734
1
        assert!(matches!(
735
1
            vault.decrypt_payload(&encrypted, Some(&Permissions::default())),
736
            Err(crate::Error::Core(bonsaidb_core::Error::PermissionDenied(
737
                _
738
            )))
739
        ));
740
1
    }
741
}