dsa/
lib.rs

1#![no_std]
2#![forbid(unsafe_code)]
3#![warn(missing_docs, rust_2018_idioms)]
4#![doc = include_str!("../README.md")]
5#![doc(
6    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
7    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
8)]
9
10//!
11//! # Examples
12//!
13//! Generate a DSA keypair
14//!
15#![cfg_attr(feature = "hazmat", doc = "```")]
16#![cfg_attr(not(feature = "hazmat"), doc = "```ignore")]
17//! # use dsa::{KeySize, Components, SigningKey};
18//! let mut csprng = rand::thread_rng();
19//! let components = Components::generate(&mut csprng, KeySize::DSA_2048_256);
20//! let signing_key = SigningKey::generate(&mut csprng, components);
21//! let verifying_key = signing_key.verifying_key();
22//! ```
23//!
24//! Create keypair from existing components
25//!
26#![cfg_attr(feature = "hazmat", doc = "```")]
27#![cfg_attr(not(feature = "hazmat"), doc = "```ignore")]
28//! # use dsa::{Components, SigningKey, VerifyingKey};
29//! # use crypto_bigint::{BoxedUint, NonZero, Odd};
30//! # let read_common_parameters = ||
31//! #     (
32//! #          Odd::new(BoxedUint::one()).unwrap(),
33//! #          NonZero::new(BoxedUint::one()).unwrap(),
34//! #          NonZero::new(BoxedUint::one()).unwrap(),
35//! #     );
36//! # let read_public_component = || NonZero::new(BoxedUint::one()).unwrap();
37//! # let read_private_component = || NonZero::new(BoxedUint::one()).unwrap();
38//! # || -> signature::Result<()> {
39//! let (p, q, g) = read_common_parameters();
40//! let components = Components::from_components(p, q, g)?;
41//!
42//! let x = read_public_component();
43//! let verifying_key = VerifyingKey::from_components(components, x)?;
44//!
45//! let y = read_private_component();
46//! let signing_key = SigningKey::from_components(verifying_key, y)?;
47//!
48//! # Ok(())
49//! # }();
50//! ```
51//!
52
53extern crate alloc;
54
55#[cfg(feature = "hazmat")]
56pub use crate::signing_key::SigningKey;
57
58pub use crate::{components::Components, size::KeySize, verifying_key::VerifyingKey};
59
60pub use crypto_bigint::{BoxedUint, NonZero, Odd};
61pub use pkcs8;
62pub use signature;
63
64use pkcs8::spki::ObjectIdentifier;
65
66mod components;
67mod generate;
68mod signing_key;
69mod size;
70mod verifying_key;
71
72/// DSA object identifier as defined by [RFC3279 ยง 2.3.2].
73///
74/// [RFC3279 2.3.2]: https://www.rfc-editor.org/rfc/rfc3279#section-2.3.2
75pub const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10040.4.1");
76
77use alloc::{boxed::Box, vec::Vec};
78use pkcs8::der::{
79    self, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Sequence,
80    Writer, asn1::UintRef,
81};
82use signature::SignatureEncoding;
83
84/// Container of the DSA signature
85#[derive(Clone, Debug)]
86#[must_use]
87pub struct Signature {
88    /// Signature part r
89    r: NonZero<BoxedUint>,
90
91    /// Signature part s
92    s: NonZero<BoxedUint>,
93}
94
95impl Signature {
96    /// Create a new Signature container from its components
97    pub fn from_components(r: NonZero<BoxedUint>, s: NonZero<BoxedUint>) -> Self {
98        Self { r, s }
99    }
100
101    /// Signature part r
102    #[must_use]
103    pub fn r(&self) -> &NonZero<BoxedUint> {
104        &self.r
105    }
106
107    /// Signature part s
108    #[must_use]
109    pub fn s(&self) -> &NonZero<BoxedUint> {
110        &self.s
111    }
112}
113
114impl<'a> DecodeValue<'a> for Signature {
115    type Error = der::Error;
116
117    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
118        reader.read_nested(header.length, |reader| {
119            let r = UintRef::decode(reader)?;
120            let s = UintRef::decode(reader)?;
121
122            let r = BoxedUint::from_be_slice(r.as_bytes(), r.as_bytes().len() as u32 * 8)
123                .map_err(|_| UintRef::TAG.value_error())?;
124            let s = BoxedUint::from_be_slice(s.as_bytes(), s.as_bytes().len() as u32 * 8)
125                .map_err(|_| UintRef::TAG.value_error())?;
126
127            let r = NonZero::new(r)
128                .into_option()
129                .ok_or(UintRef::TAG.value_error())?;
130            let s = NonZero::new(s)
131                .into_option()
132                .ok_or(UintRef::TAG.value_error())?;
133
134            Ok(Self::from_components(r, s))
135        })
136    }
137}
138
139impl EncodeValue for Signature {
140    fn value_len(&self) -> der::Result<Length> {
141        UintRef::new(&self.r.to_be_bytes())?.encoded_len()?
142            + UintRef::new(&self.s.to_be_bytes())?.encoded_len()?
143    }
144
145    fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
146        UintRef::new(&self.r.to_be_bytes())?.encode(writer)?;
147        UintRef::new(&self.s.to_be_bytes())?.encode(writer)?;
148        Ok(())
149    }
150}
151
152impl From<Signature> for Box<[u8]> {
153    fn from(sig: Signature) -> Box<[u8]> {
154        sig.to_bytes()
155    }
156}
157
158impl PartialEq for Signature {
159    fn eq(&self, other: &Self) -> bool {
160        self.r().eq(other.r()) && self.s().eq(other.s())
161    }
162}
163
164impl PartialOrd for Signature {
165    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
166        (self.r(), self.s()).partial_cmp(&(other.r(), other.s()))
167    }
168}
169
170impl Sequence<'_> for Signature {}
171
172impl SignatureEncoding for Signature {
173    type Repr = Box<[u8]>;
174
175    fn to_bytes(&self) -> Box<[u8]> {
176        SignatureEncoding::to_vec(self).into_boxed_slice()
177    }
178
179    fn to_vec(&self) -> Vec<u8> {
180        self.to_der().expect("DER encoding error")
181    }
182}
183
184impl TryFrom<&[u8]> for Signature {
185    type Error = signature::Error;
186
187    fn try_from(bytes: &[u8]) -> signature::Result<Self> {
188        // TODO(tarcieri): capture error source when `std` feature enabled
189        Self::from_der(bytes).map_err(|_| signature::Error::new())
190    }
191}
192
193/// Returns a `BoxedUint` with the value 2
194#[inline]
195fn two() -> BoxedUint {
196    BoxedUint::from(2_u8)
197}