1use std::io;
7
8use rand::{CryptoRng, Rng};
9
10use crate::{
11 native::{
12 self,
13 crypto::{hash::HashAlgorithm, public_key::PublicKeyAlgorithm},
14 types::{KeyId, KeyTrait, Mpi, PublicKeyTrait, SecretKeyRepr, SecretKeyTrait},
15 Message, PublicKey, PublicSubkey, SignedSecretKey, SignedSecretSubKey,
16 },
17 utils::spawn_blocking,
18 Error, Result,
19};
20
21#[derive(Debug)]
22pub enum PublicKeyOrSubkey {
23 Key(PublicKey),
24 Subkey(PublicSubkey),
25}
26
27#[derive(Debug)]
28pub enum SignedSecretKeyOrSubkey<'a> {
29 Key(&'a SignedSecretKey),
30 Subkey(&'a SignedSecretSubKey),
31}
32
33impl KeyTrait for SignedSecretKeyOrSubkey<'_> {
34 fn fingerprint(&self) -> Vec<u8> {
35 match self {
36 Self::Key(k) => k.fingerprint(),
37 Self::Subkey(k) => k.fingerprint(),
38 }
39 }
40
41 fn key_id(&self) -> KeyId {
42 match self {
43 Self::Key(k) => k.key_id(),
44 Self::Subkey(k) => k.key_id(),
45 }
46 }
47
48 fn algorithm(&self) -> PublicKeyAlgorithm {
49 match self {
50 Self::Key(k) => k.algorithm(),
51 Self::Subkey(k) => k.algorithm(),
52 }
53 }
54}
55
56impl PublicKeyTrait for SignedSecretKeyOrSubkey<'_> {
57 fn verify_signature(
58 &self,
59 hash: HashAlgorithm,
60 data: &[u8],
61 sig: &[Mpi],
62 ) -> native::errors::Result<()> {
63 match self {
64 Self::Key(k) => k.verify_signature(hash, data, sig),
65 Self::Subkey(k) => k.verify_signature(hash, data, sig),
66 }
67 }
68
69 fn encrypt<R: CryptoRng + Rng>(
70 &self,
71 rng: &mut R,
72 plain: &[u8],
73 ) -> native::errors::Result<Vec<Mpi>> {
74 match self {
75 Self::Key(k) => k.encrypt(rng, plain),
76 Self::Subkey(k) => k.encrypt(rng, plain),
77 }
78 }
79
80 fn to_writer_old(&self, writer: &mut impl io::Write) -> native::errors::Result<()> {
81 match self {
82 Self::Key(k) => k.to_writer_old(writer),
83 Self::Subkey(k) => k.to_writer_old(writer),
84 }
85 }
86}
87
88impl<'a> SecretKeyTrait for SignedSecretKeyOrSubkey<'a> {
89 type PublicKey = PublicKeyOrSubkey;
90
91 fn unlock<F, G>(&self, pw: F, work: G) -> native::errors::Result<()>
92 where
93 F: FnOnce() -> String,
94 G: FnOnce(&SecretKeyRepr) -> native::errors::Result<()>,
95 {
96 match self {
97 Self::Key(k) => k.unlock(pw, work),
98 Self::Subkey(k) => k.unlock(pw, work),
99 }
100 }
101
102 fn create_signature<F>(
103 &self,
104 key_pw: F,
105 hash: HashAlgorithm,
106 data: &[u8],
107 ) -> native::errors::Result<Vec<Mpi>>
108 where
109 F: FnOnce() -> String,
110 {
111 match self {
112 Self::Key(k) => k.create_signature(key_pw, hash, data),
113 Self::Subkey(k) => k.create_signature(key_pw, hash, data),
114 }
115 }
116
117 fn public_key(&self) -> Self::PublicKey {
118 match self {
119 Self::Key(k) => PublicKeyOrSubkey::Key(k.public_key()),
120 Self::Subkey(k) => PublicKeyOrSubkey::Subkey(k.public_key()),
121 }
122 }
123}
124
125fn find_skey_for_signing(key: &SignedSecretKey) -> Option<SignedSecretKeyOrSubkey> {
131 if key.is_signing_key() {
132 Some(SignedSecretKeyOrSubkey::Key(key))
133 } else {
134 key.secret_subkeys
135 .iter()
136 .find(|subkey| subkey.is_signing_key())
137 .map(SignedSecretKeyOrSubkey::Subkey)
138 }
139}
140
141pub async fn sign(
143 skey: SignedSecretKey,
144 passphrase: impl ToString,
145 plain_bytes: Vec<u8>,
146) -> Result<Vec<u8>> {
147 let passphrase = passphrase.to_string();
148
149 spawn_blocking(move || {
150 let skey = find_skey_for_signing(&skey).ok_or(Error::FindSignedSecretKeyForSigningError)?;
151
152 let msg = Message::new_literal_bytes("", &plain_bytes)
153 .sign(&skey, || passphrase, HashAlgorithm::SHA2_256)
154 .map_err(Error::SignMessageError)?;
155
156 let signature_bytes = msg
157 .into_signature()
158 .to_armored_bytes(None)
159 .map_err(Error::ExportSignedMessageToArmoredBytesError)?;
160
161 Ok(signature_bytes)
162 })
163 .await?
164}