1use crate::constants::SECURITY_PARAMETER;
16use crate::payload::key::{PayloadKey, SphinxPayloadKey};
17use crate::{Error, ErrorKind, Result};
18use blake2::VarBlake2b;
19use chacha::ChaCha; use lioness::Lioness;
21use std::borrow::Borrow;
22
23pub mod key;
24
25pub const PAYLOAD_OVERHEAD_SIZE: usize = SECURITY_PARAMETER + 1;
28
29#[derive(Debug)]
32#[cfg_attr(test, derive(PartialEq))]
33pub struct Payload(Vec<u8>);
34
35#[allow(clippy::len_without_is_empty)]
37impl Payload {
38 pub fn encapsulate_message<K>(
42 plaintext_message: &[u8],
43 payload_keys: &[K],
44 payload_size: usize,
45 ) -> Result<Self>
46 where
47 K: for<'a> SphinxPayloadKey<'a>,
48 {
49 Self::validate_parameters(payload_size, plaintext_message.len())?;
50 let mut payload = Self::set_final_payload(plaintext_message, payload_size);
51
52 for payload_key in payload_keys.iter().rev() {
54 payload = payload.add_encryption_layer(payload_key.payload_key())?;
55 }
56
57 Ok(payload)
58 }
59
60 fn validate_parameters(payload_size: usize, plaintext_len: usize) -> Result<()> {
64 if payload_size < PAYLOAD_OVERHEAD_SIZE {
65 return Err(Error::new(
66 ErrorKind::InvalidPayload,
67 "specified payload_size is smaller than the required overhead",
68 ));
69 } else if payload_size < lioness::DIGEST_RESULT_SIZE {
73 return Err(Error::new(
74 ErrorKind::InvalidPayload,
75 "specified payload_size is smaller lioness block size",
76 ));
77 }
78
79 let maximum_plaintext_length = payload_size - PAYLOAD_OVERHEAD_SIZE;
80 if plaintext_len > maximum_plaintext_length {
81 return Err(Error::new(
82 ErrorKind::InvalidPayload,
83 format!(
84 "too long message provided. Message was: {}B long, maximum_plaintext_length is: {}B",
85 plaintext_len,
86 maximum_plaintext_length
87 ),
88 ));
89 }
90 Ok(())
91 }
92
93 fn set_final_payload(plaintext_message: &[u8], payload_size: usize) -> Self {
97 let final_payload: Vec<u8> = std::iter::repeat_n(0u8, SECURITY_PARAMETER) .chain(plaintext_message.iter().copied()) .chain(std::iter::once(1)) .chain(std::iter::repeat(0u8)) .take(payload_size) .collect();
103
104 Payload(final_payload)
105 }
106
107 fn add_encryption_layer<P: Borrow<PayloadKey>>(mut self, payload_key: P) -> Result<Self> {
109 let lioness_cipher = Lioness::<VarBlake2b, ChaCha>::new_raw(payload_key.borrow());
110
111 if let Err(err) = lioness_cipher.encrypt(&mut self.0) {
112 return Err(Error::new(
113 ErrorKind::InvalidPayload,
114 format!("error while encrypting payload - {}", err),
115 ));
116 };
117 Ok(self)
118 }
119
120 pub fn unwrap<P: Borrow<PayloadKey>>(mut self, payload_key: P) -> Result<Self> {
122 let lioness_cipher = Lioness::<VarBlake2b, ChaCha>::new_raw(payload_key.borrow());
123
124 if let Err(err) = lioness_cipher.decrypt(&mut self.0) {
125 return Err(Error::new(
126 ErrorKind::InvalidPayload,
127 format!("error while unwrapping payload - {}", err),
128 ));
129 };
130 Ok(self)
131 }
132
133 fn find_start_of_padding(&self) -> Result<usize> {
137 let padded_plaintext = &self.0[SECURITY_PARAMETER..];
138 padded_plaintext
139 .iter()
140 .rposition(|b| *b == 1)
141 .ok_or(Error::new(
142 ErrorKind::InvalidPayload,
143 "malformed payload - invalid trailing padding",
144 ))
145 }
146
147 pub fn recover_plaintext(self) -> Result<Vec<u8>> {
150 if self.len() < PAYLOAD_OVERHEAD_SIZE {
151 return Err(Error::new(
152 ErrorKind::InvalidPayload,
153 "malformed payload - no leading zero padding present",
154 ));
155 }
156
157 if !self.0.iter().take(SECURITY_PARAMETER).all(|b| *b == 0) {
168 return Err(Error::new(
169 ErrorKind::InvalidPayload,
170 "malformed payload - no leading zero padding present",
171 ));
172 }
173
174 let padding_start = self.find_start_of_padding()?;
175 Ok(self
179 .into_inner()
180 .into_iter()
181 .skip(SECURITY_PARAMETER)
182 .take(padding_start)
183 .collect())
184 }
185
186 fn into_inner(self) -> Vec<u8> {
187 self.0
188 }
189
190 fn inner(&self) -> &[u8] {
191 &self.0
192 }
193
194 pub fn len(&self) -> usize {
195 self.0.len()
196 }
197
198 pub fn as_bytes(&self) -> &[u8] {
200 self.inner()
201 }
202
203 pub fn into_bytes(self) -> Vec<u8> {
205 self.into_inner()
206 }
207
208 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
210 if bytes.len() < PAYLOAD_OVERHEAD_SIZE {
213 return Err(Error::new(
214 ErrorKind::InvalidPayload,
215 "too short payload provided",
216 ));
217 }
218
219 Ok(Payload(bytes.to_vec()))
220 }
221}
222
223#[cfg(test)]
224mod building_payload_from_bytes {
225 use super::*;
226
227 #[test]
228 fn from_bytes_returns_error_if_bytes_are_too_short() {
229 let bytes = [0u8; 1].to_vec();
230 let expected = ErrorKind::InvalidPayload;
231 match Payload::from_bytes(&bytes) {
232 Err(err) => assert_eq!(expected, err.kind()),
233 _ => panic!("Should have returned an error when packet bytes too short"),
234 };
235 }
236}
237
238#[cfg(test)]
239mod parameter_verification {
240 use super::*;
241
242 #[test]
243 fn it_returns_an_error_if_payload_size_is_smaller_than_the_overhead() {
244 assert!(Payload::validate_parameters(PAYLOAD_OVERHEAD_SIZE - 1, 16).is_err());
245 }
246
247 #[test]
248 fn it_returns_an_error_if_payload_size_is_smaller_than_the_lioness_blocklen() {
249 assert!(Payload::validate_parameters(lioness::DIGEST_RESULT_SIZE - 1, 16).is_err());
250 }
251
252 #[test]
253 fn it_returns_an_error_if_message_is_longer_than_maximum_allowed_length() {
254 let payload_length = 100;
255 let max_allowed_length = payload_length - PAYLOAD_OVERHEAD_SIZE;
256 assert!(Payload::validate_parameters(payload_length, max_allowed_length + 1).is_err());
257 }
258}
259
260#[cfg(test)]
261mod final_payload_setting {
262 use super::*;
263
264 #[test]
265 fn adds_correct_padding() {
266 let plaintext_lengths = vec![0, 1, 16, 128, 4096];
267 for plaintext_length in plaintext_lengths {
268 let payload_size = plaintext_length + lioness::DIGEST_RESULT_SIZE;
270 let final_payload =
271 Payload::set_final_payload(&vec![42u8; plaintext_length], payload_size);
272 let final_payload_inner = final_payload.into_inner();
273
274 assert!(final_payload_inner
276 .iter()
277 .take(SECURITY_PARAMETER)
278 .all(|&b| b == 0));
279 assert!(final_payload_inner
281 .iter()
282 .skip(SECURITY_PARAMETER)
283 .take(plaintext_length)
284 .all(|&b| b == 42));
285 assert_eq!(
287 final_payload_inner[SECURITY_PARAMETER + plaintext_length],
288 1
289 );
290 assert!(final_payload_inner
292 .iter()
293 .skip(SECURITY_PARAMETER + plaintext_length + 1)
294 .all(|&b| b == 0))
295 }
296 }
297}
298
299#[cfg(test)]
300mod test_encapsulating_payload {
301 use super::*;
302 use crate::constants::PAYLOAD_KEY_SIZE;
303
304 #[test]
305 fn works_with_single_encryption_layer() {
306 let message = vec![1u8, 16];
307 let payload_size = 512;
308 let payload_key_1 = [3u8; PAYLOAD_KEY_SIZE];
309
310 assert!(Payload::encapsulate_message(&message, &[payload_key_1], payload_size).is_ok())
311 }
312
313 #[test]
314 fn works_with_five_encryption_layers() {
315 let message = vec![1u8, 16];
316 let payload_size = 512;
317 let payload_key_1 = [3u8; PAYLOAD_KEY_SIZE];
318 let payload_key_2 = [4u8; PAYLOAD_KEY_SIZE];
319 let payload_key_3 = [5u8; PAYLOAD_KEY_SIZE];
320 let payload_key_4 = [6u8; PAYLOAD_KEY_SIZE];
321 let payload_key_5 = [7u8; PAYLOAD_KEY_SIZE];
322
323 assert!(Payload::encapsulate_message(
324 &message,
325 &[
326 payload_key_1,
327 payload_key_2,
328 payload_key_3,
329 payload_key_4,
330 payload_key_5
331 ],
332 payload_size
333 )
334 .is_ok())
335 }
336}
337
338#[cfg(test)]
339mod test_unwrapping_payload {
340 use super::*;
341 use crate::constants::{PAYLOAD_KEY_SIZE, SECURITY_PARAMETER};
342 use crate::packet::builder::DEFAULT_PAYLOAD_SIZE;
343
344 #[test]
345 fn unwrapping_results_in_original_payload_plaintext() {
346 let message = vec![42u8; 16];
347 let payload_key_1 = [3u8; PAYLOAD_KEY_SIZE];
348 let payload_key_2 = [4u8; PAYLOAD_KEY_SIZE];
349 let payload_key_3 = [5u8; PAYLOAD_KEY_SIZE];
350 let payload_keys = [payload_key_1, payload_key_2, payload_key_3];
351
352 let encrypted_payload =
353 Payload::encapsulate_message(&message, &payload_keys, DEFAULT_PAYLOAD_SIZE).unwrap();
354
355 let unwrapped_payload = payload_keys
356 .iter()
357 .fold(encrypted_payload, |current_layer, payload_key| {
358 current_layer.unwrap(payload_key).unwrap()
359 });
360
361 let zero_bytes = vec![0u8; SECURITY_PARAMETER];
362 let additional_padding =
363 vec![0u8; DEFAULT_PAYLOAD_SIZE - PAYLOAD_OVERHEAD_SIZE - message.len()];
364 let expected_payload = [zero_bytes, message, vec![1], additional_padding].concat();
365 assert_eq!(expected_payload, unwrapped_payload.into_inner());
366 }
367}
368
369#[cfg(test)]
370mod plaintext_recovery {
371 use super::*;
372 use crate::constants::PAYLOAD_KEY_SIZE;
373 use crate::packet::builder::DEFAULT_PAYLOAD_SIZE;
374
375 #[test]
376 fn it_is_possible_to_recover_plaintext_from_valid_payload() {
377 let message = vec![42u8; 160];
378
379 let payload_key_1 = [3u8; PAYLOAD_KEY_SIZE];
380 let payload_key_2 = [4u8; PAYLOAD_KEY_SIZE];
381 let payload_key_3 = [5u8; PAYLOAD_KEY_SIZE];
382 let payload_keys = [payload_key_1, payload_key_2, payload_key_3];
383
384 let encrypted_payload =
385 Payload::encapsulate_message(&message, &payload_keys, DEFAULT_PAYLOAD_SIZE).unwrap();
386
387 let unwrapped_payload = payload_keys
388 .iter()
389 .fold(encrypted_payload, |current_layer, payload_key| {
390 current_layer.unwrap(payload_key).unwrap()
391 });
392
393 let recovered_plaintext = unwrapped_payload.recover_plaintext().unwrap();
394
395 assert_eq!(message, recovered_plaintext);
396 }
397
398 #[test]
400 fn it_is_possible_to_recover_plaintext_even_if_is_just_ones() {
401 let message = vec![1u8; 160];
402
403 let payload_key_1 = [3u8; PAYLOAD_KEY_SIZE];
404 let payload_key_2 = [4u8; PAYLOAD_KEY_SIZE];
405 let payload_key_3 = [5u8; PAYLOAD_KEY_SIZE];
406 let payload_keys = [payload_key_1, payload_key_2, payload_key_3];
407
408 let encrypted_payload =
409 Payload::encapsulate_message(&message, &payload_keys, DEFAULT_PAYLOAD_SIZE).unwrap();
410
411 let unwrapped_payload = payload_keys
412 .iter()
413 .fold(encrypted_payload, |current_layer, payload_key| {
414 current_layer.unwrap(payload_key).unwrap()
415 });
416
417 let recovered_plaintext = unwrapped_payload.recover_plaintext().unwrap();
418
419 assert_eq!(message, recovered_plaintext);
420 }
421
422 #[test]
424 fn it_is_possible_to_recover_plaintext_even_if_is_just_zeroes() {
425 let message = vec![0u8; 160];
426
427 let payload_key_1 = [3u8; PAYLOAD_KEY_SIZE];
428 let payload_key_2 = [4u8; PAYLOAD_KEY_SIZE];
429 let payload_key_3 = [5u8; PAYLOAD_KEY_SIZE];
430 let payload_keys = [payload_key_1, payload_key_2, payload_key_3];
431
432 let encrypted_payload =
433 Payload::encapsulate_message(&message, &payload_keys, DEFAULT_PAYLOAD_SIZE).unwrap();
434
435 let unwrapped_payload = payload_keys
436 .iter()
437 .fold(encrypted_payload, |current_layer, payload_key| {
438 current_layer.unwrap(payload_key).unwrap()
439 });
440
441 let recovered_plaintext = unwrapped_payload.recover_plaintext().unwrap();
442
443 assert_eq!(message, recovered_plaintext);
444 }
445
446 #[test]
447 fn it_fails_to_recover_plaintext_from_invalid_payload() {
448 let message = vec![42u8; 160];
449
450 let payload_key_1 = [3u8; PAYLOAD_KEY_SIZE];
451 let payload_key_2 = [4u8; PAYLOAD_KEY_SIZE];
452 let payload_key_3 = [5u8; PAYLOAD_KEY_SIZE];
453 let payload_keys = [payload_key_1, payload_key_2, payload_key_3];
454
455 let encrypted_payload =
456 Payload::encapsulate_message(&message, &payload_keys, DEFAULT_PAYLOAD_SIZE).unwrap();
457
458 let unwrapped_payload = payload_keys
459 .iter()
460 .skip(1) .fold(encrypted_payload, |current_layer, payload_key| {
462 current_layer.unwrap(payload_key).unwrap()
463 });
464
465 assert!(unwrapped_payload.recover_plaintext().is_err())
466 }
467
468 #[test]
469 fn it_fails_to_recover_plaintext_from_incorrectly_constructed_payload() {
470 let zero_payload = Payload(vec![0u8; DEFAULT_PAYLOAD_SIZE]);
471
472 assert!(zero_payload.recover_plaintext().is_err());
473 }
474}