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
7757
#[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
25
    pub fn to_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
103
25
        Ok(Zeroizing::new(bincode::serialize(self)?))
104
25
    }
105

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

            
112
/// A public key corresponding to a [`KeyPair`].
113
9164
#[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
4582
    pub fn to_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
122
4582
        Ok(Zeroizing::new(bincode::serialize(self)?))
123
4582
    }
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
2594
    fn from(key: &'a KeyPair) -> Self {
133
2594
        match key {
134
2594
            KeyPair::P256 { public, .. } => PublicKey::P256(public.clone()),
135
2594
        }
136
2594
    }
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
334804
#[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
2594
    pub async fn initialize(
196
2594
        server_id: StorageId,
197
2594
        server_directory: &Path,
198
2594
        master_key_storage: Arc<dyn AnyVaultKeyStorage>,
199
2594
    ) -> Result<Self, Error> {
200
171
        let master_keys_path = server_directory.join("master-keys");
201
171
        if master_keys_path.exists() {
202
122
            Self::unseal(&master_keys_path, server_id, master_key_storage).await
203
        } else {
204
1163
            Self::initialize_vault_key_storage(&master_keys_path, server_id, master_key_storage)
205
1162
                .await
206
        }
207
171
    }
208

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

            
217
155
        master_key_storage
218
155
            .set_vault_key_for(
219
155
                server_id,
220
155
                KeyPair::P256 {
221
155
                    private: private.clone(),
222
155
                    public: public.clone(),
223
155
                },
224
289
            )
225
286
            .await
226
155
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))?;
227
155
        let mut master_keys = HashMap::new();
228
155
        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
155
        let retrieved = master_key_storage
232
684
            .vault_key_for(server_id)
233
683
            .await
234
155
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))?;
235
155
        let expected_public_key_bytes = PublicKey::P256(public.clone()).to_bytes().unwrap();
236
155
        let retrieved_key_matches = retrieved
237
155
            .map(|r| PublicKey::from(&r).to_bytes().ok() == Some(expected_public_key_bytes))
238
155
            .unwrap_or_default();
239
155
        if retrieved_key_matches {
240
155
            let mut serialized_master_keys = bincode::serialize(&master_keys)?;
241

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

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

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

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

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

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

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

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

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

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

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

            
367
    pub fn decrypt_payload(
368
        &self,
369
        payload: &[u8],
370
        permissions: Option<&Permissions>,
371
    ) -> Result<Vec<u8>, crate::Error> {
372
343034
        if let Ok(payload) = VaultPayload::from_slice(payload).map_err(|err| {
373
334804
            Error::Encryption(format!("error deserializing encrypted payload: {:?}", err))
374
343034
        }) {
375
8230
            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
334804
            Ok(payload.to_vec())
380
        }
381
343034
    }
382

            
383
8230
    fn decrypt(
384
8230
        &self,
385
8230
        payload: &VaultPayload<'_>,
386
8230
        permissions: Option<&Permissions>,
387
8230
    ) -> Result<Vec<u8>, crate::Error> {
388
8230
        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
8229
        }
394

            
395
        // TODO handle key version
396
8229
        let key = match &payload.key_id {
397
8229
            KeyId::Master => self.current_master_key(),
398
            KeyId::Id(_) => todo!(),
399
            KeyId::None => unreachable!(),
400
        };
401
8229
        Ok(key.decrypt_payload(payload)?)
402
8230
    }
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
311
#[derive(Serialize, Deserialize)]
422
struct EncryptionKey([u8; 32], #[serde(skip)] Option<region::LockGuard>);
423

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

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

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

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

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

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

            
484
8229
    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
8229
        let encrypted = match payload.encryption {
487
8229
            Encryption::XChaCha20Poly1305 => {
488
8229
                XChaCha20Poly1305::new(GenericArray::from_slice(&self.0)).decrypt(
489
8229
                    GenericArray::from_slice(&payload.nonce),
490
8229
                    Payload {
491
8229
                        msg: &payload.payload,
492
8229
                        aad: b"",
493
8229
                    },
494
8229
                )?
495
            }
496
        };
497
8228
        Ok(encrypted)
498
8229
    }
499
}
500

            
501
impl Drop for EncryptionKey {
502
2384
    fn drop(&mut self) {
503
2384
        self.0.zeroize();
504
2384
    }
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
171
    async fn vault_key_for(&self, server_id: StorageId) -> Result<Option<KeyPair>, Error> {
533
790
        VaultKeyStorage::vault_key_for(self, server_id)
534
789
            .await
535
171
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))
536
341
    }
537

            
538
155
    async fn set_vault_key_for(&self, server_id: StorageId, key: KeyPair) -> Result<(), Error> {
539
289
        VaultKeyStorage::set_vault_key_for(self, server_id, key)
540
286
            .await
541
155
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))
542
310
    }
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
168
    pub async fn new<P: AsRef<Path>>(path: P) -> Result<Self, tokio::io::Error> {
568
168
        let directory = path.as_ref().to_owned();
569
168
        if !directory.exists() {
570
153
            fs::create_dir_all(&directory).await?;
571
15
        }
572
168
        Ok(Self { directory })
573
168
    }
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
2519
    async fn vault_key_for(&self, server_id: StorageId) -> Result<Option<KeyPair>, Self::Error> {
597
2544
        let server_file = self.directory.join(server_id.to_string());
598
2544
        if !server_file.exists() {
599
            return Ok(None);
600
2544
        }
601
2544
        let mut contents = File::open(server_file)
602
2544
            .and_then(|mut f| async move {
603
2519
                let mut bytes = Vec::new();
604
9109
                f.read_to_end(&mut bytes).await.map(|_| bytes)
605
11391
            })
606
11391
            .await?;
607

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

            
611
2544
        Ok(Some(key))
612
5063
    }
613

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

            
631
343034
#[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
343034
    fn from_slice(bytes: &'a [u8]) -> Result<Self, Error> {
643
343034
        bincode::deserialize(bytes).map_err(|err| {
644
334804
            Error::Encryption(format!("error deserializing encrypted payload: {:?}", err))
645
343034
        })
646
343034
    }
647

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

            
653
311
#[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
658516
#[derive(Serialize, Deserialize)]
662
enum Encryption {
663
    XChaCha20Poly1305,
664
}
665

            
666
318
#[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
}