devolutions_crypto/key/
mod.rs

1//! Module for dealing with wrapped keys and key exchange.
2//!
3//! For now, this module only deal with keypairs, as the symmetric keys are not wrapped yet.
4//!
5//! ### Generation/Derivation
6//!
7//! Using `generate_keypair` will generate a random keypair.
8//!
9//! Asymmetric keys have two uses. They can be used to [encrypt and decrypt data](##asymmetric) and to perform a [key exchange](#key-exchange).
10//!
11//! #### `generate_keypair`
12//! ```rust
13//! use devolutions_crypto::key::{generate_keypair, KeyVersion, KeyPair};
14//!
15//! let keypair: KeyPair = generate_keypair(KeyVersion::Latest);
16//! ```
17//!
18//! ### Key Exchange
19//!
20//! The goal of using a key exchange is to get a shared secret key between
21//! two parties without making it possible for users listening on the conversation
22//! to guess that shared key.
23//! 1. Alice and Bob generates a `KeyPair` each.
24//! 2. Alice and Bob exchanges their `PublicKey`.
25//! 3. Alice mix her `PrivateKey` with Bob's `PublicKey`. This gives her the shared key.
26//! 4. Bob mixes his `PrivateKey` with Alice's `PublicKey`. This gives him the shared key.
27//! 5. Both Bob and Alice has the same shared key, which they can use for symmetric encryption for further communications.
28//!
29//! ```rust
30//! use devolutions_crypto::key::{generate_keypair, mix_key_exchange, KeyVersion, KeyPair};
31//!
32//! let bob_keypair: KeyPair = generate_keypair(KeyVersion::Latest);
33//! let alice_keypair: KeyPair = generate_keypair(KeyVersion::Latest);
34//!
35//! let bob_shared = mix_key_exchange(&bob_keypair.private_key, &alice_keypair.public_key).expect("key exchange should not fail");
36//!
37//! let alice_shared = mix_key_exchange(&alice_keypair.private_key, &bob_keypair.public_key).expect("key exchange should not fail");
38//!
39//! // They now have a shared secret!
40//! assert_eq!(bob_shared, alice_shared);
41//! ```
42
43mod key_v1;
44
45use super::DataType;
46use super::Error;
47use super::Header;
48use super::HeaderType;
49use super::KeySubtype;
50pub use super::KeyVersion;
51use super::Result;
52
53use key_v1::{KeyV1Private, KeyV1Public};
54
55use std::borrow::Borrow;
56use std::convert::TryFrom;
57
58#[cfg(feature = "fuzz")]
59use arbitrary::Arbitrary;
60
61#[cfg(feature = "wbindgen")]
62use wasm_bindgen::prelude::*;
63
64/// An asymmetric keypair.
65#[derive(Clone)]
66pub struct KeyPair {
67    /// The private key of this pair.
68    pub private_key: PrivateKey,
69    /// The public key of this pair.
70    pub public_key: PublicKey,
71}
72
73/// A public key. This key can be sent in clear on unsecured channels and stored publicly.
74#[cfg_attr(feature = "wbindgen", wasm_bindgen(inspectable))]
75#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
76#[derive(Clone, Debug)]
77pub struct PublicKey {
78    pub(crate) header: Header<PublicKey>,
79    payload: PublicKeyPayload,
80}
81
82/// A private key. This key should never be sent over an insecure channel or stored unsecurely.
83#[cfg_attr(feature = "wbindgen", wasm_bindgen(inspectable))]
84#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
85#[derive(Clone, Debug)]
86pub struct PrivateKey {
87    pub(crate) header: Header<PrivateKey>,
88    payload: PrivateKeyPayload,
89}
90
91impl HeaderType for PublicKey {
92    type Version = KeyVersion;
93    type Subtype = KeySubtype;
94
95    fn data_type() -> DataType {
96        DataType::Key
97    }
98
99    fn subtype() -> Self::Subtype {
100        KeySubtype::Public
101    }
102}
103
104impl HeaderType for PrivateKey {
105    type Version = KeyVersion;
106    type Subtype = KeySubtype;
107
108    fn data_type() -> DataType {
109        DataType::Key
110    }
111
112    fn subtype() -> Self::Subtype {
113        KeySubtype::Private
114    }
115}
116
117#[derive(Clone, Debug)]
118#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
119enum PrivateKeyPayload {
120    V1(KeyV1Private),
121}
122
123#[derive(Clone, Debug)]
124#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
125enum PublicKeyPayload {
126    V1(KeyV1Public),
127}
128
129/// Generates a `KeyPair` to use in a key exchange or to encrypt data.
130/// # Arguments
131///  * `version` - Version of the key scheme to use. Use `KeyVersion::Latest` if you're not dealing with shared data.
132/// # Returns
133/// Returns a `KeyPair` containing the private key and the public key.
134/// # Example
135/// ```rust
136/// use devolutions_crypto::key::{generate_keypair, KeyVersion};
137///
138/// let keypair = generate_keypair(KeyVersion::Latest);
139/// ```
140pub fn generate_keypair(version: KeyVersion) -> KeyPair {
141    let (private_header, public_header) = keypair_headers(version);
142
143    let (private_key, public_key) = match version {
144        KeyVersion::V1 | KeyVersion::Latest => {
145            let keypair = key_v1::generate_keypair();
146            (
147                PrivateKeyPayload::V1(keypair.private_key),
148                PublicKeyPayload::V1(keypair.public_key),
149            )
150        }
151    };
152
153    KeyPair {
154        private_key: PrivateKey {
155            header: private_header,
156            payload: private_key,
157        },
158        public_key: PublicKey {
159            header: public_header,
160            payload: public_key,
161        },
162    }
163}
164
165/// Mix a `PrivateKey` with another client `PublicKey` to get a secret shared between the two parties.
166/// # Arguments
167///  * `private_key` - The user's `PrivateKey` obtained through `generate_keypair()`.
168///  * `public_key` - The peer's `PublicKey`.
169/// # Returns
170/// Returns a shared secret in the form of a `Vec<u8>`, which can then be used
171///     as an encryption key between the two parties.
172/// # Example
173/// ```rust
174/// use std::convert::TryFrom as _;
175/// use devolutions_crypto::key::{PublicKey, PrivateKey, generate_keypair, mix_key_exchange, KeyVersion};
176/// # fn send_key_to_alice(_: &[u8]) {}
177/// # fn send_key_to_bob(_: &[u8]) {}
178/// # fn receive_key_from_alice() {}
179/// # fn receive_key_from_bob() {}
180///
181/// // This happens on Bob's side.
182/// let bob_keypair = generate_keypair(KeyVersion::Latest);
183/// let bob_serialized_pub: Vec<u8> = bob_keypair.public_key.into();
184///
185/// send_key_to_alice(&bob_serialized_pub);
186///
187/// // This happens on Alice's side.
188/// let alice_keypair = generate_keypair(KeyVersion::Latest);
189/// let alice_serialized_pub: Vec<u8> = alice_keypair.public_key.into();
190///
191/// send_key_to_bob(&alice_serialized_pub);
192///
193/// // Bob can now generate the shared secret.
194/// let alice_received_serialized_pub = receive_key_from_alice();
195/// # let alice_received_serialized_pub = alice_serialized_pub;
196/// let alice_received_pub = PublicKey::try_from(alice_received_serialized_pub.as_slice()).unwrap();
197///
198/// let bob_shared = mix_key_exchange(&bob_keypair.private_key, &alice_received_pub).unwrap();
199///
200/// // Alice can now generate the shared secret
201/// let bob_received_serialized_pub = receive_key_from_bob();
202/// # let bob_received_serialized_pub = bob_serialized_pub;
203/// let bob_received_pub = PublicKey::try_from(bob_received_serialized_pub.as_slice()).unwrap();
204///
205/// let alice_shared = mix_key_exchange(&alice_keypair.private_key, &bob_received_pub).unwrap();
206///
207/// // They now have a shared secret!
208/// assert_eq!(bob_shared, alice_shared);
209/// ```
210pub fn mix_key_exchange(private_key: &PrivateKey, public_key: &PublicKey) -> Result<Vec<u8>> {
211    Ok(match (&private_key.payload, &public_key.payload) {
212        (PrivateKeyPayload::V1(private_key), PublicKeyPayload::V1(public_key)) => {
213            key_v1::mix_key_exchange(private_key, public_key)
214        } //_ => Err(DevoCryptoError::InvalidDataType),
215    })
216}
217
218fn keypair_headers(version: KeyVersion) -> (Header<PrivateKey>, Header<PublicKey>) {
219    let mut private_header = Header::default();
220    let mut public_header = Header::default();
221
222    match version {
223        KeyVersion::V1 | KeyVersion::Latest => {
224            private_header.version = KeyVersion::V1;
225            public_header.version = KeyVersion::V1;
226        }
227    }
228
229    (private_header, public_header)
230}
231
232impl From<PublicKey> for Vec<u8> {
233    /// Serialize the structure into a `Vec<u8>`, for storage, transmission or use in another language.
234    fn from(data: PublicKey) -> Self {
235        let mut header: Self = data.header.borrow().into();
236        let mut payload: Self = data.payload.into();
237        header.append(&mut payload);
238        header
239    }
240}
241
242impl TryFrom<&[u8]> for PublicKey {
243    type Error = Error;
244
245    /// Parses the data. Can return an Error of the data is invalid or unrecognized.
246    fn try_from(data: &[u8]) -> Result<Self> {
247        if data.len() < Header::len() {
248            return Err(Error::InvalidLength);
249        };
250
251        let header = Header::try_from(&data[0..Header::len()])?;
252
253        if header.data_subtype != KeySubtype::Public {
254            return Err(Error::InvalidDataType);
255        }
256
257        let payload = match header.version {
258            KeyVersion::V1 => PublicKeyPayload::V1(KeyV1Public::try_from(&data[Header::len()..])?),
259            _ => return Err(Error::UnknownVersion),
260        };
261
262        Ok(Self { header, payload })
263    }
264}
265
266impl From<PrivateKey> for Vec<u8> {
267    /// Serialize the structure into a `Vec<u8>`, for storage, transmission or use in another language.
268    fn from(data: PrivateKey) -> Self {
269        let mut header: Self = data.header.borrow().into();
270        let mut payload: Self = data.payload.into();
271        header.append(&mut payload);
272        header
273    }
274}
275
276impl TryFrom<&[u8]> for PrivateKey {
277    type Error = Error;
278
279    /// Parses the data. Can return an Error of the data is invalid or unrecognized.
280    fn try_from(data: &[u8]) -> Result<Self> {
281        if data.len() < Header::len() {
282            return Err(Error::InvalidLength);
283        };
284
285        let header = Header::try_from(&data[0..Header::len()])?;
286
287        if header.data_subtype != KeySubtype::Private {
288            return Err(Error::InvalidDataType);
289        }
290
291        let payload = match header.version {
292            KeyVersion::V1 => {
293                PrivateKeyPayload::V1(KeyV1Private::try_from(&data[Header::len()..])?)
294            }
295            _ => return Err(Error::UnknownVersion),
296        };
297
298        Ok(Self { header, payload })
299    }
300}
301
302impl From<PrivateKeyPayload> for Vec<u8> {
303    fn from(data: PrivateKeyPayload) -> Self {
304        match data {
305            PrivateKeyPayload::V1(x) => x.into(),
306        }
307    }
308}
309
310impl From<PublicKeyPayload> for Vec<u8> {
311    fn from(data: PublicKeyPayload) -> Self {
312        match data {
313            PublicKeyPayload::V1(x) => x.into(),
314        }
315    }
316}
317
318impl From<&PublicKey> for x25519_dalek::PublicKey {
319    fn from(data: &PublicKey) -> Self {
320        match &data.payload {
321            PublicKeyPayload::V1(x) => Self::from(x),
322            //_ => Err(DevoCryptoError::InvalidDataType),
323        }
324    }
325}
326
327impl From<&PrivateKey> for x25519_dalek::StaticSecret {
328    fn from(data: &PrivateKey) -> Self {
329        match &data.payload {
330            PrivateKeyPayload::V1(x) => Self::from(x),
331            //_ => Err(DevoCryptoError::InvalidDataType),
332        }
333    }
334}
335
336#[test]
337fn ecdh_test() {
338    let bob_keypair = generate_keypair(KeyVersion::Latest);
339    let alice_keypair = generate_keypair(KeyVersion::Latest);
340
341    let bob_shared = mix_key_exchange(&bob_keypair.private_key, &alice_keypair.public_key).unwrap();
342    let alice_shared =
343        mix_key_exchange(&alice_keypair.private_key, &bob_keypair.public_key).unwrap();
344
345    assert_eq!(bob_shared, alice_shared);
346}