pyrus_crypto/lib.rs
1//! # Pyrus Crypto
2//!
3//! This crate provides an OpenPGP inspired crypto system. It is
4//! based on generating certificates and using them to sign, encrypt
5//! and decrypt messages. Because it is designed for use in a larger
6//! application, this crate has some shortcomings. Mainly: symmetric
7//! encryption requires supplying a sender's certificate.
8//!
9//! # Warning!
10//!
11//! This is not a serious crypto crate. It has no tests and is not reviewed
12//! by third parties. It's security goes as far as the author's will
13//! to make his school project seem secure.
14//!
15//! # Examples
16//!
17//! ## Generate and serialize a certificate keeping its secret parts:
18//! ```rust
19//! # use std::error::Error;
20//! use pyrus_crypto::prelude::*;
21//!
22//! # fn main() -> Result<(), Box<dyn Error>> {
23//! let larry = Cert::new("Larry <larry@gentoo.org>");
24//! let cert_bytes = postcard::to_stdvec(&larry)?;
25//!
26//! //.. save the certificate
27//! // use the certificate here
28//! # Ok(())
29//! # }
30//! ```
31//!
32//! ## Encrypt a message symmetrically using a passphrase:
33//! ```rust
34//! # use std::error::Error;
35//! use pyrus_crypto::prelude::*;
36//!
37//! # fn main() -> Result<(), Box<dyn Error>> {
38//! let larry: Cert = //..
39//! # Cert::new("Larry <larry@gentoo.org>");
40//!
41//! let secret_text = b"This is a very secret message";
42//! let message = Message::new(&larry)?
43//! .write(&secret_text[..])?
44//! .encrypt_with(b"alcmdzmafia")? // don't use such passwords
45//! .finalize()?;
46//! # Ok(())
47//! # }
48//! ```
49//!
50//! ## Sign and encrypt a message asymmetrically:
51//!
52//! Note that the certificates are behind an [`std::sync::Arc`].
53//! This is how they will usually appear in the wild.
54//! ```rust
55//! # use std::error::Error;
56//! use pyrus_crypto::prelude::*;
57//! # use std::sync::Arc;
58//!
59//! # fn main() -> Result<(), Box<dyn Error>> {
60//! let larry: Arc<Cert> = //..
61//! # Arc::new(Cert::new("Larry <larry@gentoo.org>"));
62//! let agentcow: Arc<Cert> = //..
63//! # Arc::new(Cert::new("agentcow"));
64//! let agenthorse: Arc<Cert> = //..
65//! # Arc::new(Cert::new("agenthorse"));
66//! let agentfox: Arc<Cert> = //..
67//! # Arc::new(Cert::new("agentfox"));
68//! let friends = vec![agentcow.clone(), agenthorse.clone()];
69//!
70//! let secret_text = b"Let's meet up in the evening";
71//! let msg = Message::new(&larry)?
72//! .write(&secret_text[..])?
73//! .sign()
74//! .encrypt_for(&friends)?
75//! .finalize()?;
76//! # Ok(())
77//! # }
78//! ```
79//!
80//! ## Decrypt a symmetrically encrypted message
81//! ```rust
82//! # use std::error::Error;
83//! use pyrus_crypto::prelude::*;
84//!
85//! # fn main() -> Result<(), Box<dyn Error>> {
86//! # let larry: Cert = Cert::new("Larry <larry@gentoo.org>");
87//! # let secret_text = b"This is a very secret message";
88//! # let message = Message::new(&larry)?
89//! # .write(&secret_text[..])?
90//! # .encrypt_with(b"alcmdzmafia")? // don't use such passwords
91//! # .finalize()?;
92//! // another of the aforementioned shortcomings
93//! let dummy = Cert::new("dummy cert");
94//! // assume we already have a message
95//! let (_, content, sig) = message
96//! .parse(&dummy)?
97//! .decrypt_with(&b"alcmdzmafia"[..])?
98//! .finalize();
99//!
100//! assert_eq!(&secret_text[..], &content[..]);
101//! assert!(sig.is_none()); // the message is not signed
102//! # Ok(())
103//! # }
104//! ```
105//!
106//! ## Decrypt and verify a signed message
107//! ```rust
108//! # use std::error::Error;
109//! use pyrus_crypto::prelude::*;
110//! # use std::sync::Arc;
111//!
112//! # fn main() -> Result<(), Box<dyn Error>> {
113//! let larry: Arc<Cert> = //..
114//! # Arc::new(Cert::new("Larry <larry@gentoo.org>"));
115//! let agentcow: Arc<Cert> = //..
116//! # Arc::new(Cert::new("agentcow"));
117//! let agenthorse: Arc<Cert> = //..
118//! # Arc::new(Cert::new("agenthorse"));
119//! let agentfox: Arc<Cert> = //..
120//! # Arc::new(Cert::new("agentfox"));
121//! # let friends = vec![agentcow.clone(), agenthorse.clone()];
122//!
123//! let secret_text = b"Let's meet up in the evening";
124//! # let message = Message::new(&larry)?
125//! # .write(&secret_text[..])?
126//! # .sign()
127//! # .encrypt_for(&friends)?
128//! # .finalize()?;
129//! let (message, content, signature) = message
130//! .parse(&agentcow)? // decrypt using agentcow's certificate
131//! .decrypt(larry.clone())?
132//! .verify_signature(larry.clone())?
133//! .finalize();
134//!
135//! assert_eq!(&secret_text[..], &content[..]);
136//! assert!(signature.unwrap()); // signature is Some and is good
137//!
138//! let fail = message
139//! .parse(&agentfox)?
140//! .decrypt(larry.clone());
141//! assert!(fail.is_err()); // cannot decrypt, not a recipient
142//! # Ok(())
143//! # }
144//! ```
145
146/// Certificate generation and serialization.
147pub mod cert;
148/// Message creation and parsing.
149pub mod message;
150/// Cryptographic primitives, the foundation of this crate.
151pub mod crypto;
152/// [`CryptoError`](crate::error::CryptoError) type and
153/// [`Result<T>`](crate::error::Result) type specialization.
154pub mod error;
155/// Re-exports commonly used types
156pub mod prelude;
157
158/// Alias for the certificate's fingerprint type.
159///
160/// The hash type is [`blake3::Hash`].
161///
162/// # A note on equality
163/// To ensure constant time equality checking it is recommended to keep
164/// the type as is. Check the [`blake3`] crate documentation for more
165/// information.
166pub type Fingerprint = blake3::Hash;
167
168fn timestamp_bytes() -> [u8; 8] {
169 use std::time::{SystemTime, UNIX_EPOCH};
170 use rand_core::{OsRng, RngCore};
171 if let Ok(t) = SystemTime::now().duration_since(UNIX_EPOCH) {
172 let t = t.as_secs();
173 t.to_le_bytes()
174 } else {
175 let mut t = [0; 8];
176 OsRng.fill_bytes(&mut t);
177 t
178 }
179}