pgp/types/
key_traits.rs

1use crate::{
2    crypto::{
3        hash::{HashAlgorithm, KnownDigest},
4        public_key::PublicKeyAlgorithm,
5    },
6    errors::Result,
7    types::{Fingerprint, KeyId, KeyVersion, Password, PublicParams, SignatureBytes},
8};
9
10pub trait KeyDetails {
11    fn version(&self) -> KeyVersion;
12    fn fingerprint(&self) -> Fingerprint;
13    fn key_id(&self) -> KeyId;
14    fn algorithm(&self) -> PublicKeyAlgorithm;
15}
16
17pub trait Imprint {
18    /// An imprint is a shorthand identifier for a key.
19    ///
20    /// The imprint is a generalization of the
21    /// [OpenPGP fingerprint](https://www.rfc-editor.org/rfc/rfc9580.html#key-ids-fingerprints).
22    /// It is calculated over the public key parameters and other non-secret inputs (depending on
23    /// the key version), in the same way as the fingerprint.
24    /// However, the imprint may use a digest algorithm other than the one specified for the
25    /// fingerprint of the given key version.
26    ///
27    /// See <https://www.ietf.org/archive/id/draft-ietf-openpgp-replacementkey-03.html#name-key-imprints>
28    ///
29    /// NOTE: Imprints are a special purpose tool! For most use cases, the OpenPGP fingerprint is
30    /// the most appropriate identifier for a certificate or a component key.
31    fn imprint<D: KnownDigest>(&self) -> Result<generic_array::GenericArray<u8, D::OutputSize>>;
32}
33
34pub trait PublicKeyTrait: KeyDetails + std::fmt::Debug {
35    fn created_at(&self) -> &chrono::DateTime<chrono::Utc>;
36    fn expiration(&self) -> Option<u16>;
37
38    /// Verify a signed message.
39    /// Data will be hashed using `hash`, before verifying.
40    fn verify_signature(
41        &self,
42        hash: HashAlgorithm,
43        data: &[u8],
44        sig: &SignatureBytes,
45    ) -> Result<()>;
46
47    fn public_params(&self) -> &PublicParams;
48
49    fn is_signing_key(&self) -> bool {
50        use crate::crypto::public_key::PublicKeyAlgorithm::*;
51
52        #[cfg(feature = "draft-pqc")]
53        if matches!(
54            self.algorithm(),
55            MlDsa65Ed25519 | MlDsa87Ed448 | SlhDsaShake128s | SlhDsaShake128f | SlhDsaShake256s
56        ) {
57            return true;
58        }
59
60        matches!(
61            self.algorithm(),
62            RSA | RSASign | Elgamal | DSA | ECDSA | EdDSALegacy | Ed25519 | Ed448
63        )
64    }
65
66    fn is_encryption_key(&self) -> bool {
67        use crate::crypto::public_key::PublicKeyAlgorithm::*;
68
69        #[cfg(feature = "draft-pqc")]
70        if matches!(self.algorithm(), MlKem768X25519 | MlKem1024X448) {
71            return true;
72        }
73
74        matches!(
75            self.algorithm(),
76            RSA | RSAEncrypt | ECDH | DiffieHellman | Elgamal | ElgamalEncrypt | X25519 | X448
77        )
78    }
79}
80
81impl<T: KeyDetails> KeyDetails for &T {
82    fn version(&self) -> KeyVersion {
83        (*self).version()
84    }
85
86    fn fingerprint(&self) -> Fingerprint {
87        (*self).fingerprint()
88    }
89
90    /// Returns the Key ID of the associated primary key.
91    fn key_id(&self) -> KeyId {
92        (*self).key_id()
93    }
94
95    fn algorithm(&self) -> PublicKeyAlgorithm {
96        (*self).algorithm()
97    }
98}
99
100impl<T: PublicKeyTrait> PublicKeyTrait for &T {
101    fn verify_signature(
102        &self,
103        hash: HashAlgorithm,
104        data: &[u8],
105        sig: &SignatureBytes,
106    ) -> Result<()> {
107        (*self).verify_signature(hash, data, sig)
108    }
109
110    fn public_params(&self) -> &PublicParams {
111        (*self).public_params()
112    }
113
114    fn expiration(&self) -> Option<u16> {
115        (*self).expiration()
116    }
117
118    fn created_at(&self) -> &chrono::DateTime<chrono::Utc> {
119        (*self).created_at()
120    }
121}
122
123impl KeyDetails for Box<&dyn SecretKeyTrait> {
124    fn version(&self) -> KeyVersion {
125        (**self).version()
126    }
127
128    fn fingerprint(&self) -> Fingerprint {
129        (**self).fingerprint()
130    }
131
132    fn key_id(&self) -> KeyId {
133        (**self).key_id()
134    }
135
136    fn algorithm(&self) -> PublicKeyAlgorithm {
137        (**self).algorithm()
138    }
139}
140
141impl SecretKeyTrait for Box<&dyn SecretKeyTrait> {
142    fn create_signature(
143        &self,
144        key_pw: &Password,
145        hash: HashAlgorithm,
146        data: &[u8],
147    ) -> Result<crate::types::SignatureBytes> {
148        (**self).create_signature(key_pw, hash, data)
149    }
150
151    fn hash_alg(&self) -> HashAlgorithm {
152        (**self).hash_alg()
153    }
154}
155
156pub trait SecretKeyTrait: KeyDetails + std::fmt::Debug {
157    fn create_signature(
158        &self,
159        key_pw: &Password,
160        hash: HashAlgorithm,
161        data: &[u8],
162    ) -> Result<crate::types::SignatureBytes>;
163
164    /// The recommended hash algorithm to calculate the signature hash digest with,
165    /// when using this as a signer
166    fn hash_alg(&self) -> HashAlgorithm;
167}