1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
5#![allow(clippy::needless_doctest_main)]
6#![doc = include_str!("../README.md")]
7#![warn(missing_docs)]
8
9use chacha20poly1305::XNonce;
10
11#[cfg(any(feature = "reaching", feature = "reachable"))]
12pub(crate) mod aliases;
13
14#[cfg(any(feature = "reaching", feature = "reachable"))]
15mod public_key;
16#[cfg(any(feature = "reaching", feature = "reachable"))]
17pub use public_key::*;
18
19mod symmetric;
20pub use symmetric::*;
21
22pub trait Ciphertext {
27 fn ciphertext(&self) -> &[u8];
29}
30
31pub trait Nonce {
33 fn nonce(&self) -> &XNonce;
35}
36
37macro_rules! ciphertext_nonce {
50 (
51 $type_name:ident,
52 $($ciphertext:ident).+
53 ) => {
54 impl Ciphertext for $type_name {
55 fn ciphertext(&self) -> &[u8] {
56 self.$($ciphertext).+.as_slice()
57 }
58 }
59 };
60 (
61 $type_name:ident,
62 $($nonce:ident).+,
63 $($ciphertext:ident).+
64 ) => {
65 ciphertext_nonce!($type_name, $($ciphertext).+);
66
67 impl Nonce for $type_name {
68 fn nonce(&self) -> &XNonce {
69 &self.$($nonce).+
70 }
71 }
72 };
73}
74
75pub(crate) use ciphertext_nonce;
76
77#[cfg(any(feature = "reaching", feature = "reachable"))]
78mod reaching_reachable {
79 use super::*;
80
81 use reach_core::{
82 ParticipantPublicKeys, error,
83 memory::{Credentials, MessageVaultPassport, OpenedEnvelope},
84 wire::{CredentialVault, Envelope, Salts},
85 };
86
87 pub fn open_envelope<D, P>(
104 secret_keys: &D,
105 public_keys: &P,
106 envelope: &Envelope,
107 salts: &Salts,
108 ) -> Result<OpenedEnvelope, error::CryptError>
109 where
110 D: PublicKeyDecrypter<CredentialVault>,
111 P: ParticipantPublicKeys,
112 {
113 let (credential_vault, credentials, mac_shared_secret) = envelope
114 .credential_vaults
115 .iter()
116 .fold(None, |acc, cv| match acc {
117 None => secret_keys
118 .decrypt::<Credentials>(cv, salts)
119 .ok()
120 .map(|c| (cv, c, secret_keys.mac_shared_secret(cv, salts))),
121 Some(_) => acc,
122 })
123 .ok_or(error::CryptError::DecryptionFailed)?;
124
125 let message_vault_passport = MessageVaultPassport::decrypt(&credentials.key, envelope)?;
126
127 if !(credentials.authenticate(
128 credential_vault,
129 public_keys,
130 &message_vault_passport.verifying_keys,
131 ) && message_vault_passport
132 .verifying_keys
133 .verify_mac(&mac_shared_secret, &credentials.verifying_keys_mac)
134 .is_ok())
135 {
136 return Err(error::CryptError::AuthenticationFailed);
137 }
138
139 Ok(OpenedEnvelope {
140 id: envelope.id,
141 message_vault_passport,
142 credentials,
143 })
144 }
145}
146
147#[cfg(any(feature = "reaching", feature = "reachable"))]
148pub use reaching_reachable::*;