diff --git a/waku/src/decrypt.rs b/waku/src/decrypt.rs new file mode 100644 index 0000000..23e9c7f --- /dev/null +++ b/waku/src/decrypt.rs @@ -0,0 +1,63 @@ +// std +use std::ffi::{CStr, CString}; +// crates +use aes_gcm::{Aes256Gcm, Key}; +use libsecp256k1::SecretKey; +// internal +use crate::general::{DecodedPayload, JsonResponse, Result, WakuMessage}; + +/// Decrypt a message using a symmetric key +/// +/// As per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_decode_symmetricchar-messagejson-char-symmetrickey) +pub fn waku_decode_symmetric( + message: &WakuMessage, + symmetric_key: &Key, +) -> Result { + let symk = hex::encode(symmetric_key.as_slice()); + let result = unsafe { + CStr::from_ptr(waku_sys::waku_decode_symmetric( + CString::new( + serde_json::to_string(&message) + .expect("WakuMessages should always be able to success serializing"), + ) + .expect("CString should build properly from the serialized waku message") + .into_raw(), + CString::new(symk) + .expect("CString should build properly from hex encoded symmetric key") + .into_raw(), + )) + } + .to_str() + .expect("Response should always succeed to load to a &str"); + let response: JsonResponse = + serde_json::from_str(result).expect("JsonResponse should always succeed to deserialize"); + response.into() +} + +/// Decrypt a message using a symmetric key +/// +/// As per the [specification](extern char* waku_decode_asymmetric(char* messageJson, char* privateKey)) +pub fn waku_decode_asymmetric( + message: &WakuMessage, + asymmetric_key: &SecretKey, +) -> Result { + let sk = hex::encode(asymmetric_key.serialize()); + let result = unsafe { + CStr::from_ptr(waku_sys::waku_decode_asymmetric( + CString::new( + serde_json::to_string(&message) + .expect("WakuMessages should always be able to success serializing"), + ) + .expect("CString should build properly from the serialized waku message") + .into_raw(), + CString::new(sk) + .expect("CString should build properly from hex encoded symmetric key") + .into_raw(), + )) + } + .to_str() + .expect("Response should always succeed to load to a &str"); + let response: JsonResponse = + serde_json::from_str(result).expect("JsonResponse should always succeed to deserialize"); + response.into() +} diff --git a/waku/src/general/mod.rs b/waku/src/general/mod.rs index ffa3c70..1a6d123 100644 --- a/waku/src/general/mod.rs +++ b/waku/src/general/mod.rs @@ -4,9 +4,12 @@ use std::fmt::{Display, Formatter}; use std::str::FromStr; // crates +use aes_gcm::{Aes256Gcm, Key}; +use libsecp256k1::SecretKey; use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; use sscanf::{scanf, RegexRepresentation}; // internal +use crate::decrypt::{waku_decode_asymmetric, waku_decode_symmetric}; pub type WakuMessageVersion = usize; /// Base58 encoded peer id @@ -36,7 +39,7 @@ impl From> for Result { } } -/// JsonMessage, Waku message in JSON format. +/// Waku message in JSON format. /// as per the [specification](https://rfc.vac.dev/spec/36/#jsonmessage-type) #[derive(Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -50,7 +53,25 @@ pub struct WakuMessage { timestamp: usize, } +impl WakuMessage { + /// Try decode the message with an expected symmetric key + /// + /// wrapper around [`crate::decrypt::waku_decode_symmetric`] + pub fn try_decode_symmetric(&self, symmetric_key: &Key) -> Result { + waku_decode_symmetric(self, symmetric_key) + } + + /// Try decode the message with an expected asymmetric key + /// + /// wrapper around [`crate::decrypt::waku_decode_asymmetric`] + pub fn try_decode_asymmentric(&self, asymmetric_key: &SecretKey) -> Result { + waku_decode_asymmetric(self, asymmetric_key) + } +} + /// A payload once decoded, used when a received Waku Message is encrypted +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] pub struct DecodedPayload { /// Public key that signed the message (optional), hex encoded with 0x prefix public_key: Option, diff --git a/waku/src/lib.rs b/waku/src/lib.rs index 3494379..1ea19a0 100644 --- a/waku/src/lib.rs +++ b/waku/src/lib.rs @@ -1,3 +1,4 @@ +mod decrypt; mod events; mod general; mod node; diff --git a/waku/src/node/filter.rs b/waku/src/node/filter.rs index e4ccedb..c2d3bc4 100644 --- a/waku/src/node/filter.rs +++ b/waku/src/node/filter.rs @@ -7,7 +7,7 @@ use std::time::Duration; // internal use crate::general::Result; -use crate::general::{FilterSubscription, JsonResponse, MessageId, PeerId}; +use crate::general::{FilterSubscription, JsonResponse, PeerId}; /// Creates a subscription in a lightnode for messages that matches a content filter and optionally a [`WakuPubSubTopic`](`crate::general::WakuPubSubTopic`) /// As per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_filter_subscribechar-filterjson-char-peerid-int-timeoutms)