Skip to content

Commit

Permalink
Moved HPKE stuff to its own file
Browse files Browse the repository at this point in the history
  • Loading branch information
rozbb committed Nov 16, 2023
1 parent 385d65c commit 586f360
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 80 deletions.
88 changes: 88 additions & 0 deletions crates/bonsaidb-local/src/hpke_util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use generic_array::GenericArray;
use hpke::{
kem::{DhP256HkdfSha256, Kem as KemTrait},
Deserializable, Serializable,
};
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};

// Helpful aliases for the HPKE types we use in vault encryption

pub(crate) type VaultP256Kem = DhP256HkdfSha256;
pub(crate) type VaultP256PublicKey = <DhP256HkdfSha256 as KemTrait>::PublicKey;
pub(crate) type VaultP256PrivateKey = <DhP256HkdfSha256 as KemTrait>::PrivateKey;
pub(crate) type VaultP256EncappedKey = <DhP256HkdfSha256 as KemTrait>::EncappedKey;

// A previous version of hpke had serde impls. For backwards compatibility, we re-implement that
// here. All this is is casting to/from GenericArray, and using GenericArray's serde impl, just as
// the original did it:
// https://github.com/rozbb/rust-hpke/blob/57fce26b436f47846ee4f9a972ea0675786101c9/src/serde_impls.rs#L42-L74

// We put everything in its own module so we can use the `with` field attribute
// https://serde.rs/field-attrs.html#with

pub(crate) mod serde_pubkey {
use super::*;

Check failure on line 24 in crates/bonsaidb-local/src/hpke_util.rs

View workflow job for this annotation

GitHub Actions / test (--all-features, 1.70)

usage of wildcard import

pub(crate) fn serialize<S: Serializer>(
public_key: &VaultP256PublicKey,
serializer: S,
) -> Result<S::Ok, S::Error> {
let arr = public_key.to_bytes();
arr.serialize(serializer)
}

pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<VaultP256PublicKey, D::Error> {
let arr =
GenericArray::<u8, <VaultP256PublicKey as Serializable>::OutputSize>::deserialize(
deserializer,
)?;
VaultP256PublicKey::from_bytes(&arr).map_err(D::Error::custom)
}
}

pub(crate) mod serde_privkey {
use super::*;

Check failure on line 46 in crates/bonsaidb-local/src/hpke_util.rs

View workflow job for this annotation

GitHub Actions / test (--all-features, 1.70)

usage of wildcard import
use hpke::Serializable;

pub(crate) fn serialize<S: Serializer>(
private_key: &VaultP256PrivateKey,
serializer: S,
) -> Result<S::Ok, S::Error> {
let arr = private_key.to_bytes();
arr.serialize(serializer)
}

pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<VaultP256PrivateKey, D::Error> {
let arr =
GenericArray::<u8, <VaultP256PrivateKey as Serializable>::OutputSize>::deserialize(
deserializer,
)?;
VaultP256PrivateKey::from_bytes(&arr).map_err(D::Error::custom)
}
}

pub(crate) mod serde_encapped_key {
use super::*;

Check failure on line 69 in crates/bonsaidb-local/src/hpke_util.rs

View workflow job for this annotation

GitHub Actions / test (--all-features, 1.70)

usage of wildcard import

pub(crate) fn serialize<S: Serializer>(
encapped_key: &VaultP256EncappedKey,
serializer: S,
) -> Result<S::Ok, S::Error> {
let arr = encapped_key.to_bytes();
serializer.serialize_bytes(&arr)
}

pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<VaultP256EncappedKey, D::Error> {
let arr =
GenericArray::<u8, <VaultP256EncappedKey as Serializable>::OutputSize>::deserialize(
deserializer,
)?;
VaultP256EncappedKey::from_bytes(&arr).map_err(D::Error::custom)
}
}
2 changes: 2 additions & 0 deletions crates/bonsaidb-local/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub mod cli;
pub mod config;
mod database;
mod error;
#[cfg(feature = "encryption")]
mod hpke_util;
mod open_trees;
mod storage;
mod tasks;
Expand Down
96 changes: 16 additions & 80 deletions crates/bonsaidb-local/src/vault.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@
//! used directly. This variant of `ChaCha20Poly1305` extends the nonce from 12
//! bytes to 24 bytes, which allows for random nonces to be used.
use crate::hpke_util::{
serde_encapped_key, serde_privkey, serde_pubkey, VaultP256EncappedKey, VaultP256Kem,
VaultP256PrivateKey, VaultP256PublicKey,
};

use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt::{Debug, Display};
Expand All @@ -60,100 +65,31 @@ use bonsaidb_core::arc_bytes::serde::Bytes;
use bonsaidb_core::document::KeyId;
use bonsaidb_core::permissions::bonsai::{encryption_key_resource_name, EncryptionKeyAction};
use bonsaidb_core::permissions::Permissions;
use chacha20poly1305::aead::generic_array::GenericArray;
use chacha20poly1305::aead::{Aead, Payload};
use chacha20poly1305::{KeyInit, XChaCha20Poly1305};
use generic_array::GenericArray;
use hpke::aead::{AeadTag, ChaCha20Poly1305};
use hpke::kdf::HkdfSha256;
use hpke::kem::DhP256HkdfSha256;
use hpke::{self, Deserializable, Kem, OpModeS, Serializable};
use hpke::{self, Deserializable, Kem as KemTrait, OpModeS, Serializable};
use lockedbox::LockedBox;
use rand::{thread_rng, Rng};
use serde::{de::Error as DeError, Deserialize, Serialize};
use serde::{Deserialize, Serialize};
use zeroize::{Zeroize, Zeroizing};

type HpkePublicKey = <DhP256HkdfSha256 as Kem>::PublicKey;
type HpkePrivateKey = <DhP256HkdfSha256 as Kem>::PrivateKey;
type HpkeEncappedKey = <DhP256HkdfSha256 as Kem>::EncappedKey;

/// A private encryption key.
#[derive(Serialize, Deserialize)]
pub enum KeyPair {
/// A P256 keypair.
P256 {
/// The private key.
#[serde(with = "serde_privkey")]
private: HpkePrivateKey,
private: VaultP256PrivateKey,
/// The public key.
#[serde(with = "serde_pubkey")]
public: HpkePublicKey,
public: VaultP256PublicKey,
},
}

mod serde_pubkey {
use super::*;

pub(super) fn serialize<S: serde::Serializer>(
public_key: &HpkePublicKey,
serializer: S,
) -> Result<S::Ok, S::Error> {
let arr = public_key.to_bytes();
arr.serialize(serializer)
}

pub(super) fn deserialize<'de, D: serde::Deserializer<'de>>(
deserializer: D,
) -> Result<HpkePublicKey, D::Error> {
let arr = GenericArray::<u8, <HpkePublicKey as Serializable>::OutputSize>::deserialize(
deserializer,
)?;
HpkePublicKey::from_bytes(&arr).map_err(D::Error::custom)
}
}

mod serde_privkey {
use super::*;
use hpke::Serializable;

pub(super) fn serialize<S: serde::Serializer>(
private_key: &HpkePrivateKey,
serializer: S,
) -> Result<S::Ok, S::Error> {
let arr = private_key.to_bytes();
arr.serialize(serializer)
}

pub(super) fn deserialize<'de, D: serde::Deserializer<'de>>(
deserializer: D,
) -> Result<HpkePrivateKey, D::Error> {
let arr = GenericArray::<u8, <HpkePrivateKey as Serializable>::OutputSize>::deserialize(
deserializer,
)?;
HpkePrivateKey::from_bytes(&arr).map_err(D::Error::custom)
}
}

mod serde_encapped_key {
use super::*;

pub(super) fn serialize<S: serde::Serializer>(
encapped_key: &HpkeEncappedKey,
serializer: S,
) -> Result<S::Ok, S::Error> {
let arr = encapped_key.to_bytes();
serializer.serialize_bytes(&arr)
}

pub(super) fn deserialize<'de, D: serde::Deserializer<'de>>(
deserializer: D,
) -> Result<HpkeEncappedKey, D::Error> {
let arr = GenericArray::<u8, <HpkeEncappedKey as Serializable>::OutputSize>::deserialize(
deserializer,
)?;
HpkeEncappedKey::from_bytes(&arr).map_err(D::Error::custom)
}
}

impl KeyPair {
/// Serializes the private key into bytes.
pub fn to_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
Expand All @@ -171,7 +107,7 @@ impl KeyPair {
pub enum PublicKey {
/// A P256 public key.
#[serde(with = "serde_pubkey")]
P256(HpkePublicKey),
P256(VaultP256PublicKey),
}

impl PublicKey {
Expand Down Expand Up @@ -269,7 +205,7 @@ impl Vault {
master_key_storage: Arc<dyn AnyVaultKeyStorage>,
) -> Result<Self, Error> {
let master_key = EncryptionKey::random();
let (private, public) = DhP256HkdfSha256::gen_keypair(&mut thread_rng());
let (private, public) = VaultP256Kem::gen_keypair(&mut thread_rng());

master_key_storage
.set_vault_key_for(
Expand Down Expand Up @@ -297,7 +233,7 @@ impl Vault {
let (encapsulated_key, aead_tag) = hpke::single_shot_seal_in_place_detached::<
ChaCha20Poly1305,
HkdfSha256,
DhP256HkdfSha256,
VaultP256Kem,
_,
>(
&OpModeS::Base,
Expand Down Expand Up @@ -352,7 +288,7 @@ impl Vault {
let master_keys = match &vault_key {
KeyPair::P256 { private, .. } => {
let mut decryption_context =
hpke::setup_receiver::<ChaCha20Poly1305, HkdfSha256, DhP256HkdfSha256>(
hpke::setup_receiver::<ChaCha20Poly1305, HkdfSha256, VaultP256Kem>(
&hpke::OpModeR::Base,
private,
&encrypted_master_keys.encapsulated_key,
Expand Down Expand Up @@ -690,7 +626,7 @@ struct HpkePayload {
payload: Bytes,
tag: [u8; 16],
#[serde(with = "serde_encapped_key")]
encapsulated_key: HpkeEncappedKey,
encapsulated_key: VaultP256EncappedKey,
}

#[derive(Serialize, Deserialize)]
Expand Down Expand Up @@ -729,7 +665,7 @@ mod tests {
let mut master_keys = HashMap::new();
master_keys.insert(0, EncryptionKey::random());

let (_, public_key) = <DhP256HkdfSha256 as Kem>::gen_keypair(&mut thread_rng());
let (_, public_key) = <VaultP256Kem as KemTrait>::gen_keypair(&mut thread_rng());

Vault {
_vault_public_key: PublicKey::P256(public_key),
Expand Down

0 comments on commit 586f360

Please sign in to comment.