diff --git a/Cargo.lock b/Cargo.lock index 7313235ef6..9fb5d721a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -852,12 +852,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - [[package]] name = "base64" version = "0.12.3" @@ -1158,6 +1152,7 @@ dependencies = [ "fs2", "fs_extra", "futures", + "generic-array", "hpke", "itertools 0.11.0", "lockedbox", @@ -1165,7 +1160,6 @@ dependencies = [ "lz4_flex", "nebari", "once_cell", - "p256 0.13.2", "parking_lot", "pot", "rand", @@ -1831,18 +1825,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "crypto-bigint" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -1943,17 +1925,6 @@ dependencies = [ "const-oid", ] -[[package]] -name = "der" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - [[package]] name = "der-parser" version = "8.2.0" @@ -2051,7 +2022,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", - "const-oid", "crypto-common", "subtle", ] @@ -2141,20 +2111,6 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2afbb9b0aef60e4f0d2b18129b6c0dff035a6f7dbbd17c2f38c1432102ee223c" -[[package]] -name = "ecdsa" -version = "0.16.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" -dependencies = [ - "der 0.7.8", - "digest", - "elliptic-curve 0.13.6", - "rfc6979", - "signature", - "spki", -] - [[package]] name = "either" version = "1.9.0" @@ -2170,36 +2126,16 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ - "base16ct 0.1.1", - "crypto-bigint 0.4.9", - "der 0.6.1", + "base16ct", + "crypto-bigint", + "der", "digest", - "ff 0.12.1", + "ff", "generic-array", - "group 0.12.1", + "group", "hkdf", "rand_core", - "sec1 0.3.0", - "subtle", - "zeroize", -] - -[[package]] -name = "elliptic-curve" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914" -dependencies = [ - "base16ct 0.2.0", - "crypto-bigint 0.5.3", - "digest", - "ff 0.13.0", - "generic-array", - "group 0.13.0", - "pem-rfc7468", - "pkcs8", - "rand_core", - "sec1 0.7.3", + "sec1", "subtle", "zeroize", ] @@ -2365,16 +2301,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ff" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" -dependencies = [ - "rand_core", - "subtle", -] - [[package]] name = "filetime" version = "0.2.22" @@ -2657,7 +2583,6 @@ dependencies = [ "serde", "typenum", "version_check", - "zeroize", ] [[package]] @@ -2763,18 +2688,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "ff 0.12.1", - "rand_core", - "subtle", -] - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff 0.13.0", + "ff", "rand_core", "subtle", ] @@ -2935,9 +2849,8 @@ dependencies = [ "generic-array", "hkdf", "hmac", - "p256 0.11.1", + "p256", "rand_core", - "serde", "sha2", "subtle", "zeroize", @@ -3719,19 +3632,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" dependencies = [ - "elliptic-curve 0.12.3", -] - -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "ecdsa", - "elliptic-curve 0.13.6", - "primeorder", - "sha2", + "elliptic-curve", ] [[package]] @@ -3821,15 +3722,6 @@ dependencies = [ "serde", ] -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - [[package]] name = "percent-encoding" version = "2.3.0" @@ -3951,16 +3843,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der 0.7.8", - "spki", -] - [[package]] name = "pkg-config" version = "0.3.27" @@ -4067,15 +3949,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "primeorder" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3" -dependencies = [ - "elliptic-curve 0.13.6", -] - [[package]] name = "proc-macro-crate" version = "2.0.0" @@ -4372,16 +4245,6 @@ dependencies = [ "quick-error", ] -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - [[package]] name = "ring" version = "0.16.20" @@ -4613,23 +4476,9 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ - "base16ct 0.1.1", - "der 0.6.1", - "generic-array", - "subtle", - "zeroize", -] - -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct 0.2.0", - "der 0.7.8", + "base16ct", + "der", "generic-array", - "pkcs8", "subtle", "zeroize", ] @@ -4843,16 +4692,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" -dependencies = [ - "digest", - "rand_core", -] - [[package]] name = "simd-adler32" version = "0.3.7" @@ -4924,16 +4763,6 @@ dependencies = [ "lock_api", ] -[[package]] -name = "spki" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" -dependencies = [ - "base64ct", - "der 0.7.8", -] - [[package]] name = "sqlformat" version = "0.2.2" diff --git a/crates/bonsaidb-local/Cargo.toml b/crates/bonsaidb-local/Cargo.toml index 94d0b45d81..2d62995cfd 100644 --- a/crates/bonsaidb-local/Cargo.toml +++ b/crates/bonsaidb-local/Cargo.toml @@ -31,6 +31,7 @@ instrument = ["pot/tracing", "nebari/tracing", "dep:tracing"] encryption = [ "bonsaidb-core/encryption", "dep:hpke", + "dep:generic-array", "dep:zeroize", "dep:lockedbox", "dep:chacha20poly1305", @@ -71,9 +72,8 @@ zeroize = { version = "1", optional = true } lockedbox = { version = "0.1.1", optional = true } hpke = { version = "0.10", default-features = false, features = [ "p256", - "serde_impls", ], optional = true } -p256 = "0.13.2" +generic-array = { version = "0.14", features = ["serde"], optional = true } tracing = { version = "0.1", optional = true, default-features = false, features = [ "attributes", ] } diff --git a/crates/bonsaidb-local/src/hpke_util.rs b/crates/bonsaidb-local/src/hpke_util.rs new file mode 100644 index 0000000000..8ec8c92736 --- /dev/null +++ b/crates/bonsaidb-local/src/hpke_util.rs @@ -0,0 +1,51 @@ +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 = ::PublicKey; +pub(crate) type VaultP256PrivateKey = ::PrivateKey; +pub(crate) type VaultP256EncappedKey = ::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 + +// Impl serde for $t: hpke::{Serializable, Deserializable} +macro_rules! impl_serde { + ($modname:ident, $t:ty) => { + pub(crate) mod $modname { + use super::*; + + pub(crate) fn serialize( + val: &$t, + serializer: S, + ) -> Result { + let arr = val.to_bytes(); + arr.serialize(serializer) + } + + pub(crate) fn deserialize<'de, D: Deserializer<'de>>( + deserializer: D, + ) -> Result<$t, D::Error> { + let arr = GenericArray::::OutputSize>::deserialize( + deserializer, + )?; + <$t>::from_bytes(&arr).map_err(D::Error::custom) + } + } + }; +} + +impl_serde!(serde_pubkey, VaultP256PublicKey); +impl_serde!(serde_privkey, VaultP256PrivateKey); +impl_serde!(serde_encapped_key, VaultP256EncappedKey); diff --git a/crates/bonsaidb-local/src/lib.rs b/crates/bonsaidb-local/src/lib.rs index efd4d0c7a1..297c8218fe 100644 --- a/crates/bonsaidb-local/src/lib.rs +++ b/crates/bonsaidb-local/src/lib.rs @@ -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; diff --git a/crates/bonsaidb-local/src/vault.rs b/crates/bonsaidb-local/src/vault.rs index 9e70d8579d..d244dcdf69 100644 --- a/crates/bonsaidb-local/src/vault.rs +++ b/crates/bonsaidb-local/src/vault.rs @@ -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}; @@ -65,8 +70,7 @@ use chacha20poly1305::aead::{Aead, Payload}; use chacha20poly1305::{KeyInit, XChaCha20Poly1305}; 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::{Deserialize, Serialize}; @@ -78,9 +82,11 @@ pub enum KeyPair { /// A P256 keypair. P256 { /// The private key. - private: ::PrivateKey, + #[serde(with = "serde_privkey")] + private: VaultP256PrivateKey, /// The public key. - public: ::PublicKey, + #[serde(with = "serde_pubkey")] + public: VaultP256PublicKey, }, } @@ -100,7 +106,8 @@ impl KeyPair { #[derive(Serialize, Deserialize)] pub enum PublicKey { /// A P256 public key. - P256(::PublicKey), + #[serde(with = "serde_pubkey")] + P256(VaultP256PublicKey), } impl PublicKey { @@ -198,7 +205,7 @@ impl Vault { master_key_storage: Arc, ) -> Result { 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( @@ -226,7 +233,7 @@ impl Vault { let (encapsulated_key, aead_tag) = hpke::single_shot_seal_in_place_detached::< ChaCha20Poly1305, HkdfSha256, - DhP256HkdfSha256, + VaultP256Kem, _, >( &OpModeS::Base, @@ -281,7 +288,7 @@ impl Vault { let master_keys = match &vault_key { KeyPair::P256 { private, .. } => { let mut decryption_context = - hpke::setup_receiver::( + hpke::setup_receiver::( &hpke::OpModeR::Base, private, &encrypted_master_keys.encapsulated_key, @@ -618,7 +625,8 @@ struct HpkePayload { encryption: PublicKeyEncryption, payload: Bytes, tag: [u8; 16], - encapsulated_key: ::EncappedKey, + #[serde(with = "serde_encapped_key")] + encapsulated_key: VaultP256EncappedKey, } #[derive(Serialize, Deserialize)] @@ -657,7 +665,7 @@ mod tests { let mut master_keys = HashMap::new(); master_keys.insert(0, EncryptionKey::random()); - let (_, public_key) = ::gen_keypair(&mut thread_rng()); + let (_, public_key) = ::gen_keypair(&mut thread_rng()); Vault { _vault_public_key: PublicKey::P256(public_key),