dsa/
signing_key.rs

1//!
2//! Module containing the definition of the private key container
3//!
4
5use crate::{Components, Signature, VerifyingKey, OID};
6use core::{
7    cmp::min,
8    fmt::{self, Debug},
9};
10use digest::{core_api::BlockSizeUser, Digest, FixedOutputReset};
11use num_bigint::BigUint;
12use num_traits::Zero;
13use pkcs8::{
14    der::{asn1::UintRef, AnyRef, Decode, Encode},
15    AlgorithmIdentifierRef, EncodePrivateKey, PrivateKeyInfo, SecretDocument,
16};
17use signature::{
18    hazmat::{PrehashSigner, RandomizedPrehashSigner},
19    rand_core::CryptoRngCore,
20    DigestSigner, RandomizedDigestSigner, Signer,
21};
22use zeroize::{Zeroize, Zeroizing};
23
24/// DSA private key.
25///
26/// The [`(try_)sign_digest_with_rng`](::signature::RandomizedDigestSigner) API uses regular non-deterministic signatures,
27/// while the [`(try_)sign_digest`](::signature::DigestSigner) API uses deterministic signatures as described in RFC 6979
28#[derive(Clone, PartialEq)]
29#[must_use]
30pub struct SigningKey {
31    /// Public key
32    verifying_key: VerifyingKey,
33
34    /// Private component x
35    x: Zeroizing<BigUint>,
36}
37
38impl SigningKey {
39    /// Construct a new private key from the public key and private component
40    pub fn from_components(verifying_key: VerifyingKey, x: BigUint) -> signature::Result<Self> {
41        if x.is_zero() || x > *verifying_key.components().q() {
42            return Err(signature::Error::new());
43        }
44
45        Ok(Self {
46            verifying_key,
47            x: Zeroizing::new(x),
48        })
49    }
50
51    /// Generate a new DSA keypair
52    #[inline]
53    pub fn generate(rng: &mut impl CryptoRngCore, components: Components) -> SigningKey {
54        crate::generate::keypair(rng, components)
55    }
56
57    /// DSA public key
58    pub const fn verifying_key(&self) -> &VerifyingKey {
59        &self.verifying_key
60    }
61
62    /// DSA private component
63    ///
64    /// If you decide to clone this value, please consider using [`Zeroize::zeroize`](::zeroize::Zeroize::zeroize()) to zero out the memory after you're done using the clone
65    #[must_use]
66    pub fn x(&self) -> &BigUint {
67        &self.x
68    }
69
70    /// Try to sign the given message digest deterministically with a prehashed digest.
71    /// The parameter `D` must match the hash function used to sign the digest.
72    ///
73    /// [RFC6979]: https://datatracker.ietf.org/doc/html/rfc6979
74    pub fn sign_prehashed_rfc6979<D>(&self, prehash: &[u8]) -> Result<Signature, signature::Error>
75    where
76        D: Digest + BlockSizeUser + FixedOutputReset,
77    {
78        let k_kinv = crate::generate::secret_number_rfc6979::<D>(self, prehash);
79        self.sign_prehashed(k_kinv, prehash)
80    }
81
82    /// Sign some pre-hashed data
83    fn sign_prehashed(
84        &self,
85        (k, inv_k): (BigUint, BigUint),
86        hash: &[u8],
87    ) -> signature::Result<Signature> {
88        let components = self.verifying_key().components();
89        let (p, q, g) = (components.p(), components.q(), components.g());
90        let x = self.x();
91
92        let r = g.modpow(&k, p) % q;
93
94        let n = q.bits() / 8;
95        let block_size = hash.len(); // Hash function output size
96
97        let z_len = min(n, block_size);
98        let z = BigUint::from_bytes_be(&hash[..z_len]);
99
100        let s = (inv_k * (z + x * &r)) % q;
101
102        let signature = Signature::from_components(r, s)?;
103
104        if signature.r() < q && signature.s() < q {
105            Ok(signature)
106        } else {
107            Err(signature::Error::new())
108        }
109    }
110}
111
112impl Signer<Signature> for SigningKey {
113    fn try_sign(&self, msg: &[u8]) -> Result<Signature, signature::Error> {
114        let digest = sha2::Sha256::new_with_prefix(msg);
115        self.try_sign_digest(digest)
116    }
117}
118
119impl PrehashSigner<Signature> for SigningKey {
120    /// Warning: This uses `sha2::Sha256` as the hash function for the digest. If you need to use a different one, use [`SigningKey::sign_prehashed_rfc6979`].
121    fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature, signature::Error> {
122        let k_kinv = crate::generate::secret_number_rfc6979::<sha2::Sha256>(self, prehash);
123        self.sign_prehashed(k_kinv, prehash)
124    }
125}
126
127impl RandomizedPrehashSigner<Signature> for SigningKey {
128    fn sign_prehash_with_rng(
129        &self,
130        mut rng: &mut impl CryptoRngCore,
131        prehash: &[u8],
132    ) -> Result<Signature, signature::Error> {
133        let components = self.verifying_key.components();
134
135        if let Some(k_kinv) = crate::generate::secret_number(&mut rng, components) {
136            self.sign_prehashed(k_kinv, prehash)
137        } else {
138            Err(signature::Error::new())
139        }
140    }
141}
142
143impl<D> DigestSigner<D, Signature> for SigningKey
144where
145    D: Digest + BlockSizeUser + FixedOutputReset,
146{
147    fn try_sign_digest(&self, digest: D) -> Result<Signature, signature::Error> {
148        let hash = digest.finalize_fixed();
149        let ks = crate::generate::secret_number_rfc6979::<D>(self, &hash);
150
151        self.sign_prehashed(ks, &hash)
152    }
153}
154
155impl<D> RandomizedDigestSigner<D, Signature> for SigningKey
156where
157    D: Digest,
158{
159    fn try_sign_digest_with_rng(
160        &self,
161        mut rng: &mut impl CryptoRngCore,
162        digest: D,
163    ) -> Result<Signature, signature::Error> {
164        let ks = crate::generate::secret_number(&mut rng, self.verifying_key().components())
165            .ok_or_else(signature::Error::new)?;
166        let hash = digest.finalize();
167
168        self.sign_prehashed(ks, &hash)
169    }
170}
171
172impl EncodePrivateKey for SigningKey {
173    fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
174        let parameters = self.verifying_key().components().to_der()?;
175        let parameters = AnyRef::from_der(&parameters)?;
176        let algorithm = AlgorithmIdentifierRef {
177            oid: OID,
178            parameters: Some(parameters),
179        };
180
181        let mut x_bytes = self.x().to_bytes_be();
182        let x = UintRef::new(&x_bytes)?;
183        let mut signing_key = x.to_der()?;
184
185        let signing_key_info = PrivateKeyInfo::new(algorithm, &signing_key);
186        let secret_document = signing_key_info.try_into()?;
187
188        signing_key.zeroize();
189        x_bytes.zeroize();
190
191        Ok(secret_document)
192    }
193}
194
195impl<'a> TryFrom<PrivateKeyInfo<'a>> for SigningKey {
196    type Error = pkcs8::Error;
197
198    fn try_from(value: PrivateKeyInfo<'a>) -> Result<Self, Self::Error> {
199        value.algorithm.assert_algorithm_oid(OID)?;
200
201        let parameters = value.algorithm.parameters_any()?;
202        let components = parameters.decode_as::<Components>()?;
203
204        let x = UintRef::from_der(value.private_key)?;
205        let x = BigUint::from_bytes_be(x.as_bytes());
206
207        let y = if let Some(y_bytes) = value.public_key {
208            let y = UintRef::from_der(y_bytes)?;
209            BigUint::from_bytes_be(y.as_bytes())
210        } else {
211            crate::generate::public_component(&components, &x)
212        };
213
214        let verifying_key =
215            VerifyingKey::from_components(components, y).map_err(|_| pkcs8::Error::KeyMalformed)?;
216
217        SigningKey::from_components(verifying_key, x).map_err(|_| pkcs8::Error::KeyMalformed)
218    }
219}
220
221impl Debug for SigningKey {
222    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223        f.debug_struct("SigningKey")
224            .field("verifying_key", &self.verifying_key)
225            .finish_non_exhaustive()
226    }
227}