1use 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
19pub 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
71pub 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
86pub 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
101pub 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
114pub 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}