ssh_key/private/
dsa.rs

1//! Digital Signature Algorithm (DSA) private keys.
2
3use crate::{public::DsaPublicKey, Error, Mpint, Result};
4use core::fmt;
5use encoding::{CheckedSum, Decode, Encode, Reader, Writer};
6use subtle::{Choice, ConstantTimeEq};
7use zeroize::Zeroize;
8
9#[cfg(all(feature = "dsa", feature = "rand_core"))]
10use rand_core::CryptoRngCore;
11
12/// Digital Signature Algorithm (DSA) private key.
13///
14/// Uniformly random integer `x`, such that `0 < x < q`, i.e. `x` is in the
15/// range `[1, q–1]`.
16///
17/// Described in [FIPS 186-4 § 4.1](https://csrc.nist.gov/publications/detail/fips/186/4/final).
18#[derive(Clone)]
19pub struct DsaPrivateKey {
20    /// Integer representing a DSA private key.
21    inner: Mpint,
22}
23
24impl DsaPrivateKey {
25    /// Get the serialized private key as bytes.
26    pub fn as_bytes(&self) -> &[u8] {
27        self.inner.as_bytes()
28    }
29
30    /// Get the inner [`Mpint`].
31    pub fn as_mpint(&self) -> &Mpint {
32        &self.inner
33    }
34}
35
36impl AsRef<[u8]> for DsaPrivateKey {
37    fn as_ref(&self) -> &[u8] {
38        self.as_bytes()
39    }
40}
41
42impl ConstantTimeEq for DsaPrivateKey {
43    fn ct_eq(&self, other: &Self) -> Choice {
44        self.inner.ct_eq(&other.inner)
45    }
46}
47
48impl Eq for DsaPrivateKey {}
49
50impl PartialEq for DsaPrivateKey {
51    fn eq(&self, other: &Self) -> bool {
52        self.ct_eq(other).into()
53    }
54}
55
56impl Decode for DsaPrivateKey {
57    type Error = Error;
58
59    fn decode(reader: &mut impl Reader) -> Result<Self> {
60        Ok(Self {
61            inner: Mpint::decode(reader)?,
62        })
63    }
64}
65
66impl Encode for DsaPrivateKey {
67    fn encoded_len(&self) -> encoding::Result<usize> {
68        self.inner.encoded_len()
69    }
70
71    fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
72        self.inner.encode(writer)
73    }
74}
75
76impl fmt::Debug for DsaPrivateKey {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        f.debug_struct("DsaPrivateKey").finish_non_exhaustive()
79    }
80}
81
82impl Drop for DsaPrivateKey {
83    fn drop(&mut self) {
84        self.inner.zeroize();
85    }
86}
87
88#[cfg(feature = "dsa")]
89impl TryFrom<DsaPrivateKey> for dsa::BigUint {
90    type Error = Error;
91
92    fn try_from(key: DsaPrivateKey) -> Result<dsa::BigUint> {
93        dsa::BigUint::try_from(&key.inner)
94    }
95}
96
97#[cfg(feature = "dsa")]
98impl TryFrom<&DsaPrivateKey> for dsa::BigUint {
99    type Error = Error;
100
101    fn try_from(key: &DsaPrivateKey) -> Result<dsa::BigUint> {
102        dsa::BigUint::try_from(&key.inner)
103    }
104}
105
106#[cfg(feature = "dsa")]
107impl TryFrom<dsa::SigningKey> for DsaPrivateKey {
108    type Error = Error;
109
110    fn try_from(key: dsa::SigningKey) -> Result<DsaPrivateKey> {
111        DsaPrivateKey::try_from(&key)
112    }
113}
114
115#[cfg(feature = "dsa")]
116impl TryFrom<&dsa::SigningKey> for DsaPrivateKey {
117    type Error = Error;
118
119    fn try_from(key: &dsa::SigningKey) -> Result<DsaPrivateKey> {
120        Ok(DsaPrivateKey {
121            inner: key.x().try_into()?,
122        })
123    }
124}
125
126/// Digital Signature Algorithm (DSA) private/public keypair.
127#[derive(Clone)]
128pub struct DsaKeypair {
129    /// Public key.
130    pub public: DsaPublicKey,
131
132    /// Private key.
133    pub private: DsaPrivateKey,
134}
135
136impl DsaKeypair {
137    /// Key size.
138    #[cfg(all(feature = "dsa", feature = "rand_core"))]
139    #[allow(deprecated)]
140    pub(crate) const KEY_SIZE: dsa::KeySize = dsa::KeySize::DSA_1024_160;
141
142    /// Generate a random DSA private key.
143    #[cfg(all(feature = "dsa", feature = "rand_core"))]
144    pub fn random(rng: &mut impl CryptoRngCore) -> Result<Self> {
145        let components = dsa::Components::generate(rng, Self::KEY_SIZE);
146        dsa::SigningKey::generate(rng, components).try_into()
147    }
148}
149
150impl ConstantTimeEq for DsaKeypair {
151    fn ct_eq(&self, other: &Self) -> Choice {
152        Choice::from((self.public == other.public) as u8) & self.private.ct_eq(&other.private)
153    }
154}
155
156impl PartialEq for DsaKeypair {
157    fn eq(&self, other: &Self) -> bool {
158        self.ct_eq(other).into()
159    }
160}
161
162impl Eq for DsaKeypair {}
163
164impl Decode for DsaKeypair {
165    type Error = Error;
166
167    fn decode(reader: &mut impl Reader) -> Result<Self> {
168        let public = DsaPublicKey::decode(reader)?;
169        let private = DsaPrivateKey::decode(reader)?;
170        Ok(DsaKeypair { public, private })
171    }
172}
173
174impl Encode for DsaKeypair {
175    fn encoded_len(&self) -> encoding::Result<usize> {
176        [self.public.encoded_len()?, self.private.encoded_len()?].checked_sum()
177    }
178
179    fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
180        self.public.encode(writer)?;
181        self.private.encode(writer)
182    }
183}
184
185impl From<DsaKeypair> for DsaPublicKey {
186    fn from(keypair: DsaKeypair) -> DsaPublicKey {
187        keypair.public
188    }
189}
190
191impl From<&DsaKeypair> for DsaPublicKey {
192    fn from(keypair: &DsaKeypair) -> DsaPublicKey {
193        keypair.public.clone()
194    }
195}
196
197impl fmt::Debug for DsaKeypair {
198    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199        f.debug_struct("DsaKeypair")
200            .field("public", &self.public)
201            .finish_non_exhaustive()
202    }
203}
204
205#[cfg(feature = "dsa")]
206impl TryFrom<DsaKeypair> for dsa::SigningKey {
207    type Error = Error;
208
209    fn try_from(key: DsaKeypair) -> Result<dsa::SigningKey> {
210        dsa::SigningKey::try_from(&key)
211    }
212}
213
214#[cfg(feature = "dsa")]
215impl TryFrom<&DsaKeypair> for dsa::SigningKey {
216    type Error = Error;
217
218    fn try_from(key: &DsaKeypair) -> Result<dsa::SigningKey> {
219        Ok(dsa::SigningKey::from_components(
220            dsa::VerifyingKey::try_from(&key.public)?,
221            dsa::BigUint::try_from(&key.private)?,
222        )?)
223    }
224}
225
226#[cfg(feature = "dsa")]
227impl TryFrom<dsa::SigningKey> for DsaKeypair {
228    type Error = Error;
229
230    fn try_from(key: dsa::SigningKey) -> Result<DsaKeypair> {
231        DsaKeypair::try_from(&key)
232    }
233}
234
235#[cfg(feature = "dsa")]
236impl TryFrom<&dsa::SigningKey> for DsaKeypair {
237    type Error = Error;
238
239    fn try_from(key: &dsa::SigningKey) -> Result<DsaKeypair> {
240        Ok(DsaKeypair {
241            private: key.try_into()?,
242            public: key.verifying_key().try_into()?,
243        })
244    }
245}