devolutions_crypto/signing_key/
mod.rs

1//! Module for dealing with signature keys.
2//!
3//! See the `signature` module for more usage.
4//!
5//! #### `generate_keypair`
6//! Note: A private key is useless on their own as the public key is also required to sign the data.
7//! Therefore, you ned to handle use the full keypair as a private key when you want to sign data.
8//! ```rust
9//! use std::convert::TryInto;
10//!
11//! use devolutions_crypto::signing_key::{generate_signing_keypair, SigningKeyVersion, SigningKeyPair, SigningPublicKey};
12//!
13//! let keypair: SigningKeyPair = generate_signing_keypair(SigningKeyVersion::Latest);
14//! let public_key: SigningPublicKey = keypair.get_public_key();
15//!
16//! // You can serialize to and from a byte array to store and transfer the keys
17//! let keypair_bytes: Vec<u8> = keypair.into();
18//! let public_bytes: Vec<u8> = public_key.into();
19//!
20//! let keypair: SigningKeyPair = (keypair_bytes.as_slice()).try_into().unwrap();
21//! let public_key: SigningPublicKey = (public_bytes.as_slice()).try_into().unwrap();
22//! ```
23
24mod signing_key_v1;
25
26use super::DataType;
27use super::Error;
28use super::Header;
29use super::HeaderType;
30use super::KeySubtype;
31use super::Result;
32pub use super::SigningKeyVersion;
33
34use signing_key_v1::{SigningKeyV1Pair, SigningKeyV1Public};
35
36use std::borrow::Borrow;
37use std::convert::TryFrom;
38
39#[cfg(feature = "fuzz")]
40use arbitrary::Arbitrary;
41
42#[cfg(feature = "wbindgen")]
43use wasm_bindgen::prelude::*;
44
45/// A public key. This key can be sent in clear on unsecured channels and stored publicly.
46#[cfg_attr(feature = "wbindgen", wasm_bindgen(inspectable))]
47#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
48#[derive(Clone, Debug)]
49pub struct SigningPublicKey {
50    pub(crate) header: Header<SigningPublicKey>,
51    payload: SigningPublicKeyPayload,
52}
53
54/// A keypair. This should never be sent over an insecure channel or stored unsecurely.
55/// To extract the public part of the keypair, use `get_public_key()`
56#[cfg_attr(feature = "wbindgen", wasm_bindgen(inspectable))]
57#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
58#[derive(Clone, Debug)]
59pub struct SigningKeyPair {
60    pub(crate) header: Header<SigningKeyPair>,
61    payload: SigningKeyPairPayload,
62}
63
64impl HeaderType for SigningPublicKey {
65    type Version = SigningKeyVersion;
66    type Subtype = KeySubtype;
67
68    fn data_type() -> DataType {
69        DataType::SigningKey
70    }
71
72    fn subtype() -> Self::Subtype {
73        KeySubtype::Public
74    }
75}
76
77impl HeaderType for SigningKeyPair {
78    type Version = SigningKeyVersion;
79    type Subtype = KeySubtype;
80
81    fn data_type() -> DataType {
82        DataType::SigningKey
83    }
84
85    fn subtype() -> Self::Subtype {
86        KeySubtype::Private
87    }
88}
89
90#[derive(Clone, Debug)]
91#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
92enum SigningKeyPairPayload {
93    V1(SigningKeyV1Pair),
94}
95
96#[derive(Clone, Debug)]
97#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
98enum SigningPublicKeyPayload {
99    V1(SigningKeyV1Public),
100}
101
102/// Generates a `SigningKeyPair` to use in a key exchange or to encrypt data.
103/// # Arguments
104///  * `version` - Version of the key scheme to use. Use `SigningKeyVersion::Latest` if you're not dealing with shared data.
105/// # Returns
106/// Returns a `SigningKeyPair` containing the private key and the public key.
107/// # Example
108/// ```rust
109/// use devolutions_crypto::signing_key::{generate_signing_keypair, SigningKeyVersion, SigningKeyPair};
110///
111/// let keypair: SigningKeyPair = generate_signing_keypair(SigningKeyVersion::Latest);
112/// ```
113pub fn generate_signing_keypair(version: SigningKeyVersion) -> SigningKeyPair {
114    let mut header = Header::default();
115
116    let payload = match version {
117        SigningKeyVersion::V1 | SigningKeyVersion::Latest => {
118            header.version = SigningKeyVersion::V1;
119
120            let keypair = signing_key_v1::generate_signing_keypair();
121            SigningKeyPairPayload::V1(keypair)
122        }
123    };
124
125    SigningKeyPair { header, payload }
126}
127
128impl SigningKeyPair {
129    /// Gets the public part `SingingPublicKey` of a `SigningKeyPair`
130    /// # Returns
131    /// Returns a `SingingPublicKey` containingthe public key.
132    /// # Example
133    /// ```rust
134    /// use devolutions_crypto::signing_key::{generate_signing_keypair, SigningKeyVersion, SigningKeyPair, SigningPublicKey};
135    ///
136    /// let keypair: SigningKeyPair = generate_signing_keypair(SigningKeyVersion::Latest);
137    /// let public: SigningPublicKey = keypair.get_public_key();
138    /// ```
139    pub fn get_public_key(&self) -> SigningPublicKey {
140        let mut header = Header::default();
141
142        let payload = match &self.payload {
143            SigningKeyPairPayload::V1(x) => {
144                header.version = SigningKeyVersion::V1;
145
146                SigningPublicKeyPayload::V1(x.get_public_key())
147            }
148        };
149
150        SigningPublicKey { header, payload }
151    }
152}
153
154impl From<SigningPublicKey> for Vec<u8> {
155    /// Serialize the structure into a `Vec<u8>`, for storage, transmission or use in another language.
156    fn from(data: SigningPublicKey) -> Self {
157        let mut header: Self = data.header.borrow().into();
158        let mut payload: Self = data.payload.into();
159        header.append(&mut payload);
160        header
161    }
162}
163
164impl TryFrom<&[u8]> for SigningPublicKey {
165    type Error = Error;
166
167    /// Parses the data. Can return an Error of the data is invalid or unrecognized.
168    fn try_from(data: &[u8]) -> Result<Self> {
169        if data.len() < Header::len() {
170            return Err(Error::InvalidLength);
171        };
172
173        let header = Header::try_from(&data[0..Header::len()])?;
174
175        if header.data_subtype != KeySubtype::Public {
176            return Err(Error::InvalidDataType);
177        }
178
179        let payload = match header.version {
180            SigningKeyVersion::V1 => {
181                SigningPublicKeyPayload::V1(SigningKeyV1Public::try_from(&data[Header::len()..])?)
182            }
183            _ => return Err(Error::UnknownVersion),
184        };
185
186        Ok(Self { header, payload })
187    }
188}
189
190impl From<SigningKeyPair> for Vec<u8> {
191    /// Serialize the structure into a `Vec<u8>`, for storage, transmission or use in another language.
192    fn from(data: SigningKeyPair) -> Self {
193        let mut header: Self = data.header.borrow().into();
194        let mut payload: Self = data.payload.into();
195        header.append(&mut payload);
196        header
197    }
198}
199
200impl TryFrom<&[u8]> for SigningKeyPair {
201    type Error = Error;
202
203    /// Parses the data. Can return an Error of the data is invalid or unrecognized.
204    fn try_from(data: &[u8]) -> Result<Self> {
205        if data.len() < Header::len() {
206            return Err(Error::InvalidLength);
207        };
208
209        let header = Header::try_from(&data[0..Header::len()])?;
210
211        if header.data_subtype != KeySubtype::Private {
212            return Err(Error::InvalidDataType);
213        }
214
215        let payload = match header.version {
216            SigningKeyVersion::V1 => {
217                SigningKeyPairPayload::V1(SigningKeyV1Pair::try_from(&data[Header::len()..])?)
218            }
219            _ => return Err(Error::UnknownVersion),
220        };
221
222        Ok(Self { header, payload })
223    }
224}
225
226impl From<SigningKeyPairPayload> for Vec<u8> {
227    fn from(data: SigningKeyPairPayload) -> Self {
228        match data {
229            SigningKeyPairPayload::V1(x) => x.into(),
230        }
231    }
232}
233
234impl From<SigningPublicKeyPayload> for Vec<u8> {
235    fn from(data: SigningPublicKeyPayload) -> Self {
236        match data {
237            SigningPublicKeyPayload::V1(x) => x.into(),
238        }
239    }
240}
241
242impl From<&SigningPublicKey> for ed25519_dalek::VerifyingKey {
243    fn from(data: &SigningPublicKey) -> Self {
244        match &data.payload {
245            SigningPublicKeyPayload::V1(x) => Self::from(x),
246            //_ => Err(DevoCryptoError::InvalidDataType),
247        }
248    }
249}
250
251impl From<&SigningKeyPair> for ed25519_dalek::SigningKey {
252    fn from(data: &SigningKeyPair) -> Self {
253        match &data.payload {
254            SigningKeyPairPayload::V1(x) => Self::from(x),
255            //_ => Err(DevoCryptoError::InvalidDataType),
256        }
257    }
258}
259
260#[test]
261fn test_signing_keypair_v1() {
262    use std::convert::TryInto;
263
264    let keypair = generate_signing_keypair(SigningKeyVersion::V1);
265    let public = keypair.get_public_key();
266
267    let keypair_bytes: Vec<u8> = keypair.into();
268    let public_bytes: Vec<u8> = public.into();
269
270    let _: SigningKeyPair = (keypair_bytes.as_slice()).try_into().unwrap();
271    let _: SigningPublicKey = (public_bytes.as_slice()).try_into().unwrap();
272}