ssh_key/private/
dsa.rs

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