pg_core/client/mod.rs
1//! PostGuard client API.
2//!
3//! Used for:
4//! - Encrypting, signing, packing metadata (*sealing*),
5//! - Decrypting, verifying, unpacking metadata (*unsealing*).
6
7mod header;
8
9pub use header::{Algorithm, Header, Mode, RecipientHeader};
10
11#[cfg(feature = "rust")]
12pub mod rust;
13
14#[cfg(feature = "web")]
15pub mod web;
16
17use crate::artifacts::VerifyingKey;
18use crate::identity::Policy;
19use crate::util::*;
20use crate::{artifacts::SigningKeyExt, consts::*};
21use header::SignatureExt;
22use ibs::gg::Verifier;
23use serde::{Deserialize, Serialize};
24
25/// Returns a copy of a signing key whose policy is canonicalized.
26///
27/// The policy travels into the container, where a verifier derives the signer's
28/// identity from it. Canonicalizing it here means that identity matches the one
29/// the PKG derived when it issued this key — including for a verifier that
30/// predates the rule and derives the header bytes as they stand.
31pub(crate) fn canonical_signing_key(key: &SigningKeyExt) -> SigningKeyExt {
32 let mut key = key.clone();
33 key.policy.canonicalize();
34
35 key
36}
37
38/// A Sealer is used to encrypt and sign data using PostGuard.
39#[derive(Debug)]
40pub struct Sealer<'r, R, C> {
41 // The prebuilt header.
42 header: Header,
43
44 // An exclusive reference to a random number generator.
45 rng: &'r mut R,
46
47 // The flavor-specific configuration.
48 config: C,
49
50 // The public signing key. Used to sign public data, such as the header.
51 // The signature and claims are visible to outsiders.
52 pub_sign_key: SigningKeyExt,
53
54 // An optional private signing key.
55 // The signature and claims are encrypted and not visible to outsiders.
56 priv_sign_key: Option<SigningKeyExt>,
57}
58
59impl<'r, R, C> Sealer<'r, R, C> {
60 /// Add a private signing key and policy.
61 ///
62 /// This policy is safe to include private data as it is encrypted after signing.
63 pub fn with_priv_signing_key(mut self, mut priv_sign_key: SigningKeyExt) -> Self {
64 // See `canonical_signing_key`; this policy reaches the wire too.
65 priv_sign_key.policy.canonicalize();
66
67 self.priv_sign_key = Some(priv_sign_key);
68 self
69 }
70}
71
72/// An Unsealer is used to decrypt and verify data using PostGuard.
73///
74/// Unsealing is a two-step process:
75///
76/// 1. First the header is read. This yields information for whom the message is encrypted. Using
77/// this information the user can retrieve a user secret key.
78///
79/// 2. Then, the user has input the user secret key and the recipient for which decryption should
80/// take place.
81///
82/// Step 1 does *not* authenticate the sender. The [`pub_id`] read there is claimed, not bound to
83/// the ciphertext; only the [`VerificationResult`] returned by step 2 can carry a bound sender,
84/// and then only against a party on the wire and only for a container that carries the AEAD-side
85/// copy of the policy. Do not display step 1's identity as a verified sender.
86///
87/// [`pub_id`]: Unsealer#structfield.pub_id
88#[derive(Debug)]
89pub struct Unsealer<R, C: UnsealerConfig> {
90 /// The version found before the raw header.
91 pub version: u16,
92
93 /// The parsed header.
94 pub header: Header,
95
96 /// The sender identity *claimed* in the header.
97 ///
98 /// The header signature over it verifies, but nothing binds it to the ciphertext until
99 /// `unseal` returns: a container's header signature can be replaced by any party the PKG will
100 /// issue a signing key to (see <https://github.com/encryption4all/postguard/issues/338>). The
101 /// closest to a bound answer is the `public` field of the [`VerificationResult`] that `unseal`
102 /// returns, which catches that swap only for a container carrying the AEAD-side copy of the
103 /// policy and only against a party who does not hold the DEM key.
104 pub pub_id: Policy,
105
106 // The input.
107 r: R,
108
109 // The implementation-specific configuration.
110 config: C,
111
112 // The message verifier.
113 verifier: Verifier,
114
115 // The message verifier key.
116 vk: VerifyingKey,
117}
118
119/// Sender verification result.
120#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
121pub struct VerificationResult {
122 /// The public signing verified claims.
123 pub public: Policy,
124
125 /// The private signing verified claims.
126 #[serde(skip_serializing_if = "Option::is_none")]
127 pub private: Option<Policy>,
128}
129
130/// Sealer configuration.
131///
132/// This trait is sealed, you cannot implement it yourself.
133#[doc(hidden)]
134pub trait SealerConfig: sealed::SealerConfig {}
135
136/// Unsealer configuration.
137///
138/// This trait is sealed, you cannot implement it yourself.
139#[doc(hidden)]
140pub trait UnsealerConfig: sealed::UnsealerConfig {}
141
142pub(crate) mod sealed {
143 pub trait UnsealerConfig {}
144 pub trait SealerConfig {}
145}
146
147#[cfg(any(feature = "stream", target_arch = "wasm32"))]
148impl From<futures::io::Error> for crate::error::Error {
149 fn from(e: futures::io::Error) -> Self {
150 Self::FuturesIO(e)
151 }
152}
153
154#[cfg(feature = "stream")]
155fn stream_mode_checked(h: &Header) -> Result<(u32, (u64, Option<u64>)), crate::error::Error> {
156 let (segment_size, size_hint) = match h {
157 Header {
158 mode:
159 Mode::Streaming {
160 segment_size,
161 size_hint,
162 },
163 ..
164 } => (segment_size, size_hint),
165 _ => return Err(crate::error::Error::ModeNotSupported(h.mode)),
166 };
167
168 if *segment_size > MAX_SYMMETRIC_CHUNK_SIZE {
169 return Err(crate::error::Error::ConstraintViolation);
170 }
171
172 Ok((*segment_size, *size_hint))
173}