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::kem::DhP256HkdfSha256;
69
use hpke::{self, Deserializable, Kem, OpModeS, Serializable};
70
use lockedbox::LockedBox;
71
use rand::{thread_rng, Rng};
72
use serde::{Deserialize, Serialize};
73
use zeroize::{Zeroize, Zeroizing};
74

            
75
/// A private encryption key.
76
15783
#[derive(Serialize, Deserialize)]
77
pub enum KeyPair {
78
    /// A P256 keypair.
79
    P256 {
80
        /// The private key.
81
        private: <DhP256HkdfSha256 as Kem>::PrivateKey,
82
        /// The public key.
83
        public: <DhP256HkdfSha256 as Kem>::PublicKey,
84
    },
85
}
86

            
87
impl KeyPair {
88
    /// Serializes the private key into bytes.
89
74
    pub fn to_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
90
74
        Ok(Zeroizing::new(bincode::serialize(self)?))
91
74
    }
92

            
93
    /// Deserializes the private key.
94
148
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
95
148
        bincode::deserialize(bytes).map_err(Error::from)
96
148
    }
97
}
98

            
99
/// A public key corresponding to a [`KeyPair`].
100
18504
#[derive(Serialize, Deserialize)]
101
pub enum PublicKey {
102
    /// A P256 public key.
103
    P256(<DhP256HkdfSha256 as Kem>::PublicKey),
104
}
105

            
106
impl PublicKey {
107
    /// Serializes the public key into bytes.
108
9252
    pub fn to_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
109
9252
        Ok(Zeroizing::new(bincode::serialize(self)?))
110
9252
    }
111

            
112
    /// Deserializes the public key.
113
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
114
        bincode::deserialize(bytes).map_err(Error::from)
115
    }
116
}
117

            
118
impl<'a> From<&'a KeyPair> for PublicKey {
119
5261
    fn from(key: &'a KeyPair) -> Self {
120
5261
        match key {
121
5261
            KeyPair::P256 { public, .. } => PublicKey::P256(public.clone()),
122
5261
        }
123
5261
    }
124
}
125

            
126
use crate::storage::StorageId;
127

            
128
pub(crate) struct Vault {
129
    _vault_public_key: PublicKey,
130
    master_keys: HashMap<u32, EncryptionKey>,
131
    current_master_key_id: u32,
132
    master_key_storage: Arc<dyn AnyVaultKeyStorage>,
133
}
134

            
135
impl Debug for Vault {
136
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137
        f.debug_struct("Vault")
138
            .field("master_keys", &self.master_keys)
139
            .field("current_master_key_id", &self.current_master_key_id)
140
            .field("master_key_storage", &self.master_key_storage)
141
            .finish_non_exhaustive()
142
    }
143
}
144

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

            
163
impl From<chacha20poly1305::aead::Error> for Error {
164
1
    fn from(err: chacha20poly1305::aead::Error) -> Self {
165
1
        Self::Encryption(err.to_string())
166
1
    }
167
}
168

            
169
impl From<hpke::HpkeError> for Error {
170
    fn from(err: hpke::HpkeError) -> Self {
171
        Self::Encryption(err.to_string())
172
    }
173
}
174

            
175
impl From<bincode::Error> for Error {
176
    fn from(err: bincode::Error) -> Self {
177
        Self::Initializing(err.to_string())
178
    }
179
}
180

            
181
impl Vault {
182
5335
    pub fn initialize(
183
5335
        server_id: StorageId,
184
5335
        server_directory: &Path,
185
5335
        master_key_storage: Arc<dyn AnyVaultKeyStorage>,
186
5335
    ) -> Result<Self, Error> {
187
5335
        let master_keys_path = server_directory.join("master-keys");
188
5335
        if master_keys_path.exists() {
189
709
            Self::unseal(&master_keys_path, server_id, master_key_storage)
190
        } else {
191
4626
            Self::initialize_vault_key_storage(&master_keys_path, server_id, master_key_storage)
192
        }
193
5335
    }
194

            
195
4626
    fn initialize_vault_key_storage(
196
4626
        master_keys_path: &Path,
197
4626
        server_id: StorageId,
198
4626
        master_key_storage: Arc<dyn AnyVaultKeyStorage>,
199
4626
    ) -> Result<Self, Error> {
200
4626
        let master_key = EncryptionKey::random();
201
4626
        let (private, public) = DhP256HkdfSha256::gen_keypair(&mut thread_rng());
202
4626

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

            
226
4626
            let (encapsulated_key, aead_tag) = hpke::single_shot_seal_in_place_detached::<
227
4626
                ChaCha20Poly1305,
228
4626
                HkdfSha256,
229
4626
                DhP256HkdfSha256,
230
4626
                _,
231
4626
            >(
232
4626
                &OpModeS::Base,
233
4626
                &public,
234
4626
                b"",
235
4626
                &mut serialized_master_keys,
236
4626
                b"",
237
4626
                &mut thread_rng(),
238
4626
            )?;
239
4626
            let mut tag = [0_u8; 16];
240
4626
            tag.copy_from_slice(&aead_tag.to_bytes());
241

            
242
4626
            let encrypted_master_keys_payload = bincode::serialize(&HpkePayload {
243
4626
                encryption: PublicKeyEncryption::DhP256HkdfSha256ChaCha20,
244
4626
                payload: Bytes::from(serialized_master_keys),
245
4626
                encapsulated_key,
246
4626
                tag,
247
4626
            })?;
248

            
249
4626
            File::create(master_keys_path)
250
4626
                .and_then(move |mut file| file.write_all(&encrypted_master_keys_payload))
251
4626
                .map_err(|err| Error::Initializing(format!("error saving vault key: {err:?}")))?;
252

            
253
4626
            Ok(Self {
254
4626
                _vault_public_key: PublicKey::P256(public),
255
4626
                master_keys,
256
4626
                current_master_key_id: 0,
257
4626
                master_key_storage,
258
4626
            })
259
        } else {
260
            Err(Error::VaultKeyStorage(String::from(
261
                "vault key storage failed to return the same stored key during initialization",
262
            )))
263
        }
264
4626
    }
265

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

            
292
635
                    decryption_context
293
635
                        .open_in_place_detached(
294
635
                            &mut encrypted_master_keys.payload.0,
295
635
                            b"",
296
635
                            &AeadTag::<ChaCha20Poly1305>::from_bytes(&encrypted_master_keys.tag)
297
635
                                .unwrap(),
298
635
                        )
299
635
                        .unwrap();
300
635

            
301
635
                    bincode::deserialize::<HashMap<u32, EncryptionKey>>(
302
635
                        &encrypted_master_keys.payload,
303
635
                    )?
304
                }
305
            };
306

            
307
635
            let current_master_key_id = *master_keys.keys().max().unwrap();
308
635
            Ok(Self {
309
635
                _vault_public_key: PublicKey::from(&vault_key),
310
635
                master_keys,
311
635
                current_master_key_id,
312
635
                master_key_storage,
313
635
            })
314
        } else {
315
74
            Err(Error::VaultKeyNotFound)
316
        }
317
709
    }
318

            
319
90301
    fn current_master_key(&self) -> &EncryptionKey {
320
90301
        self.master_keys.get(&self.current_master_key_id).unwrap()
321
90301
    }
322

            
323
74321
    pub fn encrypt_payload(
324
74321
        &self,
325
74321
        key_id: &KeyId,
326
74321
        payload: &[u8],
327
74321
        permissions: Option<&Permissions>,
328
74321
    ) -> Result<Vec<u8>, crate::Error> {
329
74321
        if let Some(permissions) = permissions {
330
1
            permissions.check(
331
1
                encryption_key_resource_name(key_id),
332
1
                &EncryptionKeyAction::Encrypt,
333
1
            )?;
334
74320
        }
335

            
336
74320
        let (key, version) = match key_id {
337
74320
            KeyId::Master => (self.current_master_key(), self.current_master_key_id),
338
            KeyId::Id(_) => todo!(),
339
            KeyId::None => unreachable!(),
340
        };
341
74320
        let payload = key.encrypt_payload(key_id.clone(), version, payload);
342
74320
        Ok(payload.to_vec())
343
74321
    }
344

            
345
    pub fn decrypt_payload(
346
        &self,
347
        payload: &[u8],
348
        permissions: Option<&Permissions>,
349
    ) -> Result<Vec<u8>, crate::Error> {
350
164698
        if let Ok(payload) = VaultPayload::from_slice(payload).map_err(|err| {
351
148716
            Error::Encryption(format!("error deserializing encrypted payload: {err:?}"))
352
164698
        }) {
353
15982
            self.decrypt(&payload, permissions)
354
        } else {
355
            // If we can't parse it as a VaultPayload, it might have been stored
356
            // decrypted originally.
357
148716
            Ok(payload.to_vec())
358
        }
359
164698
    }
360

            
361
15982
    fn decrypt(
362
15982
        &self,
363
15982
        payload: &VaultPayload<'_>,
364
15982
        permissions: Option<&Permissions>,
365
15982
    ) -> Result<Vec<u8>, crate::Error> {
366
15982
        if let Some(permissions) = permissions {
367
1
            permissions.check(
368
1
                encryption_key_resource_name(&payload.key_id),
369
1
                &EncryptionKeyAction::Decrypt,
370
1
            )?;
371
15981
        }
372

            
373
        // TODO handle key version
374
15981
        let key = match &payload.key_id {
375
15981
            KeyId::Master => self.current_master_key(),
376
            KeyId::Id(_) => todo!(),
377
            KeyId::None => unreachable!(),
378
        };
379
15981
        Ok(key.decrypt_payload(payload)?)
380
15982
    }
381
}
382

            
383
/// Stores encrypted keys for a vault.
384
pub trait VaultKeyStorage: Send + Sync + Debug + 'static {
385
    /// The error type that the functions return.
386
    type Error: Display;
387
    /// Store a key. Each server id should have unique storage.
388
    fn set_vault_key_for(&self, storage_id: StorageId, key: KeyPair) -> Result<(), Self::Error>;
389

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

            
394
struct EncryptionKey(LockedBox<[u8; 32]>);
395

            
396
impl EncryptionKey {
397
4628
    pub fn new(secret: [u8; 32]) -> Self {
398
4628
        Self(LockedBox::new(secret))
399
4628
    }
400

            
401
90301
    pub fn key(&self) -> &[u8] {
402
90301
        &*self.0
403
90301
    }
404

            
405
4628
    pub fn random() -> Self {
406
4628
        Self::new(thread_rng().gen())
407
4628
    }
408

            
409
74320
    pub fn encrypt_payload(
410
74320
        &self,
411
74320
        key_id: KeyId,
412
74320
        key_version: u32,
413
74320
        payload: &[u8],
414
74320
    ) -> VaultPayload<'static> {
415
74320
        let mut rng = thread_rng();
416
74320
        let nonce: [u8; 24] = rng.gen();
417
74320
        self.encrypt_payload_with_nonce(key_id, key_version, payload, &nonce)
418
74320
    }
419

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

            
445
15981
    pub fn decrypt_payload(&self, payload: &VaultPayload<'_>) -> Result<Vec<u8>, Error> {
446
        // This is a no-op, but it will cause a compiler error if we introduce additional encryption methods
447
15981
        let encrypted = match payload.encryption {
448
15981
            Encryption::XChaCha20Poly1305 => {
449
15981
                XChaCha20Poly1305::new(GenericArray::from_slice(self.key())).decrypt(
450
15981
                    GenericArray::from_slice(&payload.nonce),
451
15981
                    Payload {
452
15981
                        msg: &payload.payload,
453
15981
                        aad: b"",
454
15981
                    },
455
15981
                )?
456
            }
457
        };
458
15980
        Ok(encrypted)
459
15981
    }
460
}
461

            
462
impl Drop for EncryptionKey {
463
5115
    fn drop(&mut self) {
464
5115
        self.0.zeroize();
465
5115
    }
466
}
467

            
468
impl Debug for EncryptionKey {
469
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
470
        f.debug_struct("PrivateKey").finish_non_exhaustive()
471
    }
472
}
473

            
474
impl Serialize for EncryptionKey {
475
9252
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
476
9252
    where
477
9252
        S: serde::Serializer,
478
9252
    {
479
9252
        self.0.serialize(serializer)
480
9252
    }
481
}
482

            
483
impl<'de> Deserialize<'de> for EncryptionKey {
484
635
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
485
635
    where
486
635
        D: serde::Deserializer<'de>,
487
635
    {
488
635
        Ok(Self(LockedBox::new(<[u8; 32]>::deserialize(deserializer)?)))
489
635
    }
490
}
491

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

            
499
    /// Store a key. Each server id should have unique storage. The keys are
500
    /// uniquely encrypted per storage id and can only be decrypted by keys
501
    /// contained in the storage itself.
502
    fn set_vault_key_for(&self, storage_id: StorageId, key: KeyPair) -> Result<(), Error>;
503
}
504

            
505
impl<T> AnyVaultKeyStorage for T
506
where
507
    T: VaultKeyStorage + 'static,
508
{
509
5119
    fn vault_key_for(&self, server_id: StorageId) -> Result<Option<KeyPair>, Error> {
510
5119
        VaultKeyStorage::vault_key_for(self, server_id)
511
5119
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))
512
5119
    }
513

            
514
4554
    fn set_vault_key_for(&self, server_id: StorageId, key: KeyPair) -> Result<(), Error> {
515
4554
        VaultKeyStorage::set_vault_key_for(self, server_id, key)
516
4554
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))
517
4554
    }
518
}
519

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

            
538
impl LocalVaultKeyStorage {
539
    /// Creates a new file-based vaultr key storage, storing files within
540
    /// `path`. The path provided shouod be a directory. If it doesn't exist, it
541
    /// will be created.
542
5113
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Self, std::io::Error> {
543
5113
        let directory = path.as_ref().to_owned();
544
5113
        if !directory.exists() {
545
4551
            fs::create_dir_all(&directory)?;
546
562
        }
547
5113
        Ok(Self { directory })
548
5113
    }
549
}
550

            
551
/// Errors from local vault key storage.
552
#[derive(thiserror::Error, Debug)]
553
pub enum LocalVaultKeyStorageError {
554
    /// An error interacting with the filesystem.
555
    #[error("io error: {0}")]
556
    Io(#[from] std::io::Error),
557

            
558
    /// An error serializing or deserializing the keys.
559
    #[error("serialization error: {0}")]
560
    Serialization(#[from] bincode::Error),
561

            
562
    /// The file was not the correct size.
563
    #[error("file was not the correct size")]
564
    InvalidFile,
565
}
566

            
567
impl VaultKeyStorage for LocalVaultKeyStorage {
568
    type Error = LocalVaultKeyStorageError;
569

            
570
5113
    fn vault_key_for(&self, server_id: StorageId) -> Result<Option<KeyPair>, Self::Error> {
571
5113
        let server_file = self.directory.join(server_id.to_string());
572
5113
        if !server_file.exists() {
573
            return Ok(None);
574
5113
        }
575
5113
        let mut contents = File::open(server_file).and_then(|mut f| {
576
5113
            let mut bytes = Vec::new();
577
5113
            f.read_to_end(&mut bytes).map(|_| bytes)
578
5113
        })?;
579

            
580
5113
        let key = bincode::deserialize::<KeyPair>(&contents)?;
581
5113
        contents.zeroize();
582
5113

            
583
5113
        Ok(Some(key))
584
5113
    }
585

            
586
4552
    fn set_vault_key_for(&self, server_id: StorageId, key: KeyPair) -> Result<(), Self::Error> {
587
4552
        let server_file = self.directory.join(server_id.to_string());
588
4552
        let bytes = bincode::serialize(&key)?;
589
4552
        File::create(server_file).and_then(|mut file| file.write_all(&bytes))?;
590
4552
        Ok(())
591
4552
    }
592
}
593

            
594
313414
#[derive(Serialize, Deserialize)]
595
struct VaultPayload<'a> {
596
    // TODO make key_id be the additional data
597
    key_id: KeyId,
598
    key_version: u32,
599
    encryption: Encryption,
600
    payload: Cow<'a, [u8]>,
601
    nonce: Cow<'a, [u8]>,
602
}
603

            
604
impl<'a> VaultPayload<'a> {
605
164698
    fn from_slice(bytes: &'a [u8]) -> Result<Self, Error> {
606
164698
        bincode::deserialize(bytes).map_err(|err| {
607
148716
            Error::Encryption(format!("error deserializing encrypted payload: {err:?}"))
608
164698
        })
609
164698
    }
610

            
611
74320
    fn to_vec(&self) -> Vec<u8> {
612
74320
        bincode::serialize(self).unwrap()
613
74320
    }
614
}
615

            
616
9252
#[derive(Serialize, Deserialize)]
617
struct HpkePayload {
618
    encryption: PublicKeyEncryption,
619
    payload: Bytes,
620
    tag: [u8; 16],
621
    encapsulated_key: <DhP256HkdfSha256 as Kem>::EncappedKey,
622
}
623

            
624
388439
#[derive(Serialize, Deserialize)]
625
enum Encryption {
626
    XChaCha20Poly1305,
627
}
628

            
629
9252
#[derive(Serialize, Deserialize)]
630
enum PublicKeyEncryption {
631
    DhP256HkdfSha256ChaCha20,
632
}
633

            
634
#[cfg(test)]
635
mod tests {
636
    use super::*;
637

            
638
    #[derive(Debug)]
639
    struct NullKeyStorage;
640
    impl VaultKeyStorage for NullKeyStorage {
641
        type Error = anyhow::Error;
642

            
643
        fn set_vault_key_for(
644
            &self,
645
            _storage_id: StorageId,
646
            _key: KeyPair,
647
        ) -> Result<(), Self::Error> {
648
            unreachable!()
649
        }
650

            
651
        fn vault_key_for(&self, _storage_id: StorageId) -> Result<Option<KeyPair>, Self::Error> {
652
            unreachable!()
653
        }
654
    }
655

            
656
2
    fn random_null_vault() -> Vault {
657
2
        let mut master_keys = HashMap::new();
658
2
        master_keys.insert(0, EncryptionKey::random());
659
2

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

            
662
2
        Vault {
663
2
            _vault_public_key: PublicKey::P256(public_key),
664
2
            master_keys,
665
2
            current_master_key_id: 0,
666
2
            master_key_storage: Arc::new(NullKeyStorage),
667
2
        }
668
2
    }
669

            
670
1
    #[test]
671
1
    fn vault_encryption_test() {
672
1
        let vault = random_null_vault();
673
1
        let encrypted = vault
674
1
            .encrypt_payload(&KeyId::Master, b"hello", None)
675
1
            .unwrap();
676
1
        let decrypted = vault.decrypt_payload(&encrypted, None).unwrap();
677
1

            
678
1
        assert_eq!(decrypted, b"hello");
679
1
    }
680

            
681
1
    #[test]
682
1
    fn vault_permissions_test() {
683
1
        let vault = random_null_vault();
684
1
        assert!(matches!(
685
1
            vault.encrypt_payload(&KeyId::Master, b"hello", Some(&Permissions::default()),),
686
            Err(crate::Error::Core(bonsaidb_core::Error::PermissionDenied(
687
                _
688
            )))
689
        ));
690
1
        let encrypted = vault
691
1
            .encrypt_payload(&KeyId::Master, b"hello", None)
692
1
            .unwrap();
693
1
        assert!(matches!(
694
1
            vault.decrypt_payload(&encrypted, Some(&Permissions::default())),
695
            Err(crate::Error::Core(bonsaidb_core::Error::PermissionDenied(
696
                _
697
            )))
698
        ));
699
1
    }
700
}