-
Notifications
You must be signed in to change notification settings - Fork 31
Migrating away from the serde_impls feature
Since version 0.12, there is no more serde_impls
feature in hpke
. This means that serde::{Serialize, Deserialize}
are no longer implemented for AeadTag
, PublicKey
, or PrivateKey
(for any kem::{PublicKey, PrivateKey}
).
If you were using these serde implementations and absolutely must maintain compatibility with the previous format, here's what you can do.
Note: if you aren't in the situation where you need to maintain compatiblity, you should consider how precisely you want to serialize fixed-length byte sequences in your format. There are a lot of options and it can make a big difference. See the discussion here.
First, import generic_array
. Versions 0.14
and 1.x.x
are fine.
Now suppose you have a struct like
#[derive(Serialize, Deserialize)]
struct HpkeStuff {
public_key: HpkePublicKey,
private_key: HpkePrivateKey,
encapsulated_key: HpkeEncappedKey,
// ...
}
where
type HpkePublicKey = <DhP256HkdfSha256 as Kem>::PublicKey;
type HpkePrivateKey = <DhP256HkdfSha256 as Kem>::PrivateKey;
type HpkeEncappedKey = <DhP256HkdfSha256 as Kem>::EncappedKey;
or something like that.
We will not be able to assume public_key
, private_key
, and encapsulated_key
have serde impls anymore. So we apply a field attribute to tell serde what to do with them. Specifically, we change the struct def to
#[derive(Serialize, Deserialize)]
struct HpkeStuff {
#[serde(with = "serde_pubkey")]
public_key: HpkePublicKey,
#[serde(with = "serde_privkey")]
private_key: HpkePrivateKey,
#[serde(with = "serde_encapped_key")]
encapsulated_key: HpkeEncappedKey,
// ...
}
What are serde_pubkey
and friends? They're modules that we define now:
use generic_array::GenericArray;
use hpke::{
Deserializable, Serializable,
};
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
use zeroize::Zeroize;
// 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.
// 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<S: Serializer>(
val: &$t,
serializer: S,
) -> Result<S::Ok, S::Error> {
let mut arr = val.to_bytes();
let ret = arr.serialize(serializer);
arr.zeroize();
ret
}
pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<$t, D::Error> {
let mut arr = GenericArray::<u8, <$t as Serializable>::OutputSize>::deserialize(
deserializer,
)?;
let ret = <$t>::from_bytes(&arr).map_err(D::Error::custom);
arr.zeroize();
ret
}
}
};
}
impl_serde!(serde_pubkey, HpkePublicKey);
impl_serde!(serde_privkey, HpkePrivateKey);
impl_serde!(serde_encapped_key, HpkeEncappedKey);
And that's it. Now everything should work exactly as before.