sequoia_openpgp/crypto/mod.rs
1//! Cryptographic primitives.
2//!
3//! This module contains cryptographic primitives as defined and used
4//! by OpenPGP. It abstracts over the cryptographic library chosen at
5//! compile time. Most of the time, it will not be necessary to
6//! explicitly use types from this module directly, but they are used
7//! in the API (e.g. [`Password`]). Advanced users may use these
8//! primitives to provide custom extensions to OpenPGP.
9//!
10//!
11//! # Common Operations
12//!
13//! - *Converting a string to a [`Password`]*: Use [`Password::from`].
14//! - *Create a session key*: Use [`SessionKey::new`].
15//! - *Use secret keys*: See the [`KeyPair` example].
16//!
17//! [`Password::from`]: std::convert::From
18//! [`SessionKey::new`]: SessionKey::new()
19//! [`KeyPair` example]: KeyPair#examples
20
21use std::cmp::Ordering;
22use std::ops::{Deref, DerefMut};
23use std::fmt;
24use std::borrow::Cow;
25
26use crate::{
27 Error,
28 Result,
29};
30
31pub mod aead;
32mod asymmetric;
33pub use self::asymmetric::{Signer, Decryptor, KeyPair};
34pub(crate) mod backend;
35pub mod ecdh;
36pub mod hash;
37mod key;
38pub mod mem;
39pub mod mpi;
40mod s2k;
41pub use s2k::S2K;
42pub mod symmetric;
43mod types;
44pub use types::{
45 AEADAlgorithm,
46 Curve,
47 HashAlgorithm,
48 PublicKeyAlgorithm,
49 SymmetricAlgorithm,
50};
51#[cfg(test)]
52mod tests;
53
54/// Returns a short, human-readable description of the backend.
55///
56/// This starts with the name of the backend, possibly a version, and
57/// any optional features that are available. This is meant for
58/// inclusion in version strings to improve bug reports.
59pub fn backend() -> String {
60 use backend::interface::Backend;
61 backend::Backend::backend()
62}
63
64/// Fills the given buffer with random data.
65///
66/// Fills the given buffer with random data produced by a
67/// cryptographically secure pseudorandom number generator (CSPRNG).
68/// The output may be used as session keys or to derive long-term
69/// cryptographic keys from. However, to create session keys,
70/// consider using [`SessionKey::new`].
71///
72/// [`SessionKey::new`]: crate::crypto::SessionKey::new()
73pub fn random<B: AsMut<[u8]>>(mut buf: B) -> Result<()> {
74 use backend::interface::Backend;
75 backend::Backend::random(buf.as_mut())
76}
77
78/// Holds a session key.
79///
80/// The session key is cleared when dropped. Sequoia uses this type
81/// to ensure that session keys are not left in memory returned to the
82/// allocator.
83///
84/// Session keys can be generated using [`SessionKey::new`], or
85/// converted from various types using [`From`].
86///
87/// [`SessionKey::new`]: SessionKey::new()
88/// [`From`]: std::convert::From
89#[derive(Clone, PartialEq, Eq)]
90pub struct SessionKey(mem::Protected);
91assert_send_and_sync!(SessionKey);
92
93impl SessionKey {
94 /// Creates a new session key.
95 ///
96 /// Creates a new session key `size` bytes in length initialized
97 /// using a strong cryptographic number generator.
98 ///
99 /// # Examples
100 ///
101 /// This creates a session key and encrypts it for a given
102 /// recipient key producing a [`PKESK`] packet.
103 ///
104 /// [`PKESK`]: crate::packet::PKESK
105 ///
106 /// ```
107 /// # fn main() -> sequoia_openpgp::Result<()> {
108 /// use sequoia_openpgp as openpgp;
109 /// use openpgp::types::{Curve, SymmetricAlgorithm};
110 /// use openpgp::crypto::SessionKey;
111 /// use openpgp::packet::prelude::*;
112 ///
113 /// let cipher = SymmetricAlgorithm::AES256;
114 /// let sk = SessionKey::new(cipher.key_size()?)?;
115 ///
116 /// let key: Key<key::SecretParts, key::UnspecifiedRole> =
117 /// Key6::generate_ecc(false, Curve::Cv25519)?.into();
118 ///
119 /// let pkesk: PKESK =
120 /// PKESK3::for_recipient(cipher, &sk, &key)?.into();
121 /// # Ok(()) }
122 /// ```
123 pub fn new(size: usize) -> Result<Self> {
124 let mut sk: mem::Protected = vec![0; size].into();
125 random(&mut sk)?;
126 Ok(Self(sk))
127 }
128
129 /// Returns a reference to the inner [`mem::Protected`].
130 pub fn as_protected(&self) -> &mem::Protected {
131 &self.0
132 }
133}
134
135impl Deref for SessionKey {
136 type Target = [u8];
137
138 fn deref(&self) -> &Self::Target {
139 &self.0
140 }
141}
142
143impl AsRef<[u8]> for SessionKey {
144 fn as_ref(&self) -> &[u8] {
145 &self.0
146 }
147}
148
149impl DerefMut for SessionKey {
150 fn deref_mut(&mut self) -> &mut [u8] {
151 &mut self.0
152 }
153}
154
155impl AsMut<[u8]> for SessionKey {
156 fn as_mut(&mut self) -> &mut [u8] {
157 &mut self.0
158 }
159}
160
161impl From<mem::Protected> for SessionKey {
162 fn from(v: mem::Protected) -> Self {
163 SessionKey(v)
164 }
165}
166
167impl From<Vec<u8>> for SessionKey {
168 fn from(v: Vec<u8>) -> Self {
169 SessionKey(v.into())
170 }
171}
172
173impl From<Box<[u8]>> for SessionKey {
174 fn from(v: Box<[u8]>) -> Self {
175 SessionKey(v.into())
176 }
177}
178
179impl From<&[u8]> for SessionKey {
180 fn from(v: &[u8]) -> Self {
181 Vec::from(v).into()
182 }
183}
184
185impl fmt::Debug for SessionKey {
186 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
187 write!(f, "SessionKey ({:?})", self.0)
188 }
189}
190
191/// Holds a password.
192///
193/// `Password`s can be converted from various types using [`From`].
194/// The password is encrypted in memory and only decrypted on demand.
195/// See [`mem::Encrypted`] for details.
196///
197/// [`From`]: std::convert::From
198///
199/// # Examples
200///
201/// ```
202/// use sequoia_openpgp as openpgp;
203/// use openpgp::crypto::Password;
204///
205/// // Convert from a &str.
206/// let p: Password = "hunter2".into();
207///
208/// // Convert from a &[u8].
209/// let p: Password = b"hunter2"[..].into();
210///
211/// // Convert from a String.
212/// let p: Password = String::from("hunter2").into();
213///
214/// // ...
215/// ```
216#[derive(Clone, PartialEq, Eq)]
217pub struct Password(mem::Encrypted);
218assert_send_and_sync!(Password);
219
220impl From<Vec<u8>> for Password {
221 fn from(v: Vec<u8>) -> Self {
222 Password(mem::Encrypted::new(v.into())
223 .expect("encrypting memory failed"))
224 }
225}
226
227impl From<Box<[u8]>> for Password {
228 fn from(v: Box<[u8]>) -> Self {
229 Password(mem::Encrypted::new(v.into())
230 .expect("encrypting memory failed"))
231 }
232}
233
234impl From<String> for Password {
235 fn from(v: String) -> Self {
236 v.into_bytes().into()
237 }
238}
239
240impl<'a> From<&'a str> for Password {
241 fn from(v: &'a str) -> Self {
242 v.to_owned().into()
243 }
244}
245
246impl From<&[u8]> for Password {
247 fn from(v: &[u8]) -> Self {
248 Vec::from(v).into()
249 }
250}
251
252impl fmt::Debug for Password {
253 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
254 if cfg!(debug_assertions) {
255 self.map(|p| write!(f, "Password({:?})", p))
256 } else {
257 f.write_str("Password(<Encrypted>)")
258 }
259 }
260}
261
262impl Password {
263 /// Maps the given function over the password.
264 ///
265 /// The password is stored encrypted in memory. This function
266 /// temporarily decrypts it for the given function to use.
267 ///
268 /// # Examples
269 ///
270 /// ```
271 /// use sequoia_openpgp as openpgp;
272 /// use openpgp::crypto::Password;
273 ///
274 /// let p: Password = "hunter2".into();
275 /// p.map(|p| assert_eq!(p.as_ref(), &b"hunter2"[..]));
276 /// ```
277 pub fn map<F, T>(&self, fun: F) -> T
278 where F: FnMut(&mem::Protected) -> T
279 {
280 self.0.map(fun)
281 }
282}
283
284/// Returns the value zero-padded to the given length.
285///
286/// Some encodings strip leading zero-bytes. This function adds them
287/// back, if necessary. If the size exceeds `to`, an error is
288/// returned.
289pub(crate) fn pad(value: &[u8], to: usize) -> Result<Cow<'_, [u8]>>
290{
291 match value.len().cmp(&to) {
292 Ordering::Equal => Ok(Cow::Borrowed(value)),
293 Ordering::Less => {
294 let missing = to - value.len();
295 let mut v = vec![0; to];
296 v[missing..].copy_from_slice(value);
297 Ok(Cow::Owned(v))
298 }
299 Ordering::Greater => {
300 Err(Error::InvalidOperation(
301 format!("Input value is longer than expected: {} > {}",
302 value.len(), to)).into())
303 }
304 }
305}
306
307/// Returns the value zero-padded to the given length.
308///
309/// Some encodings strip leading zero-bytes. This function adds them
310/// back, if necessary. If the size exceeds `to`, the value is
311/// returned as-is.
312#[allow(dead_code)]
313pub(crate) fn pad_at_least(value: &[u8], to: usize) -> Cow<'_, [u8]>
314{
315 pad(value, to).unwrap_or(Cow::Borrowed(value))
316}
317
318/// Returns the value zero-padded or truncated to the given length.
319///
320/// Some encodings strip leading zero-bytes. This function adds them
321/// back, if necessary. If the size exceeds `to`, the value is
322/// silently truncated.
323#[allow(dead_code)]
324pub(crate) fn pad_truncating(value: &[u8], to: usize) -> Cow<'_, [u8]>
325{
326 if value.len() == to {
327 Cow::Borrowed(value)
328 } else {
329 let missing = to.saturating_sub(value.len());
330 let limit = value.len().min(to);
331 let mut v = vec![0; to];
332 v[missing..].copy_from_slice(&value[..limit]);
333 Cow::Owned(v)
334 }
335}
336
337/// Compares two arbitrary-sized big-endian integers.
338///
339/// Note that the tempting `a < b` doesn't work: it computes the
340/// lexicographical order, so that `[2] > [1, 2]`, whereas we want
341/// `[2] < [1, 2]`.
342pub(crate) fn raw_bigint_cmp(mut a: &[u8], mut b: &[u8]) -> Ordering {
343 // First, trim leading zeros.
344 while a.get(0) == Some(&0) {
345 a = &a[1..];
346 }
347
348 while b.get(0) == Some(&0) {
349 b = &b[1..];
350 }
351
352 // Then, compare their length. Shorter integers are also smaller.
353 a.len().cmp(&b.len())
354 // Finally, if their length is equal, do a lexicographical
355 // comparison.
356 .then_with(|| a.cmp(b))
357}
358
359/// Given the secret prime values `p` and `q`, returns the pair of
360/// primes so that the smaller one comes first.
361///
362/// Section 5.5.3 of RFC4880 demands that `p < q`. This function can
363/// be used to order `p` and `q` accordingly.
364#[allow(dead_code)]
365pub(crate) fn rsa_sort_raw_pq<'a>(p: &'a [u8], q: &'a [u8])
366 -> (&'a [u8], &'a [u8])
367{
368 match raw_bigint_cmp(p, q) {
369 Ordering::Less => (p, q),
370 Ordering::Equal => (p, q),
371 Ordering::Greater => (q, p),
372 }
373}