nym_sphinx/
receiver.rs

1// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::message::{NymMessage, NymMessageError, PaddedMessage, PlainMessage};
5use nym_crypto::aes::cipher::{KeyIvInit, StreamCipher};
6use nym_crypto::asymmetric::x25519;
7use nym_crypto::shared_key::recompute_shared_key;
8use nym_crypto::symmetric::stream_cipher;
9use nym_crypto::symmetric::stream_cipher::CipherKey;
10use nym_sphinx_anonymous_replies::SurbEncryptionKey;
11use nym_sphinx_anonymous_replies::requests::AnonymousSenderTag;
12use nym_sphinx_chunking::ChunkingError;
13use nym_sphinx_chunking::fragment::Fragment;
14use nym_sphinx_chunking::reconstruction::MessageReconstructor;
15use nym_sphinx_params::{
16    PacketEncryptionAlgorithm, PacketHkdfAlgorithm, ReplySurbEncryptionAlgorithm,
17};
18use thiserror::Error;
19
20// TODO: should this live in this file?
21#[derive(Debug)]
22pub struct ReconstructedMessage {
23    /// The actual plaintext message that was received.
24    pub message: Vec<u8>,
25
26    /// Optional ephemeral sender tag indicating pseudo-identity of the party who sent us the message
27    /// (alongside any reply SURBs)
28    pub sender_tag: Option<AnonymousSenderTag>,
29}
30
31impl From<ReconstructedMessage> for (Vec<u8>, Option<AnonymousSenderTag>) {
32    fn from(msg: ReconstructedMessage) -> Self {
33        (msg.message, msg.sender_tag)
34    }
35}
36
37impl ReconstructedMessage {
38    pub fn new(message: Vec<u8>, sender_tag: AnonymousSenderTag) -> Self {
39        Self {
40            message,
41            sender_tag: Some(sender_tag),
42        }
43    }
44
45    pub fn into_inner(self) -> (Vec<u8>, Option<AnonymousSenderTag>) {
46        self.into()
47    }
48}
49
50impl From<PlainMessage> for ReconstructedMessage {
51    fn from(message: PlainMessage) -> Self {
52        ReconstructedMessage {
53            message,
54            sender_tag: None,
55        }
56    }
57}
58
59#[derive(Debug, Error)]
60pub enum MessageRecoveryError {
61    #[error(
62        "The received message did not contain enough bytes to recover the ephemeral public key. Got {provided}. required: {required}"
63    )]
64    NotEnoughBytesForEphemeralKey { provided: usize, required: usize },
65
66    #[error("Recovered remote x25519 public key is invalid - {0}")]
67    InvalidRemoteEphemeralKey(#[from] x25519::KeyRecoveryError),
68
69    #[error("The reconstructed message was malformed - {source}")]
70    MalformedReconstructedMessage {
71        #[source]
72        source: NymMessageError,
73        used_sets: Vec<i32>,
74    },
75
76    #[error("Failed to recover message fragment - {0}")]
77    FragmentRecoveryError(#[from] ChunkingError),
78}
79
80pub trait MessageReceiver {
81    fn new() -> Self;
82    fn reconstructor(&mut self) -> &mut MessageReconstructor;
83
84    fn decrypt_raw_message<C>(
85        &self,
86        message: &mut [u8],
87        key: &CipherKey<C>,
88    ) -> Result<(), MessageRecoveryError>
89    where
90        C: StreamCipher + KeyIvInit;
91
92    fn recover_plaintext_from_reply(
93        &self,
94        reply_ciphertext: &mut [u8],
95        reply_key: SurbEncryptionKey,
96    ) -> Result<(), MessageRecoveryError> {
97        self.decrypt_raw_message::<ReplySurbEncryptionAlgorithm>(
98            reply_ciphertext,
99            reply_key.inner(),
100        )
101    }
102
103    fn recover_plaintext_from_regular_packet<'a>(
104        &self,
105        local_key: &x25519::PrivateKey,
106        raw_enc_frag: &'a mut [u8],
107    ) -> Result<&'a mut [u8], MessageRecoveryError> {
108        if raw_enc_frag.len() < x25519::PUBLIC_KEY_SIZE {
109            return Err(MessageRecoveryError::NotEnoughBytesForEphemeralKey {
110                provided: raw_enc_frag.len(),
111                required: x25519::PUBLIC_KEY_SIZE,
112            });
113        }
114
115        // 1. recover remote encryption key
116        let remote_key_bytes = &raw_enc_frag[..x25519::PUBLIC_KEY_SIZE];
117        let remote_ephemeral_key = x25519::PublicKey::from_bytes(remote_key_bytes)?;
118
119        // 2. recompute shared encryption key
120        let encryption_key = recompute_shared_key::<PacketEncryptionAlgorithm, PacketHkdfAlgorithm>(
121            &remote_ephemeral_key,
122            local_key,
123        );
124
125        // 3. decrypt fragment data
126        let fragment_ciphertext = &mut raw_enc_frag[x25519::PUBLIC_KEY_SIZE..];
127
128        self.decrypt_raw_message::<PacketEncryptionAlgorithm>(
129            fragment_ciphertext,
130            &encryption_key,
131        )?;
132        let fragment_data = fragment_ciphertext;
133
134        Ok(fragment_data)
135    }
136
137    fn recover_fragment(&self, frag_data: &[u8]) -> Result<Fragment, MessageRecoveryError> {
138        Ok(Fragment::try_from_bytes(frag_data)?)
139    }
140
141    fn insert_new_fragment(
142        &mut self,
143        fragment: Fragment,
144    ) -> Result<Option<(NymMessage, Vec<i32>)>, MessageRecoveryError> {
145        if let Some((message, used_sets)) = self.reconstructor().insert_new_fragment(fragment) {
146            match PaddedMessage::new_reconstructed(message).remove_padding() {
147                Ok(message) => Ok(Some((message, used_sets))),
148                Err(err) => Err(MessageRecoveryError::MalformedReconstructedMessage {
149                    source: err,
150                    used_sets,
151                }),
152            }
153        } else {
154            Ok(None)
155        }
156    }
157}
158
159#[derive(Clone, Default)]
160pub struct SphinxMessageReceiver {
161    /// High level public structure used to buffer all received data [`Fragment`]s and eventually
162    /// returning original messages that they encapsulate.
163    reconstructor: MessageReconstructor,
164}
165
166impl MessageReceiver for SphinxMessageReceiver {
167    fn new() -> Self {
168        Default::default()
169    }
170
171    fn decrypt_raw_message<C>(
172        &self,
173        message: &mut [u8],
174        key: &CipherKey<C>,
175    ) -> Result<(), MessageRecoveryError>
176    where
177        C: StreamCipher + KeyIvInit,
178    {
179        let zero_iv = stream_cipher::zero_iv::<C>();
180        stream_cipher::decrypt_in_place::<C>(key, &zero_iv, message);
181        Ok(())
182    }
183
184    fn reconstructor(&mut self) -> &mut MessageReconstructor {
185        &mut self.reconstructor
186    }
187}