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
    fs::{self, File},
56
    io::{Read, Write},
57
    path::{Path, PathBuf},
58
    sync::Arc,
59
};
60

            
61
use bonsaidb_core::{
62
    arc_bytes::serde::Bytes,
63
    document::KeyId,
64
    permissions::{
65
        bonsai::{encryption_key_resource_name, EncryptionKeyAction},
66
        Permissions,
67
    },
68
};
69
use chacha20poly1305::{
70
    aead::{generic_array::GenericArray, Aead, NewAead, Payload},
71
    XChaCha20Poly1305,
72
};
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 zeroize::{Zeroize, Zeroizing};
83

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

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

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

            
108
/// A public key corresponding to a [`KeyPair`].
109
11894
#[derive(Serialize, Deserialize)]
110
pub enum PublicKey {
111
    /// A P256 public key.
112
    P256(<DhP256HkdfSha256 as Kem>::PublicKey),
113
}
114

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

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

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

            
135
use crate::storage::StorageId;
136

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
310
426
                    bincode::deserialize::<HashMap<u32, EncryptionKey>>(
311
426
                        &encrypted_master_keys.payload,
312
426
                    )?
313
                }
314
            };
315

            
316
426
            let current_master_key_id = *master_keys.keys().max().unwrap();
317
426
            Ok(Self {
318
426
                _vault_public_key: PublicKey::from(&vault_key),
319
426
                master_keys,
320
426
                current_master_key_id,
321
426
                master_key_storage,
322
426
            })
323
        } else {
324
60
            Err(Error::VaultKeyNotFound)
325
        }
326
486
    }
327

            
328
63746
    fn current_master_key(&self) -> &EncryptionKey {
329
63746
        self.master_keys.get(&self.current_master_key_id).unwrap()
330
63746
    }
331

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

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

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

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

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

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

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

            
403
5962
#[derive(Serialize, Deserialize)]
404
struct EncryptionKey([u8; 32], #[serde(skip)] Option<region::LockGuard>);
405

            
406
impl EncryptionKey {
407
2983
    pub fn new(secret: [u8; 32]) -> Self {
408
2983
        let mut new_key = Self(secret, None);
409
2983
        new_key.lock_memory();
410
2983
        new_key
411
2983
    }
412

            
413
5966
    pub fn key(&self) -> &[u8] {
414
5966
        &self.0
415
5966
    }
416

            
417
2983
    pub fn lock_memory(&mut self) {
418
2983
        if self.1.is_none() {
419
2983
            match region::lock(self.key().as_ptr(), self.key().len()) {
420
2983
                Ok(guard) => self.1 = Some(guard),
421
                Err(err) => log::error!("Security Warning: Unable to lock memory {:?}", err),
422
            }
423
        }
424
2983
    }
425

            
426
2983
    pub fn random() -> Self {
427
2983
        Self::new(thread_rng().gen())
428
2983
    }
429

            
430
52403
    pub fn encrypt_payload(
431
52403
        &self,
432
52403
        key_id: KeyId,
433
52403
        key_version: u32,
434
52403
        payload: &[u8],
435
52403
    ) -> VaultPayload<'static> {
436
52403
        let mut rng = thread_rng();
437
52403
        let nonce: [u8; 24] = rng.gen();
438
52403
        self.encrypt_payload_with_nonce(key_id, key_version, payload, &nonce)
439
52403
    }
440

            
441
52403
    pub fn encrypt_payload_with_nonce(
442
52403
        &self,
443
52403
        key_id: KeyId,
444
52403
        key_version: u32,
445
52403
        payload: &[u8],
446
52403
        nonce: &[u8],
447
52403
    ) -> VaultPayload<'static> {
448
52403
        let encrypted = XChaCha20Poly1305::new(GenericArray::from_slice(&self.0))
449
52403
            .encrypt(
450
52403
                GenericArray::from_slice(nonce),
451
52403
                Payload {
452
52403
                    msg: payload,
453
52403
                    aad: b"",
454
52403
                },
455
52403
            )
456
52403
            .unwrap();
457
52403
        VaultPayload {
458
52403
            key_id,
459
52403
            encryption: Encryption::XChaCha20Poly1305,
460
52403
            payload: Cow::Owned(encrypted),
461
52403
            nonce: Cow::Owned(nonce.to_vec()),
462
52403
            key_version,
463
52403
        }
464
52403
    }
465

            
466
11343
    pub fn decrypt_payload(&self, payload: &VaultPayload<'_>) -> Result<Vec<u8>, Error> {
467
        // This is a no-op, but it will cause a compiler error if we introduce additional encryption methods
468
11343
        let encrypted = match payload.encryption {
469
11343
            Encryption::XChaCha20Poly1305 => {
470
11343
                XChaCha20Poly1305::new(GenericArray::from_slice(&self.0)).decrypt(
471
11343
                    GenericArray::from_slice(&payload.nonce),
472
11343
                    Payload {
473
11343
                        msg: &payload.payload,
474
11343
                        aad: b"",
475
11343
                    },
476
11343
                )?
477
            }
478
        };
479
11342
        Ok(encrypted)
480
11343
    }
481
}
482

            
483
impl Drop for EncryptionKey {
484
3319
    fn drop(&mut self) {
485
3319
        self.0.zeroize();
486
3319
    }
487
}
488

            
489
impl Debug for EncryptionKey {
490
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
491
        f.debug_struct("PrivateKey").finish_non_exhaustive()
492
    }
493
}
494

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

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

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

            
517
2923
    fn set_vault_key_for(&self, server_id: StorageId, key: KeyPair) -> Result<(), Error> {
518
2923
        VaultKeyStorage::set_vault_key_for(self, server_id, key)
519
2923
            .map_err(|err| Error::VaultKeyStorage(err.to_string()))
520
2923
    }
521
}
522

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

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

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

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

            
565
    /// The file was not the correct size.
566
    #[error("file was not the correct size")]
567
    InvalidFile,
568
}
569

            
570
impl VaultKeyStorage for LocalVaultKeyStorage {
571
    type Error = LocalVaultKeyStorageError;
572

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

            
583
3287
        let key = bincode::deserialize::<KeyPair>(&contents)?;
584
3287
        contents.zeroize();
585
3287

            
586
3287
        Ok(Some(key))
587
3287
    }
588

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

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

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

            
614
52373
    fn to_vec(&self) -> Vec<u8> {
615
52373
        bincode::serialize(self).unwrap()
616
52373
    }
617
}
618

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

            
627
232504
#[derive(Serialize, Deserialize)]
628
enum Encryption {
629
    XChaCha20Poly1305,
630
}
631

            
632
5932
#[derive(Serialize, Deserialize)]
633
enum PublicKeyEncryption {
634
    DhP256HkdfSha256ChaCha20,
635
}
636

            
637
#[cfg(test)]
638
mod tests {
639
    use super::*;
640

            
641
    #[derive(Debug)]
642
    struct NullKeyStorage;
643
    impl VaultKeyStorage for NullKeyStorage {
644
        type Error = anyhow::Error;
645

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

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

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

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

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

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

            
681
1
        assert_eq!(decrypted, b"hello");
682
1
    }
683

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