Skip to main content

ssh_key/public/
dsa.rs

1//! Digital Signature Algorithm (DSA) public keys.
2
3use crate::{Error, Mpint, Result};
4use core::hash::{Hash, Hasher};
5use encoding::{CheckedSum, Decode, Encode, Reader, Writer};
6
7#[cfg(feature = "dsa")]
8use encoding::Uint;
9
10/// Digital Signature Algorithm (DSA) public key.
11///
12/// Described in [FIPS 186-4 § 4.1](https://csrc.nist.gov/publications/detail/fips/186/4/final).
13#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
14pub struct DsaPublicKey {
15    /// Prime modulus.
16    p: Mpint,
17
18    /// Prime divisor of `p - 1`.
19    q: Mpint,
20
21    /// Generator of a subgroup of order `q` in the multiplicative group `GF(p)`, such that
22    /// `1 < g < p`.
23    g: Mpint,
24
25    /// The public key, where `y = gˣ mod p`.
26    y: Mpint,
27}
28
29impl DsaPublicKey {
30    /// Create a new [`DsaPublicKey`] with the following components:
31    ///
32    /// - `p`: prime modulus.
33    /// - `q`: prime divisor of `p - 1`.
34    /// - `g`: generator of a subgroup of order `q` in the multiplicative group `GF(p)`, such
35    ///   that `1 < g < p`.
36    /// - `y`: the public key, where `y = gˣ mod p`.
37    ///
38    /// # Errors
39    /// Returns [`Error::FormatEncoding`] in the event any of the components are negative.
40    pub fn new(p: Mpint, q: Mpint, g: Mpint, y: Mpint) -> Result<Self> {
41        if p.is_positive() && q.is_positive() && g.is_positive() && y.is_positive() {
42            Ok(Self { p, q, g, y })
43        } else {
44            Err(Error::FormatEncoding)
45        }
46    }
47
48    /// Prime modulus.
49    #[must_use]
50    pub fn p(&self) -> &Mpint {
51        &self.p
52    }
53
54    /// Prime divisor of `p - 1`.
55    #[must_use]
56    pub fn q(&self) -> &Mpint {
57        &self.q
58    }
59
60    /// Generator of a subgroup of order `q` in the multiplicative group `GF(p)`, such that
61    /// `1 < g < p`.
62    #[must_use]
63    pub fn g(&self) -> &Mpint {
64        &self.g
65    }
66
67    /// The public key, where `y = gˣ mod p`.
68    #[must_use]
69    pub fn y(&self) -> &Mpint {
70        &self.y
71    }
72}
73
74impl Decode for DsaPublicKey {
75    type Error = Error;
76
77    fn decode(reader: &mut impl Reader) -> Result<Self> {
78        let p = Mpint::decode(reader)?;
79        let q = Mpint::decode(reader)?;
80        let g = Mpint::decode(reader)?;
81        let y = Mpint::decode(reader)?;
82        Self::new(p, q, g, y)
83    }
84}
85
86impl Encode for DsaPublicKey {
87    fn encoded_len(&self) -> encoding::Result<usize> {
88        [
89            self.p.encoded_len()?,
90            self.q.encoded_len()?,
91            self.g.encoded_len()?,
92            self.y.encoded_len()?,
93        ]
94        .checked_sum()
95    }
96
97    fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
98        self.p.encode(writer)?;
99        self.q.encode(writer)?;
100        self.g.encode(writer)?;
101        self.y.encode(writer)
102    }
103}
104
105impl Hash for DsaPublicKey {
106    #[inline]
107    fn hash<H: Hasher>(&self, state: &mut H) {
108        self.p.as_bytes().hash(state);
109        self.q.as_bytes().hash(state);
110        self.g.as_bytes().hash(state);
111        self.y.as_bytes().hash(state);
112    }
113}
114
115#[cfg(feature = "dsa")]
116impl TryFrom<DsaPublicKey> for dsa::VerifyingKey {
117    type Error = Error;
118
119    fn try_from(key: DsaPublicKey) -> Result<dsa::VerifyingKey> {
120        dsa::VerifyingKey::try_from(&key)
121    }
122}
123
124#[cfg(feature = "dsa")]
125impl TryFrom<&DsaPublicKey> for dsa::VerifyingKey {
126    type Error = Error;
127
128    fn try_from(key: &DsaPublicKey) -> Result<dsa::VerifyingKey> {
129        let p = Uint::try_from(&key.p)?;
130        let q = Uint::try_from(&key.q)?;
131        let g = Uint::try_from(&key.g)?;
132        let y = Uint::try_from(&key.y)?;
133
134        let components = dsa::Components::from_components(p, q, g)?;
135        dsa::VerifyingKey::from_components(components, y).map_err(|_| Error::Crypto)
136    }
137}
138
139#[cfg(feature = "dsa")]
140impl From<dsa::VerifyingKey> for DsaPublicKey {
141    fn from(key: dsa::VerifyingKey) -> DsaPublicKey {
142        DsaPublicKey::from(&key)
143    }
144}
145
146#[cfg(feature = "dsa")]
147impl From<&dsa::VerifyingKey> for DsaPublicKey {
148    fn from(key: &dsa::VerifyingKey) -> DsaPublicKey {
149        DsaPublicKey {
150            p: key.components().p().as_ref().into(),
151            q: key.components().q().as_ref().into(),
152            g: key.components().g().as_ref().into(),
153            y: key.y().as_ref().into(),
154        }
155    }
156}