1use crate::{
65 identity::{BareIdKey, IdentityKey},
66 lockbox::*,
67 stream::{stream_key_encrypt, BareStreamKey, StreamKey},
68 CryptoError, CryptoSrc,
69};
70
71use chacha20poly1305::KeyInit;
72use rand_core::{CryptoRng, RngCore};
73
74use zeroize::Zeroize;
75
76use std::{convert::TryFrom, fmt, sync::Arc};
77
78pub const DEFAULT_LOCK_VERSION: u8 = 1;
80
81pub const MIN_LOCK_VERSION: u8 = 1;
83
84pub const MAX_LOCK_VERSION: u8 = 1;
86
87const V1_LOCK_ID_SIZE: usize = 32; const V1_LOCK_KEY_SIZE: usize = 32; pub(crate) fn lock_id_size(_version: u8) -> usize {
91 1 + V1_LOCK_ID_SIZE
92}
93
94pub(crate) fn lock_eph_size(_version: u8) -> usize {
95 V1_LOCK_ID_SIZE
96}
97
98#[derive(Clone)]
129pub struct LockKey {
130 interface: Arc<dyn LockInterface>,
131}
132
133#[cfg(feature = "getrandom")]
134impl Default for LockKey {
135 fn default() -> Self {
136 Self::new()
137 }
138}
139
140impl LockKey {
141
142 pub fn from_interface(interface: Arc<dyn LockInterface>) -> Self {
145 Self { interface }
146 }
147
148 pub fn new() -> LockKey {
150 let interface = Arc::new(BareLockKey::new());
151 Self::from_interface(interface)
152 }
153
154 pub fn with_rng<R>(csprng: &mut R) -> LockKey
157 where
158 R: CryptoRng + RngCore,
159 {
160 let interface = Arc::new(BareLockKey::with_rng(csprng));
161 Self::from_interface(interface)
162 }
163
164 pub fn with_rng_and_version<R>(csprng: &mut R, version: u8) -> Result<LockKey, CryptoError>
167 where
168 R: CryptoRng + RngCore,
169 {
170 let interface = Arc::new(BareLockKey::with_rng_and_version(csprng, version)?);
171 Ok(Self::from_interface(interface))
172 }
173
174 pub fn version(&self) -> u8 {
176 self.interface.id().version()
177 }
178
179 pub fn id(&self) -> &LockId {
181 self.interface.id()
182 }
183
184 pub fn decrypt_lock_key(&self, lockbox: &LockLockboxRef) -> Result<LockKey, CryptoError> {
187 self.interface.decrypt_lock_key(lockbox)
188 }
189
190 pub fn decrypt_identity_key(
193 &self,
194 lockbox: &IdentityLockboxRef,
195 ) -> Result<IdentityKey, CryptoError> {
196 self.interface.decrypt_identity_key(lockbox)
197 }
198
199 pub fn decrypt_stream_key(&self, lockbox: &StreamLockboxRef) -> Result<StreamKey, CryptoError> {
202 self.interface.decrypt_stream_key(lockbox)
203 }
204
205 pub fn decrypt_data(&self, lockbox: &DataLockboxRef) -> Result<Vec<u8>, CryptoError> {
207 self.interface.decrypt_data(lockbox)
208 }
209
210 pub fn export_for_lock(
213 &self,
214 lock: &LockId,
215 ) -> Option<LockLockbox> {
216 self.interface.self_export_lock(&mut rand_core::OsRng, lock)
217 }
218
219 pub fn export_for_lock_with_rng<R: CryptoRng + RngCore>(
222 &self,
223 csprng: &mut R,
224 lock: &LockId,
225 ) -> Option<LockLockbox> {
226 self.interface.self_export_lock(csprng, lock)
227 }
228
229 #[cfg(feature = "getrandom")]
230 pub fn export_for_stream(
236 &self,
237 stream: &StreamKey,
238 ) -> Option<LockLockbox> {
239 self.interface.self_export_stream(&mut rand_core::OsRng, stream)
240 }
241
242 pub fn export_for_stream_with_rng<R: CryptoRng + RngCore>(
248 &self,
249 csprng: &mut R,
250 stream: &StreamKey,
251 ) -> Option<LockLockbox> {
252 self.interface.self_export_stream(csprng, stream)
253 }
254}
255
256impl fmt::Debug for LockKey {
257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258 f.debug_struct("LockKey")
259 .field("version", &self.version())
260 .field("lock_id", &self.id().raw_public_key())
261 .finish()
262 }
263}
264
265impl fmt::Display for LockKey {
266 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
268 fmt::Display::fmt(self.id(), f)
269 }
270}
271
272impl<T: LockInterface + 'static> From<T> for LockKey {
273 fn from(value: T) -> Self {
274 Self::from_interface(Arc::new(value))
275 }
276}
277
278pub trait LockInterface {
284 fn id(&self) -> &LockId;
286
287 fn decrypt_lock_key(&self, lockbox: &LockLockboxRef) -> Result<LockKey, CryptoError>;
289
290 fn decrypt_identity_key(
292 &self,
293 lockbox: &IdentityLockboxRef,
294 ) -> Result<IdentityKey, CryptoError>;
295
296 fn decrypt_stream_key(&self, lockbox: &StreamLockboxRef) -> Result<StreamKey, CryptoError>;
298
299 fn decrypt_data(&self, lockbox: &DataLockboxRef) -> Result<Vec<u8>, CryptoError>;
301
302 fn self_export_lock(
305 &self,
306 csprng: &mut dyn CryptoSrc,
307 receive_lock: &LockId,
308 ) -> Option<LockLockbox>;
309
310 fn self_export_stream(
313 &self,
314 csprng: &mut dyn CryptoSrc,
315 receive_stream: &StreamKey,
316 ) -> Option<LockLockbox>;
317}
318
319#[derive(Clone, PartialEq, Eq, Hash)]
342pub struct LockId {
343 inner: x25519_dalek::PublicKey,
344}
345
346impl LockId {
347
348 #[cfg(feature = "getrandom")]
349 pub fn encrypt_data(&self, content: &[u8]) -> DataLockbox {
351 self.encrypt_data_with_rng(&mut rand_core::OsRng, content)
352 }
353
354 pub fn encrypt_data_with_rng<R>(&self, csprng: &mut R, content: &[u8]) -> DataLockbox
357 where
358 R: CryptoRng + RngCore,
359 {
360 data_lockbox_from_parts(lock_id_encrypt(
361 self,
362 csprng,
363 LockboxType::Data(false),
364 content,
365 ))
366 }
367
368 pub fn version(&self) -> u8 {
370 1u8
371 }
372
373 pub fn raw_public_key(&self) -> &[u8] {
375 self.inner.as_bytes()
376 }
377
378 pub fn as_vec(&self) -> Vec<u8> {
381 let mut v = Vec::new();
382 self.encode_vec(&mut v);
383 v
384 }
385
386 pub fn from_base58(s: &str) -> Result<Self, CryptoError> {
388 let raw = bs58::decode(s)
389 .into_vec()
390 .or(Err(CryptoError::BadFormat("Not valid Base58")))?;
391 Self::try_from(&raw[..])
392 }
393
394 pub fn to_base58(&self) -> String {
396 bs58::encode(&(self.as_vec())).into_string()
397 }
398
399 pub fn encode_vec(&self, buf: &mut Vec<u8>) {
402 buf.reserve(self.size());
403 buf.push(self.version());
404 buf.extend_from_slice(self.inner.as_bytes());
405 }
406
407 pub fn size(&self) -> usize {
409 1 + V1_LOCK_ID_SIZE
410 }
411}
412
413impl TryFrom<&[u8]> for LockId {
414 type Error = CryptoError;
415
416 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
417 let (&version, data) = value.split_first().ok_or(CryptoError::BadLength {
418 step: "get LockId version",
419 expected: 1,
420 actual: 0,
421 })?;
422 if version != 1u8 {
423 return Err(CryptoError::UnsupportedVersion(version));
424 }
425 if data.len() != V1_LOCK_ID_SIZE {
426 return Err(CryptoError::BadLength {
427 step: "get LockId public key",
428 expected: V1_LOCK_ID_SIZE,
429 actual: data.len(),
430 });
431 }
432 let inner: [u8; V1_LOCK_ID_SIZE] =
433 TryFrom::try_from(data).map_err(|_| CryptoError::BadLength {
434 step: "get LockId public key",
435 expected: V1_LOCK_ID_SIZE,
436 actual: data.len(),
437 })?;
438 Ok(Self {
439 inner: x25519_dalek::PublicKey::from(inner),
440 })
441 }
442}
443
444impl fmt::Debug for LockId {
445 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
446 f.debug_struct("Identity")
447 .field("version", &self.version())
448 .field("public_key", &self.raw_public_key())
449 .finish()
450 }
451}
452
453impl fmt::Display for LockId {
454 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
456 write!(f, "{}", self.to_base58())
457 }
458}
459
460impl fmt::LowerHex for LockId {
461 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
462 for byte in self.as_vec().iter() {
463 write!(f, "{:x}", byte)?;
464 }
465 Ok(())
466 }
467}
468
469impl fmt::UpperHex for LockId {
470 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
471 for byte in self.as_vec().iter() {
472 write!(f, "{:X}", byte)?;
473 }
474 Ok(())
475 }
476}
477
478pub fn lock_id_encrypt(
488 id: &LockId,
489 csprng: &mut dyn CryptoSrc,
490 lock_type: LockboxType,
491 content: &[u8],
492) -> Vec<u8> {
493 assert!(
494 !lock_type.is_for_stream(),
495 "Tried to encrypt a non-lock-recipient lockbox with a LockId"
496 );
497 use chacha20poly1305::{ AeadInPlace, XChaCha20Poly1305, XNonce };
498
499 let mut nonce = [0u8; crate::lockbox::V1_LOCKBOX_NONCE_SIZE];
501 csprng.fill_bytes(nonce.as_mut());
502 let eph = x25519_dalek::EphemeralSecret::random_from_rng(csprng);
503 let eph_pub = x25519_dalek::PublicKey::from(&eph);
504
505 let version = id.version();
507 let tag_len = lockbox_tag_size(version);
508 let nonce_len = lockbox_nonce_size(version);
509 let header_len = 2 + id.size() + eph_pub.as_bytes().len();
510 let len = header_len + nonce_len + content.len() + tag_len;
511 let mut lockbox = Vec::with_capacity(len);
512
513 lockbox.push(version);
515 lockbox.push(lock_type.as_u8());
516 id.encode_vec(&mut lockbox);
517 lockbox.extend_from_slice(eph_pub.as_bytes());
518 lockbox.extend_from_slice(&nonce);
519 lockbox.extend_from_slice(content);
520
521 let (additional, nonce_and_content) = lockbox.split_at_mut(header_len);
523 let (_, content) = nonce_and_content.split_at_mut(nonce_len);
524 let secret = eph.diffie_hellman(&id.inner);
525 let aead = XChaCha20Poly1305::new_from_slice(secret.as_bytes()).unwrap();
526 let nonce = XNonce::from(nonce);
527
528 let tag = aead
532 .encrypt_in_place_detached(&nonce, additional, content)
533 .expect("More data than the cipher can accept was put in");
534 lockbox.extend_from_slice(&tag);
535 lockbox
536}
537
538pub struct BareLockKey {
541 id: LockId,
542 key: x25519_dalek::StaticSecret,
543}
544
545#[cfg(feature = "getrandom")]
546impl Default for BareLockKey {
547 fn default() -> Self {
548 Self::new()
549 }
550}
551
552impl BareLockKey {
553
554 #[cfg(feature = "getrandom")]
555 pub fn new() -> Self {
557 let key = x25519_dalek::StaticSecret::random();
558 let id = LockId {
559 inner: (&key).into()
560 };
561 Self { key, id }
562 }
563
564 pub fn with_rng<R>(csprng: &mut R) -> Self
566 where
567 R: CryptoRng + RngCore,
568 {
569 Self::with_rng_and_version(csprng, DEFAULT_LOCK_VERSION).unwrap()
570 }
571
572 pub fn with_rng_and_version<R>(csprng: &mut R, version: u8) -> Result<Self, CryptoError>
575 where
576 R: CryptoRng + RngCore,
577 {
578 if (version < MIN_LOCK_VERSION) || (version > MAX_LOCK_VERSION) {
579 return Err(CryptoError::UnsupportedVersion(version));
580 }
581
582 let key = x25519_dalek::StaticSecret::random_from_rng(csprng);
583 let id = LockId {
584 inner: x25519_dalek::PublicKey::from(&key),
585 };
586
587 Ok(Self { key, id })
588 }
589
590 pub fn encode_vec(&self, buf: &mut Vec<u8>) {
593 buf.reserve(1 + V1_LOCK_KEY_SIZE);
594 buf.push(1u8);
595 let mut raw_key = self.key.to_bytes();
598 buf.extend_from_slice(&raw_key);
599 raw_key.zeroize();
600 }
601
602 fn decrypt_parts(
605 &self,
606 recipient: &LockboxRecipient,
607 parts: LockboxParts,
608 ) -> Result<Vec<u8>, CryptoError> {
609 if let LockboxRecipient::LockId(id) = recipient {
612 if id != &self.id {
613 return Err(CryptoError::ObjectMismatch(
614 "LockKey being used on a lockbox meant for a different LockId",
615 ));
616 }
617 } else {
618 return Err(CryptoError::ObjectMismatch(
619 "Attempted to use a LockKey to decrypt a lockbox with a StreamId recipient",
620 ));
621 }
622
623 let eph_pub = parts.eph_pub.unwrap();
625 if eph_pub.len() != V1_LOCK_ID_SIZE {
626 return Err(CryptoError::BadLength {
627 step: "get Lockbox ephemeral public key",
628 expected: V1_LOCK_ID_SIZE,
629 actual: eph_pub.len(),
630 });
631 }
632 let eph_pub: [u8; 32] = TryFrom::try_from(eph_pub).map_err(|_| CryptoError::BadLength {
633 step: "get Lockbox ephemeral public key",
634 expected: V1_LOCK_ID_SIZE,
635 actual: eph_pub.len(),
636 })?;
637 let eph_pub = x25519_dalek::PublicKey::from(eph_pub);
638 let secret = self.key.diffie_hellman(&eph_pub);
639
640 use chacha20poly1305::aead::Aead;
642 use chacha20poly1305::*;
643 let aead = XChaCha20Poly1305::new(Key::from_slice(secret.as_bytes()));
644 let nonce = XNonce::from_slice(parts.nonce);
645 let payload = aead::Payload {
646 msg: parts.ciphertext,
647 aad: parts.additional,
648 };
649 aead.decrypt(nonce, payload)
650 .map_err(|_| CryptoError::DecryptFailed)
651 }
652}
653
654impl TryFrom<&[u8]> for BareLockKey {
655 type Error = CryptoError;
656
657 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
659 let (version, raw_key) = value.split_first().ok_or(CryptoError::BadLength {
660 step: "get LockKey version",
661 expected: 1,
662 actual: 0,
663 })?;
664 let version = *version;
665 if version < MIN_LOCK_VERSION {
666 return Err(CryptoError::OldVersion(version));
667 }
668 if version > MAX_LOCK_VERSION {
669 return Err(CryptoError::UnsupportedVersion(version));
670 }
671
672 if raw_key.len() != V1_LOCK_KEY_SIZE {
676 return Err(CryptoError::BadLength {
677 step: "get LockKey key bytes",
678 expected: V1_LOCK_KEY_SIZE,
679 actual: raw_key.len(),
680 });
681 }
682 let mut raw_key: [u8; V1_LOCK_KEY_SIZE] =
683 TryFrom::try_from(raw_key).map_err(|_| CryptoError::BadLength {
684 step: "get LockKey key bytes",
685 expected: V1_LOCK_KEY_SIZE,
686 actual: raw_key.len(),
687 })?;
688 let key = x25519_dalek::StaticSecret::from(raw_key);
689 raw_key.zeroize();
690
691 let public = x25519_dalek::PublicKey::from(&key);
692
693 Ok(Self {
694 key,
695 id: LockId { inner: public },
696 })
697 }
698}
699
700impl LockInterface for BareLockKey {
701 fn id(&self) -> &LockId {
702 &self.id
703 }
704
705 fn decrypt_lock_key(&self, lockbox: &LockLockboxRef) -> Result<LockKey, CryptoError> {
706 let recipient = lockbox.recipient();
707 let parts = lockbox.as_parts();
708 let mut key = self.decrypt_parts(&recipient, parts)?;
709 let result = BareLockKey::try_from(key.as_ref());
710 key.zeroize();
711 Ok(LockKey::from_interface(Arc::new(result?)))
712 }
713
714 fn decrypt_identity_key(
715 &self,
716 lockbox: &IdentityLockboxRef,
717 ) -> Result<IdentityKey, CryptoError> {
718 let recipient = lockbox.recipient();
719 let parts = lockbox.as_parts();
720 let mut key = self.decrypt_parts(&recipient, parts)?;
721 let result = BareIdKey::try_from(key.as_ref());
722 key.zeroize();
723 Ok(IdentityKey::from_interface(Arc::new(result?)))
724 }
725
726 fn decrypt_stream_key(&self, lockbox: &StreamLockboxRef) -> Result<StreamKey, CryptoError> {
727 let recipient = lockbox.recipient();
728 let parts = lockbox.as_parts();
729 let mut key = self.decrypt_parts(&recipient, parts)?;
730 let result = BareStreamKey::try_from(key.as_ref());
731 key.zeroize();
732 Ok(StreamKey::from_interface(Arc::new(result?)))
733 }
734
735 fn decrypt_data(&self, lockbox: &DataLockboxRef) -> Result<Vec<u8>, CryptoError> {
736 let recipient = lockbox.recipient();
737 let parts = lockbox.as_parts();
738 self.decrypt_parts(&recipient, parts)
739 }
740
741 fn self_export_lock(
742 &self,
743 csprng: &mut dyn CryptoSrc,
744 receive_lock: &LockId,
745 ) -> Option<LockLockbox> {
746 let mut raw_secret = Vec::new(); self.encode_vec(&mut raw_secret);
748 let lockbox_vec =
749 lock_id_encrypt(receive_lock, csprng, LockboxType::Lock(false), &raw_secret);
750 raw_secret.zeroize();
751 debug_assert!(raw_secret.iter().all(|&x| x == 0)); Some(lock_lockbox_from_parts(lockbox_vec))
753 }
754
755 fn self_export_stream(
756 &self,
757 csprng: &mut dyn CryptoSrc,
758 receive_stream: &StreamKey,
759 ) -> Option<LockLockbox> {
760 let mut raw_secret = Vec::new(); self.encode_vec(&mut raw_secret);
762 let lockbox_vec =
763 stream_key_encrypt(receive_stream, csprng, LockboxType::Lock(true), &raw_secret);
764 raw_secret.zeroize();
765 debug_assert!(raw_secret.iter().all(|&x| x == 0)); Some(lock_lockbox_from_parts(lockbox_vec))
767 }
768}
769
770#[cfg(test)]
771mod tests {
772 use super::*;
773
774 #[test]
775 fn basics() {
776 let mut csprng = rand::rngs::OsRng;
777 let key = LockKey::with_rng(&mut csprng);
778 assert_eq!(key.version(), DEFAULT_LOCK_VERSION);
779 let key = LockKey::with_rng_and_version(&mut csprng, DEFAULT_LOCK_VERSION).unwrap();
780 assert_eq!(key.version(), DEFAULT_LOCK_VERSION);
781 let result = LockKey::with_rng_and_version(&mut csprng, 99u8);
782 if let Err(CryptoError::UnsupportedVersion(99u8)) = result {
783 } else {
784 panic!("Didn't get expected error on with_rng_and_version");
785 }
786 }
787
788 #[test]
789 fn display() {
790 let mut csprng = rand::rngs::OsRng;
791 let key = LockKey::with_rng(&mut csprng);
792 let disp_key = format!("{}", &key);
793 let disp_id = format!("{}", key.id());
794 let base58 = key.id().to_base58();
795 assert_eq!(disp_key, disp_id);
796 assert_eq!(disp_key, base58);
797 assert!(disp_key.len() > 1);
798 }
799
800 #[test]
801 fn base58() {
802 let mut csprng = rand::rngs::OsRng;
803 let key = LockKey::with_rng(&mut csprng);
804 let mut base58 = key.id().to_base58();
805 assert!(base58.len() > 1);
806 let id = LockId::from_base58(&base58).unwrap();
807 assert_eq!(&id, key.id());
808 base58.push('a');
809 base58.push('a');
810 assert!(LockId::from_base58(&base58).is_err());
811 base58.pop();
812 base58.pop();
813 base58.pop();
814 assert!(LockId::from_base58(&base58).is_err());
815 }
816
817 #[test]
818 fn encode() {
819 let mut csprng = rand::rngs::OsRng;
820 let key = LockKey::with_rng(&mut csprng);
821 let id = key.id();
822 let mut id_vec = Vec::new();
823 id.encode_vec(&mut id_vec);
824 assert_eq!(id_vec.len(), id.size());
825 let id = LockId::try_from(&id_vec[..]).unwrap();
826 assert_eq!(&id, key.id());
827 }
828
829 fn corrupt_version<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
830 where
831 F1: Fn(&[u8]) -> bool,
832 F2: Fn(&[u8]) -> bool,
833 {
834 let version = enc[0];
836 enc[0] = 0;
837 assert!(!check_decode(&enc[..]));
838 enc[0] = 2;
839 assert!(!check_decode(&enc[..]));
840 enc[0] = version;
841 assert!(check_decrypt(&enc[..]));
842 }
843
844 fn corrupt_type<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
845 where
846 F1: Fn(&[u8]) -> bool,
847 F2: Fn(&[u8]) -> bool,
848 {
849 enc[1] |= 0x80;
851 assert!(!check_decode(&enc[..]));
852 enc[1] &= 0x07;
853 assert!(check_decrypt(&enc[..]));
854 enc[1] = (enc[1] + 1) & 0x7; assert!(check_decode(&enc[..]));
856 assert!(!check_decrypt(&enc[..]));
857 for _ in 0..6 {
858 enc[1] = (enc[1] + 1) & 0x7;
860 assert!(!check_decode(&enc[..]));
861 }
862 enc[1] = (enc[1] + 1) & 0x7;
863 assert!(check_decrypt(&enc[..]));
864 }
865
866 fn corrupt_id<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
867 where
868 F1: Fn(&[u8]) -> bool,
869 F2: Fn(&[u8]) -> bool,
870 {
871 enc[2] = 0;
873 assert!(!check_decode(&enc[..]));
874 enc[2] = 2;
875 assert!(!check_decode(&enc[..]));
876 enc[2] = DEFAULT_LOCK_VERSION;
877 assert!(check_decrypt(&enc[..]));
878 enc[3] ^= 0xFF;
879 assert!(!check_decrypt(&enc[..]));
880 enc[3] ^= 0xFF;
881 assert!(check_decrypt(&enc[..]));
882 }
883
884 fn corrupt_ephemeral<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
885 where
886 F1: Fn(&[u8]) -> bool,
887 F2: Fn(&[u8]) -> bool,
888 {
889 enc[35] ^= 0xFF;
891 assert!(check_decode(&enc[..]));
892 assert!(!check_decrypt(&enc[..]));
893 enc[35] ^= 0xFF;
894 assert!(check_decrypt(&enc[..]));
895 }
896
897 fn corrupt_nonce<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
898 where
899 F1: Fn(&[u8]) -> bool,
900 F2: Fn(&[u8]) -> bool,
901 {
902 enc[67] ^= 0xFF;
904 assert!(check_decode(&enc[..]));
905 assert!(!check_decrypt(&enc[..]));
906 enc[67] ^= 0xFF;
907 assert!(check_decrypt(&enc[..]));
908 }
909
910 fn corrupt_ciphertext<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
911 where
912 F1: Fn(&[u8]) -> bool,
913 F2: Fn(&[u8]) -> bool,
914 {
915 enc[91] ^= 0xFF;
917 assert!(check_decode(&enc[..]));
918 assert!(!check_decrypt(&enc[..]));
919 enc[91] ^= 0xFF;
920 assert!(check_decrypt(&enc[..]));
921 }
922
923 fn corrupt_tag<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
924 where
925 F1: Fn(&[u8]) -> bool,
926 F2: Fn(&[u8]) -> bool,
927 {
928 let tag_end = enc.last_mut().unwrap();
930 *tag_end ^= 0xFF;
931 assert!(check_decode(&enc[..]));
932 assert!(!check_decrypt(&enc[..]));
933 let tag_end = enc.last_mut().unwrap();
934 *tag_end ^= 0xFF;
935 assert!(check_decrypt(&enc[..]));
936 }
937
938 fn corrupt_length_extend<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
939 where
940 F1: Fn(&[u8]) -> bool,
941 F2: Fn(&[u8]) -> bool,
942 {
943 enc.push(0);
945 assert!(check_decode(&enc[..]));
946 assert!(!check_decrypt(&enc[..]));
947 enc.pop();
948 assert!(check_decrypt(&enc[..]));
949 }
950
951 fn corrupt_truncation<F1, F2>(mut enc: Vec<u8>, check_decode: F1, check_decrypt: F2)
952 where
953 F1: Fn(&[u8]) -> bool,
954 F2: Fn(&[u8]) -> bool,
955 {
956 enc.pop();
958 assert!(check_decode(&enc[..]));
959 assert!(!check_decrypt(&enc[..]));
960 }
961
962 fn corrupt_each_byte<F1, F2>(mut enc: Vec<u8>, _check_decode: F1, check_decrypt: F2)
963 where
964 F1: Fn(&[u8]) -> bool,
965 F2: Fn(&[u8]) -> bool,
966 {
967 for i in 0..enc.len() {
968 enc[i] ^= 0xFF;
969 assert!(!check_decrypt(&enc[..]));
970 enc[i] ^= 0xFF;
971 }
972 }
973
974 fn corrupt_inner_version<F: Fn(&[u8]) -> bool>(mut content: Vec<u8>, check_sequence: F) {
975 content[0] = 0u8;
977 assert!(!check_sequence(&content[..]));
978 content[0] = 99u8;
980 assert!(!check_sequence(&content[..]));
981 }
982
983 fn corrupt_inner_length_extend<F: Fn(&[u8]) -> bool>(mut content: Vec<u8>, check_sequence: F) {
984 content.push(0u8);
985 assert!(!check_sequence(&content[..]));
986 }
987
988 fn corrupt_inner_truncate<F: Fn(&[u8]) -> bool>(mut content: Vec<u8>, check_sequence: F) {
989 content.pop();
990 assert!(!check_sequence(&content[..]));
991 }
992
993 fn setup_data() -> (Vec<u8>, impl Fn(&[u8]) -> bool, impl Fn(&[u8]) -> bool) {
994 let key = LockKey::new();
996 let message = b"I am a test message, going undercover";
997
998 let lockbox = key.id().encrypt_data(message);
1000 let recipient = LockboxRecipient::LockId(key.id().clone());
1001 assert_eq!(recipient, lockbox.recipient());
1002 let enc = Vec::from(lockbox.as_bytes());
1003 (
1004 enc,
1005 |enc| DataLockboxRef::from_bytes(enc).is_ok(),
1006 move |enc| {
1007 let dec_lockbox = if let Ok(d) = DataLockboxRef::from_bytes(enc) {
1008 d
1009 } else {
1010 return false;
1011 };
1012 if LockboxRecipient::LockId(key.id().clone()) != dec_lockbox.recipient() {
1013 return false;
1014 }
1015 if let Ok(dec) = key.decrypt_data(dec_lockbox) {
1016 dec == message
1017 } else {
1018 false
1019 }
1020 },
1021 )
1022 }
1023
1024 #[test]
1025 fn data_clean_decrypt() {
1026 let (enc, _check_decode, check_decrypt) = setup_data();
1027 assert!(check_decrypt(&enc[..]));
1028 }
1029
1030 #[test]
1031 fn data_corrupt_version() {
1032 let (enc, check_decode, check_decrypt) = setup_data();
1033 corrupt_version(enc, check_decode, check_decrypt);
1034 }
1035
1036 #[test]
1037 fn data_corrupt_type() {
1038 let (enc, check_decode, check_decrypt) = setup_data();
1039 corrupt_type(enc, check_decode, check_decrypt);
1040 }
1041
1042 #[test]
1043 fn data_corrupt_id() {
1044 let (enc, check_decode, check_decrypt) = setup_data();
1045 corrupt_id(enc, check_decode, check_decrypt);
1046 }
1047
1048 #[test]
1049 fn data_corrupt_ephemeral() {
1050 let (enc, check_decode, check_decrypt) = setup_data();
1051 corrupt_ephemeral(enc, check_decode, check_decrypt);
1052 }
1053
1054 #[test]
1055 fn data_corrupt_nonce() {
1056 let (enc, check_decode, check_decrypt) = setup_data();
1057 corrupt_nonce(enc, check_decode, check_decrypt);
1058 }
1059
1060 #[test]
1061 fn data_corrupt_ciphertext() {
1062 let (enc, check_decode, check_decrypt) = setup_data();
1063 corrupt_ciphertext(enc, check_decode, check_decrypt);
1064 }
1065
1066 #[test]
1067 fn data_corrupt_tag() {
1068 let (enc, check_decode, check_decrypt) = setup_data();
1069 corrupt_tag(enc, check_decode, check_decrypt);
1070 }
1071
1072 #[test]
1073 fn data_corrupt_length_extend() {
1074 let (enc, check_decode, check_decrypt) = setup_data();
1075 corrupt_length_extend(enc, check_decode, check_decrypt);
1076 }
1077
1078 #[test]
1079 fn data_corrupt_truncation() {
1080 let (enc, check_decode, check_decrypt) = setup_data();
1081 corrupt_truncation(enc, check_decode, check_decrypt);
1082 }
1083
1084 #[test]
1085 fn data_corrupt_each_byte() {
1086 let (enc, check_decode, check_decrypt) = setup_data();
1087 corrupt_each_byte(enc, check_decode, check_decrypt);
1088 }
1089
1090 fn setup_id() -> (Vec<u8>, impl Fn(&[u8]) -> bool, impl Fn(&[u8]) -> bool) {
1091 let key = LockKey::new();
1093 let to_send = IdentityKey::new();
1094
1095 let lockbox = to_send.export_for_lock(key.id()).unwrap();
1097 let recipient = LockboxRecipient::LockId(key.id().clone());
1098 assert_eq!(recipient, lockbox.recipient());
1099 let enc = Vec::from(lockbox.as_bytes());
1100 (
1101 enc,
1102 |enc| IdentityLockboxRef::from_bytes(enc).is_ok(),
1103 move |enc| {
1104 let dec_lockbox = if let Ok(d) = IdentityLockboxRef::from_bytes(enc) {
1105 d
1106 } else {
1107 return false;
1108 };
1109 if LockboxRecipient::LockId(key.id().clone()) != dec_lockbox.recipient() {
1110 return false;
1111 }
1112 if let Ok(dec) = key.decrypt_identity_key(dec_lockbox) {
1113 dec.id() == to_send.id()
1114 } else {
1115 false
1116 }
1117 },
1118 )
1119 }
1120
1121 #[test]
1122 fn id_clean_decrypt() {
1123 let (enc, _check_decode, check_decrypt) = setup_id();
1124 assert!(check_decrypt(&enc[..]));
1125 }
1126
1127 #[test]
1128 fn id_corrupt_version() {
1129 let (enc, check_decode, check_decrypt) = setup_id();
1130 corrupt_version(enc, check_decode, check_decrypt);
1131 }
1132
1133 #[test]
1134 fn id_corrupt_type() {
1135 let (enc, check_decode, check_decrypt) = setup_id();
1136 corrupt_type(enc, check_decode, check_decrypt);
1137 }
1138
1139 #[test]
1140 fn id_corrupt_id() {
1141 let (enc, check_decode, check_decrypt) = setup_id();
1142 corrupt_id(enc, check_decode, check_decrypt);
1143 }
1144
1145 #[test]
1146 fn id_corrupt_ephemeral() {
1147 let (enc, check_decode, check_decrypt) = setup_id();
1148 corrupt_ephemeral(enc, check_decode, check_decrypt);
1149 }
1150
1151 #[test]
1152 fn id_corrupt_nonce() {
1153 let (enc, check_decode, check_decrypt) = setup_id();
1154 corrupt_nonce(enc, check_decode, check_decrypt);
1155 }
1156
1157 #[test]
1158 fn id_corrupt_ciphertext() {
1159 let (enc, check_decode, check_decrypt) = setup_id();
1160 corrupt_ciphertext(enc, check_decode, check_decrypt);
1161 }
1162
1163 #[test]
1164 fn id_corrupt_tag() {
1165 let (enc, check_decode, check_decrypt) = setup_id();
1166 corrupt_tag(enc, check_decode, check_decrypt);
1167 }
1168
1169 #[test]
1170 fn id_corrupt_length_extend() {
1171 let (enc, check_decode, check_decrypt) = setup_id();
1172 corrupt_length_extend(enc, check_decode, check_decrypt);
1173 }
1174
1175 #[test]
1176 fn id_corrupt_truncation() {
1177 let (enc, check_decode, check_decrypt) = setup_id();
1178 corrupt_truncation(enc, check_decode, check_decrypt);
1179 }
1180
1181 #[test]
1182 fn id_corrupt_each_byte() {
1183 let (enc, check_decode, check_decrypt) = setup_id();
1184 corrupt_each_byte(enc, check_decode, check_decrypt);
1185 }
1186
1187 fn setup_id_raw() -> (Vec<u8>, impl Fn(&[u8]) -> bool) {
1188 use crate::identity::SignInterface;
1189 let mut csprng = rand::rngs::OsRng;
1191 let key = LockKey::with_rng(&mut csprng);
1192 let to_send = crate::BareIdKey::with_rng(&mut csprng);
1193
1194 let mut content = Vec::new();
1196 to_send.encode_vec(&mut content);
1197
1198 (content, move |content| {
1199 let mut csprng = rand::rngs::OsRng;
1200 let lockbox = identity_lockbox_from_parts(crate::lock::lock_id_encrypt(
1201 key.id(),
1202 &mut csprng,
1203 crate::lockbox::LockboxType::Identity(false),
1204 content,
1205 ));
1206 let enc = Vec::from(lockbox.as_bytes());
1207 let lockbox = if let Ok(l) = IdentityLockboxRef::from_bytes(&enc[..]) {
1208 l
1209 } else {
1210 return false;
1211 };
1212 if let Ok(dec) = key.decrypt_identity_key(lockbox) {
1213 dec.id() == to_send.id()
1214 } else {
1215 false
1216 }
1217 })
1218 }
1219
1220 #[test]
1221 fn id_inner_ok() {
1222 let (content, check_sequence) = setup_id_raw();
1223 assert!(check_sequence(&content[..]));
1224 }
1225
1226 #[test]
1227 fn id_corrupt_inner_version() {
1228 let (content, check_sequence) = setup_id_raw();
1229 corrupt_inner_version(content, check_sequence);
1230 }
1231
1232 #[test]
1233 fn id_corrupt_inner_length_extend() {
1234 let (content, check_sequence) = setup_id_raw();
1235 corrupt_inner_length_extend(content, check_sequence);
1236 }
1237
1238 #[test]
1239 fn id_corrupt_inner_truncate() {
1240 let (content, check_sequence) = setup_id_raw();
1241 corrupt_inner_truncate(content, check_sequence);
1242 }
1243
1244 fn setup_lock_stream() -> (Vec<u8>, impl Fn(&[u8]) -> bool, impl Fn(&[u8]) -> bool) {
1245 let key = LockKey::new();
1247 let to_send = StreamKey::new();
1248
1249 let lockbox = to_send.export_for_lock(key.id()).unwrap();
1251 let recipient = LockboxRecipient::LockId(key.id().clone());
1252 assert_eq!(recipient, lockbox.recipient());
1253 let enc = Vec::from(lockbox.as_bytes());
1254 (
1255 enc,
1256 |enc| StreamLockboxRef::from_bytes(enc).is_ok(),
1257 move |enc| {
1258 let dec_lockbox = if let Ok(d) = StreamLockboxRef::from_bytes(enc) {
1259 d
1260 } else {
1261 return false;
1262 };
1263 if LockboxRecipient::LockId(key.id().clone()) != dec_lockbox.recipient() {
1264 return false;
1265 }
1266 if let Ok(dec) = key.decrypt_stream_key(dec_lockbox) {
1267 dec.id() == to_send.id()
1268 } else {
1269 false
1270 }
1271 },
1272 )
1273 }
1274
1275 #[test]
1276 fn stream_clean_decrypt() {
1277 let (enc, _check_decode, check_decrypt) = setup_lock_stream();
1278 assert!(check_decrypt(&enc[..]));
1279 }
1280
1281 #[test]
1282 fn stream_corrupt_version() {
1283 let (enc, check_decode, check_decrypt) = setup_lock_stream();
1284 corrupt_version(enc, check_decode, check_decrypt);
1285 }
1286
1287 #[test]
1288 fn stream_corrupt_type() {
1289 let (enc, check_decode, check_decrypt) = setup_lock_stream();
1290 corrupt_type(enc, check_decode, check_decrypt);
1291 }
1292
1293 #[test]
1294 fn stream_corrupt_id() {
1295 let (enc, check_decode, check_decrypt) = setup_lock_stream();
1296 corrupt_id(enc, check_decode, check_decrypt);
1297 }
1298
1299 #[test]
1300 fn stream_corrupt_ephemeral() {
1301 let (enc, check_decode, check_decrypt) = setup_lock_stream();
1302 corrupt_ephemeral(enc, check_decode, check_decrypt);
1303 }
1304
1305 #[test]
1306 fn stream_corrupt_nonce() {
1307 let (enc, check_decode, check_decrypt) = setup_lock_stream();
1308 corrupt_nonce(enc, check_decode, check_decrypt);
1309 }
1310
1311 #[test]
1312 fn stream_corrupt_ciphertext() {
1313 let (enc, check_decode, check_decrypt) = setup_lock_stream();
1314 corrupt_ciphertext(enc, check_decode, check_decrypt);
1315 }
1316
1317 #[test]
1318 fn stream_corrupt_tag() {
1319 let (enc, check_decode, check_decrypt) = setup_lock_stream();
1320 corrupt_tag(enc, check_decode, check_decrypt);
1321 }
1322
1323 #[test]
1324 fn stream_corrupt_length_extend() {
1325 let (enc, check_decode, check_decrypt) = setup_lock_stream();
1326 corrupt_length_extend(enc, check_decode, check_decrypt);
1327 }
1328
1329 #[test]
1330 fn stream_corrupt_truncation() {
1331 let (enc, check_decode, check_decrypt) = setup_lock_stream();
1332 corrupt_truncation(enc, check_decode, check_decrypt);
1333 }
1334
1335 #[test]
1336 fn stream_corrupt_each_byte() {
1337 let (enc, check_decode, check_decrypt) = setup_lock_stream();
1338 corrupt_each_byte(enc, check_decode, check_decrypt);
1339 }
1340
1341 fn setup_lock_stream_raw() -> (Vec<u8>, impl Fn(&[u8]) -> bool) {
1342 use crate::stream::StreamInterface;
1343 let mut csprng = rand::rngs::OsRng;
1345 let key = LockKey::with_rng(&mut csprng);
1346 let to_send = crate::BareStreamKey::with_rng(&mut csprng);
1347
1348 let mut content = Vec::new();
1350 to_send.encode_vec(&mut content);
1351
1352 (content, move |content| {
1353 let mut csprng = rand::rngs::OsRng;
1354 let lockbox = stream_lockbox_from_parts(crate::lock::lock_id_encrypt(
1355 key.id(),
1356 &mut csprng,
1357 crate::lockbox::LockboxType::Stream(false),
1358 content,
1359 ));
1360 let enc = Vec::from(lockbox.as_bytes());
1361 let lockbox = if let Ok(l) = StreamLockboxRef::from_bytes(&enc[..]) {
1362 l
1363 } else {
1364 return false;
1365 };
1366 if let Ok(dec) = key.decrypt_stream_key(lockbox) {
1367 dec.id() == to_send.id()
1368 } else {
1369 false
1370 }
1371 })
1372 }
1373
1374 #[test]
1375 fn stream_inner_ok() {
1376 let (content, check_sequence) = setup_lock_stream_raw();
1377 assert!(check_sequence(&content[..]));
1378 }
1379
1380 #[test]
1381 fn stream_corrupt_inner_version() {
1382 let (content, check_sequence) = setup_lock_stream_raw();
1383 corrupt_inner_version(content, check_sequence);
1384 }
1385
1386 #[test]
1387 fn stream_corrupt_inner_length_extend() {
1388 let (content, check_sequence) = setup_lock_stream_raw();
1389 corrupt_inner_length_extend(content, check_sequence);
1390 }
1391
1392 #[test]
1393 fn stream_corrupt_inner_truncate() {
1394 let (content, check_sequence) = setup_lock_stream_raw();
1395 corrupt_inner_truncate(content, check_sequence);
1396 }
1397
1398 fn setup_lock() -> (Vec<u8>, impl Fn(&[u8]) -> bool, impl Fn(&[u8]) -> bool) {
1399 let key = LockKey::new();
1401 let to_send = LockKey::new();
1402
1403 let lockbox = to_send.export_for_lock(key.id()).unwrap();
1405 let recipient = LockboxRecipient::LockId(key.id().clone());
1406 assert_eq!(recipient, lockbox.recipient());
1407 let enc = Vec::from(lockbox.as_bytes());
1408 (
1409 enc,
1410 |enc| LockLockboxRef::from_bytes(enc).is_ok(),
1411 move |enc| {
1412 let dec_lockbox = if let Ok(d) = LockLockboxRef::from_bytes(enc) {
1413 d
1414 } else {
1415 return false;
1416 };
1417 if LockboxRecipient::LockId(key.id().clone()) != dec_lockbox.recipient() {
1418 return false;
1419 }
1420 if let Ok(dec) = key.decrypt_lock_key(dec_lockbox) {
1421 dec.id() == to_send.id()
1422 } else {
1423 false
1424 }
1425 },
1426 )
1427 }
1428
1429 #[test]
1430 fn lock_clean_decrypt() {
1431 let (enc, _check_decode, check_decrypt) = setup_lock();
1432 assert!(check_decrypt(&enc[..]));
1433 }
1434
1435 #[test]
1436 fn lock_corrupt_version() {
1437 let (enc, check_decode, check_decrypt) = setup_lock();
1438 corrupt_version(enc, check_decode, check_decrypt);
1439 }
1440
1441 #[test]
1442 fn lock_corrupt_type() {
1443 let (enc, check_decode, check_decrypt) = setup_lock();
1444 corrupt_type(enc, check_decode, check_decrypt);
1445 }
1446
1447 #[test]
1448 fn lock_corrupt_id() {
1449 let (enc, check_decode, check_decrypt) = setup_lock();
1450 corrupt_id(enc, check_decode, check_decrypt);
1451 }
1452
1453 #[test]
1454 fn lock_corrupt_ephemeral() {
1455 let (enc, check_decode, check_decrypt) = setup_lock();
1456 corrupt_ephemeral(enc, check_decode, check_decrypt);
1457 }
1458
1459 #[test]
1460 fn lock_corrupt_nonce() {
1461 let (enc, check_decode, check_decrypt) = setup_lock();
1462 corrupt_nonce(enc, check_decode, check_decrypt);
1463 }
1464
1465 #[test]
1466 fn lock_corrupt_ciphertext() {
1467 let (enc, check_decode, check_decrypt) = setup_lock();
1468 corrupt_ciphertext(enc, check_decode, check_decrypt);
1469 }
1470
1471 #[test]
1472 fn lock_corrupt_tag() {
1473 let (enc, check_decode, check_decrypt) = setup_lock();
1474 corrupt_tag(enc, check_decode, check_decrypt);
1475 }
1476
1477 #[test]
1478 fn lock_corrupt_length_extend() {
1479 let (enc, check_decode, check_decrypt) = setup_lock();
1480 corrupt_length_extend(enc, check_decode, check_decrypt);
1481 }
1482
1483 #[test]
1484 fn lock_corrupt_truncation() {
1485 let (enc, check_decode, check_decrypt) = setup_lock();
1486 corrupt_truncation(enc, check_decode, check_decrypt);
1487 }
1488
1489 #[test]
1490 fn lock_corrupt_each_byte() {
1491 let (enc, check_decode, check_decrypt) = setup_lock();
1492 corrupt_each_byte(enc, check_decode, check_decrypt);
1493 }
1494
1495 fn setup_lock_raw() -> (Vec<u8>, impl Fn(&[u8]) -> bool) {
1496 let mut csprng = rand::rngs::OsRng;
1498 let key = LockKey::with_rng(&mut csprng);
1499 let to_send = crate::BareLockKey::with_rng(&mut csprng);
1500
1501 let mut content = Vec::new();
1503 to_send.encode_vec(&mut content);
1504
1505 (content, move |content| {
1506 let mut csprng = rand::rngs::OsRng;
1507 let lockbox = lock_lockbox_from_parts(crate::lock::lock_id_encrypt(
1508 key.id(),
1509 &mut csprng,
1510 crate::lockbox::LockboxType::Lock(false),
1511 content,
1512 ));
1513 let enc = Vec::from(lockbox.as_bytes());
1514 let lockbox = if let Ok(l) = LockLockboxRef::from_bytes(&enc[..]) {
1515 l
1516 } else {
1517 return false;
1518 };
1519 if let Ok(dec) = key.decrypt_lock_key(lockbox) {
1520 dec.id() == to_send.id()
1521 } else {
1522 false
1523 }
1524 })
1525 }
1526
1527 #[test]
1528 fn lock_inner_ok() {
1529 let (content, check_sequence) = setup_lock_raw();
1530 assert!(check_sequence(&content[..]));
1531 }
1532
1533 #[test]
1534 fn lock_corrupt_inner_version() {
1535 let (content, check_sequence) = setup_lock_raw();
1536 corrupt_inner_version(content, check_sequence);
1537 }
1538
1539 #[test]
1540 fn lock_corrupt_inner_length_extend() {
1541 let (content, check_sequence) = setup_lock_raw();
1542 corrupt_inner_length_extend(content, check_sequence);
1543 }
1544
1545 #[test]
1546 fn lock_corrupt_inner_truncate() {
1547 let (content, check_sequence) = setup_lock_raw();
1548 corrupt_inner_truncate(content, check_sequence);
1549 }
1550}