pgp/
utils.rs

1//! # Utils
2//!
3//! Module dedicated to PGP helpers.
4
5use std::{fs, io::Cursor, path::PathBuf};
6
7use smallvec::smallvec;
8
9use crate::{
10    native::{
11        crypto::{hash::HashAlgorithm, sym::SymmetricKeyAlgorithm},
12        types::{CompressionAlgorithm, SecretKeyTrait},
13        Deserializable, KeyType, SecretKeyParamsBuilder, SignedPublicKey, SignedSecretKey,
14        StandaloneSignature, SubkeyParamsBuilder,
15    },
16    Error, Result,
17};
18
19/// Generates a new pair of secret and public keys for the given email
20/// address and passphrase.
21pub async fn gen_key_pair(
22    email: impl ToString,
23    passphrase: impl ToString,
24) -> Result<(SignedSecretKey, SignedPublicKey)> {
25    let email = email.to_string();
26    let passphrase = passphrase.to_string();
27    let passphrase = if passphrase.trim().is_empty() {
28        None
29    } else {
30        Some(passphrase)
31    };
32
33    spawn_blocking(move || {
34        let key_params = SecretKeyParamsBuilder::default()
35            .key_type(KeyType::EdDSA)
36            .can_create_certificates(true)
37            .can_sign(true)
38            .primary_user_id(email)
39            .passphrase(passphrase.clone())
40            .preferred_symmetric_algorithms(smallvec![SymmetricKeyAlgorithm::AES256])
41            .preferred_hash_algorithms(smallvec![HashAlgorithm::SHA2_256])
42            .preferred_compression_algorithms(smallvec![CompressionAlgorithm::ZLIB])
43            .subkey(
44                SubkeyParamsBuilder::default()
45                    .key_type(KeyType::ECDH)
46                    .can_encrypt(true)
47                    .passphrase(passphrase)
48                    .build()
49                    .map_err(Error::BuildPublicKeyParamsError)?,
50            )
51            .build()
52            .map_err(Error::BuildSecretKeyParamsError)?;
53
54        let skey = key_params
55            .generate()
56            .map_err(Error::GenerateSecretKeyError)?;
57        let skey = skey.sign(String::new).map_err(Error::SignSecretKeyError)?;
58        skey.verify().map_err(Error::VerifySecretKeyError)?;
59
60        let pkey = skey.public_key();
61        let pkey = pkey
62            .sign(&skey, String::new)
63            .map_err(Error::SignPublicKeyError)?;
64        pkey.verify().map_err(Error::VerifyPublicKeyError)?;
65
66        Ok((skey, pkey))
67    })
68    .await?
69}
70
71/// Reads a signed public key from the given path.
72///
73/// The given path needs to contain a single armored secret key,
74/// otherwise it fails.
75pub async fn read_pkey_from_path(path: PathBuf) -> Result<SignedPublicKey> {
76    spawn_blocking(move || {
77        let data =
78            fs::read(&path).map_err(|err| Error::ReadArmoredPublicKeyError(err, path.clone()))?;
79        let (pkey, _) = SignedPublicKey::from_armor_single(Cursor::new(data))
80            .map_err(|err| Error::ParseArmoredPublicKeyError(err, path.clone()))?;
81        Ok(pkey)
82    })
83    .await?
84}
85
86/// Reads a signed secret key from the given path.
87///
88/// The given path needs to contain a single armored secret key,
89/// otherwise it fails.
90pub async fn read_skey_from_file(path: PathBuf) -> Result<SignedSecretKey> {
91    spawn_blocking(move || {
92        let data = fs::read(&path)
93            .map_err(|err| Error::ReadArmoredSecretKeyFromPathError(err, path.clone()))?;
94        let (skey, _) = SignedSecretKey::from_armor_single(Cursor::new(data))
95            .map_err(|err| Error::ParseArmoredSecretKeyFromPathError(err, path.clone()))?;
96        Ok(skey)
97    })
98    .await?
99}
100
101/// Reads a signed secret key from the given raw string.
102///
103/// The given raw string needs to contain a single armored secret key,
104/// otherwise it fails.
105pub async fn read_skey_from_string(string: String) -> Result<SignedSecretKey> {
106    spawn_blocking(move || {
107        let (skey, _) = SignedSecretKey::from_armor_single(Cursor::new(string))
108            .map_err(Error::ParseArmoredSecretKeyFromStringError)?;
109        Ok(skey)
110    })
111    .await?
112}
113
114/// Reads a standalone signature from the given raw bytes.
115///
116/// The given raw bytes needs to match a single armored signature,
117/// otherwise it fails.
118pub async fn read_sig_from_bytes(bytes: Vec<u8>) -> Result<StandaloneSignature> {
119    spawn_blocking(move || {
120        let (sig, _) = StandaloneSignature::from_armor_single(Cursor::new(&bytes))
121            .map_err(Error::ReadStandaloneSignatureFromArmoredBytesError)?;
122        Ok(sig)
123    })
124    .await?
125}
126
127#[cfg(feature = "key-discovery")]
128#[cfg(feature = "async-std")]
129pub(crate) async fn spawn<F>(f: F) -> Result<F::Output>
130where
131    F: std::future::Future + Send + 'static,
132    F::Output: Send + 'static,
133{
134    Ok(async_std::task::spawn(f).await)
135}
136
137#[cfg(feature = "async-std")]
138pub(crate) async fn spawn_blocking<F, T>(f: F) -> Result<T>
139where
140    F: FnOnce() -> T + Send + 'static,
141    T: Send + 'static,
142{
143    Ok(async_std::task::spawn_blocking(f).await)
144}
145
146#[cfg(feature = "key-discovery")]
147#[cfg(feature = "tokio")]
148pub(crate) async fn spawn<F>(f: F) -> Result<F::Output>
149where
150    F: std::future::Future + Send + 'static,
151    F::Output: Send + 'static,
152{
153    Ok(tokio::task::spawn(f).await?)
154}
155
156#[cfg(feature = "tokio")]
157pub(crate) async fn spawn_blocking<F, T>(f: F) -> Result<T>
158where
159    F: FnOnce() -> T + Send + 'static,
160    T: Send + 'static,
161{
162    Ok(tokio::task::spawn_blocking(f).await?)
163}