Skip to content

Commit

Permalink
Delete verbose serde impl where macros do
Browse files Browse the repository at this point in the history
Almost all of the replaced field serializers have serde impls so macros just work.
  • Loading branch information
DanGould committed Sep 8, 2024
1 parent 31604d2 commit 827b719
Show file tree
Hide file tree
Showing 3 changed files with 250 additions and 267 deletions.
234 changes: 234 additions & 0 deletions payjoin/src/hpke.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
use core::fmt;

use hpke::Kem;
use hpke::{aead::ChaCha20Poly1305, kem::SecpK256HkdfSha256};
use hpke::{kdf::HkdfSha256, rand_core::OsRng};

pub const PADDED_MESSAGE_BYTES: usize = 7168; // 7KB
pub const INFO_A: &[u8] = b"Payjoin v2 Message A";
pub const INFO_B: &[u8] = b"Payjoin v2 Message B";

#[derive(Clone, PartialEq, Eq)]
pub struct HpkeSecretKey(pub <SecpK256HkdfSha256 as hpke::Kem>::PrivateKey);

impl core::fmt::Debug for HpkeSecretKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use hpke::Serializable;
write!(f, "SecpHpkeSecretKey")
}
}

impl serde::Serialize for HpkeSecretKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use hpke::Serializable;
serializer.serialize_bytes(&self.0.to_bytes().to_vec())
}
}

impl<'de> serde::Deserialize<'de> for HpkeSecretKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use hpke::Deserializable;
let bytes = Vec::<u8>::deserialize(deserializer)?;
Ok(HpkeSecretKey(<SecpK256HkdfSha256 as hpke::Kem>::PrivateKey::from_bytes(&bytes).map_err(|_| serde::de::Error::custom("Invalid secret key"))?))
}
}

#[derive(Clone, PartialEq, Eq)]
pub struct HpkePublicKey(pub <SecpK256HkdfSha256 as hpke::Kem>::PublicKey);

impl core::fmt::Debug for HpkePublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SecpHpkePublicKey({:?})", self.0)
}
}

impl serde::Serialize for HpkePublicKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use hpke::Serializable;
serializer.serialize_bytes(&self.0.to_bytes().to_vec())
}
}

impl<'de> serde::Deserialize<'de> for HpkePublicKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use hpke::Deserializable;
let bytes = Vec::<u8>::deserialize(deserializer)?;
Ok(HpkePublicKey(<SecpK256HkdfSha256 as hpke::Kem>::PublicKey::from_bytes(&bytes).map_err(|_| serde::de::Error::custom("Invalid public key"))?))
}
}

#[cfg(feature = "send")]
pub fn encrypt_message_a_hpke(
plaintext: Vec<u8>,
e_sec: &HpkeSecretKey,
rs: &HpkePublicKey,
) -> Result<Vec<u8>, HpkeError> {
use hpke::{OpModeS, Serializable};

let pk = <SecpK256HkdfSha256 as hpke::Kem>::sk_to_pk(&e_sec.0);
let (encapsulated_key, mut encryption_context) = hpke::setup_sender::<
ChaCha20Poly1305,
HkdfSha256,
SecpK256HkdfSha256,
_,
>(&OpModeS::Auth((e_sec.0.clone(), pk.clone())), &rs.0, INFO_A, &mut OsRng)?;
let aad = pk.to_bytes().to_vec();
let ciphertext: Vec<u8> = encryption_context.seal(&plaintext, &aad)?;
let mut message_a = encapsulated_key.to_bytes().to_vec();
message_a.extend(&aad);
message_a.extend(&ciphertext);
//TODO let message_a = pad(&mut message_a).expect("TODO: handle error");
Ok(message_a.to_vec())
}

#[cfg(feature = "receive")]
pub fn decrypt_message_a_hpke(
message_a: &[u8],
s: HpkeSecretKey,
) -> Result<(Vec<u8>, <SecpK256HkdfSha256 as hpke::Kem>::EncappedKey), HpkeError> {
use hpke::{OpModeR, Deserializable};
// Extract the encapsulated key (65 bytes)
let enc = message_a.get(..65).ok_or(HpkeError::PayloadTooShort)?;
let enc = <SecpK256HkdfSha256 as hpke::Kem>::EncappedKey::from_bytes(enc)?;

// Extract the sender's public key (AAD, 65 bytes)
let aad = message_a.get(65..130).ok_or(HpkeError::PayloadTooShort)?;
let pk_s = <SecpK256HkdfSha256 as hpke::Kem>::PublicKey::from_bytes(aad)?;

let mut decryption_ctx = hpke::setup_receiver::<
ChaCha20Poly1305,
HkdfSha256,
SecpK256HkdfSha256,
>(&OpModeR::Auth(pk_s), &s.0, &enc, INFO_A)?;

// The ciphertext is the remainder of the message
let ciphertext = message_a.get(130..).ok_or(HpkeError::PayloadTooShort)?;
let plaintext = decryption_ctx.open(ciphertext, aad)?;

Ok((plaintext, enc))
}

// #[cfg(feature = "receive")]
// pub fn encrypt_message_b(raw_msg: &mut Vec<u8>, re_pub: PublicKey) -> Result<Vec<u8>, HpkeError> {
// // let message b = [pubkey/AD][nonce][authentication tag][ciphertext]
// let secp = Secp256k1::new();
// let (e_sec, e_pub) = secp.generate_keypair(&mut OsRng);
// let ee = SharedSecret::new(&re_pub, &e_sec);
// let cipher = ChaCha20Poly1305::new_from_slice(&ee.secret_bytes())
// .map_err(|_| HpkeError::InvalidKeyLength)?;
// let nonce = Nonce::from_slice(&[0u8; 12]); // key es encrypts only 1 message so 0 is unique
// let aad = &e_pub.serialize();
// let msg = pad(raw_msg)?;
// let payload = Payload { msg, aad };
// let c_t = cipher.encrypt(nonce, payload)?;
// let mut message_b = e_pub.serialize().to_vec();
// message_b.extend(&nonce[..]);
// message_b.extend(&c_t[..]);
// Ok(message_b)
// }

#[cfg(feature = "receive")]
pub fn encrypt_message_b_hpke(
plaintext: Vec<u8>,
s_pair: (HpkeSecretKey, HpkePublicKey),
re_pub: &HpkePublicKey,
) -> Result<Vec<u8>, HpkeError> {
use hpke::{OpModeS, Serializable};

let (encapsulated_key, mut encryption_context) = hpke::setup_sender::<
ChaCha20Poly1305,
HkdfSha256,
SecpK256HkdfSha256,
_,
>(&OpModeS::Auth((s_pair.0.0, s_pair.1.0.clone())), &re_pub.0, INFO_B, &mut OsRng)?;
let aad = s_pair.1.0.to_bytes().to_vec();
let ciphertext: Vec<u8> = encryption_context.seal(&plaintext, &aad)?;
let mut message_b = encapsulated_key.to_bytes().to_vec();
println!("message_b encapped_key: {:?}", message_b);
message_b.extend(&aad);
message_b.extend(&ciphertext);
//let message_b = pad(&mut message_b).expect("TODO: handle error");
Ok(message_b.to_vec())
}

#[cfg(feature = "send")]
pub fn decrypt_message_b_hpke(
message_b: &[u8],
s: HpkeSecretKey,
) -> Result<Vec<u8>, HpkeError> {
use hpke::{OpModeR, Deserializable, Serializable};

let enc = message_b.get(..65).ok_or(HpkeError::PayloadTooShort)?;
println!("message_b enc: {:?}", enc);
let enc = <SecpK256HkdfSha256 as hpke::Kem>::EncappedKey::from_bytes(&enc).unwrap();
let aad = message_b.get(65..130).ok_or(HpkeError::PayloadTooShort)?;
let pk_s = <SecpK256HkdfSha256 as hpke::Kem>::PublicKey::from_bytes(aad).unwrap();
let mut decryption_ctx = hpke::setup_receiver::<
ChaCha20Poly1305,
HkdfSha256,
SecpK256HkdfSha256,
>(&OpModeR::Auth(pk_s), &s.0, &enc, INFO_B)?;

let plaintext = decryption_ctx.open(message_b.get(130..).ok_or(HpkeError::PayloadTooShort)?, &aad)?;
Ok(plaintext)
}

fn pad(msg: &mut Vec<u8>) -> Result<&[u8], HpkeError> {
if msg.len() > PADDED_MESSAGE_BYTES {
return Err(HpkeError::PayloadTooLarge);
}
while msg.len() < PADDED_MESSAGE_BYTES {
msg.push(0);
}
Ok(msg)
}

/// Error from de/encrypting a v2 Hybrid Public Key Encryption payload.
#[derive(Debug)]
pub enum HpkeError {
Hpke(hpke::HpkeError),
InvalidKeyLength,
PayloadTooLarge,
PayloadTooShort,
}

impl From<hpke::HpkeError> for HpkeError {
fn from(value: hpke::HpkeError) -> Self { Self::Hpke(value) }
}

impl fmt::Display for HpkeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use HpkeError::*;

match &self {
Hpke(e) => e.fmt(f),
InvalidKeyLength => write!(f, "Invalid Length"),
PayloadTooLarge =>
write!(f, "Payload too large, max size is {} bytes", PADDED_MESSAGE_BYTES),
PayloadTooShort => write!(f, "Payload too small"),
}
}
}

impl std::error::Error for HpkeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use HpkeError::*;

match &self {
Hpke(e) => Some(e),
InvalidKeyLength | PayloadTooLarge | PayloadTooShort => None,
}
}
}
Loading

0 comments on commit 827b719

Please sign in to comment.