1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
//! Module for dealing with signature keys.
//!
//! See the `signature` module for more usage.
//!
//! #### `generate_keypair`
//! Note: A private key is useless on their own as the public key is also required to sign the data.
//! Therefore, you ned to handle use the full keypair as a private key when you want to sign data.
//! ```rust
//! use std::convert::TryInto;
//!
//! use devolutions_crypto::signing_key::{generate_signing_keypair, SigningKeyVersion, SigningKeyPair, SigningPublicKey};
//!
//! let keypair: SigningKeyPair = generate_signing_keypair(SigningKeyVersion::Latest);
//! let public_key: SigningPublicKey = keypair.get_public_key();
//!
//! // You can serialize to and from a byte array to store and transfer the keys
//! let keypair_bytes: Vec<u8> = keypair.into();
//! let public_bytes: Vec<u8> = public_key.into();
//!
//! let keypair: SigningKeyPair = (keypair_bytes.as_slice()).try_into().unwrap();
//! let public_key: SigningPublicKey = (public_bytes.as_slice()).try_into().unwrap();
//! ```

mod signing_key_v1;

use super::DataType;
use super::Error;
use super::Header;
use super::HeaderType;
use super::KeySubtype;
use super::Result;
pub use super::SigningKeyVersion;

use signing_key_v1::{SigningKeyV1Pair, SigningKeyV1Public};

use std::convert::TryFrom;

#[cfg(feature = "fuzz")]
use arbitrary::Arbitrary;

#[cfg(feature = "wbindgen")]
use wasm_bindgen::prelude::*;

/// A public key. This key can be sent in clear on unsecured channels and stored publicly.
#[cfg_attr(feature = "wbindgen", wasm_bindgen(inspectable))]
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
#[derive(Clone, Debug)]
pub struct SigningPublicKey {
    pub(crate) header: Header<SigningPublicKey>,
    payload: SigningPublicKeyPayload,
}

/// A keypair. This should never be sent over an insecure channel or stored unsecurely.
/// To extract the public part of the keypair, use `get_public_key()`
#[cfg_attr(feature = "wbindgen", wasm_bindgen(inspectable))]
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
#[derive(Clone, Debug)]
pub struct SigningKeyPair {
    pub(crate) header: Header<SigningKeyPair>,
    payload: SigningKeyPairPayload,
}

impl HeaderType for SigningPublicKey {
    type Version = SigningKeyVersion;
    type Subtype = KeySubtype;

    fn data_type() -> DataType {
        DataType::SigningKey
    }

    fn subtype() -> Self::Subtype {
        KeySubtype::Public
    }
}

impl HeaderType for SigningKeyPair {
    type Version = SigningKeyVersion;
    type Subtype = KeySubtype;

    fn data_type() -> DataType {
        DataType::SigningKey
    }

    fn subtype() -> Self::Subtype {
        KeySubtype::Private
    }
}

#[derive(Clone, Debug)]
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
enum SigningKeyPairPayload {
    V1(SigningKeyV1Pair),
}

#[derive(Clone, Debug)]
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
enum SigningPublicKeyPayload {
    V1(SigningKeyV1Public),
}

/// Generates a `SigningKeyPair` to use in a key exchange or to encrypt data.
/// # Arguments
///  * `version` - Version of the key scheme to use. Use `SigningKeyVersion::Latest` if you're not dealing with shared data.
/// # Returns
/// Returns a `SigningKeyPair` containing the private key and the public key.
/// # Example
/// ```rust
/// use devolutions_crypto::signing_key::{generate_signing_keypair, SigningKeyVersion, SigningKeyPair};
///
/// let keypair: SigningKeyPair = generate_signing_keypair(SigningKeyVersion::Latest);
/// ```
pub fn generate_signing_keypair(version: SigningKeyVersion) -> SigningKeyPair {
    let mut header = Header::default();

    let payload = match version {
        SigningKeyVersion::V1 | SigningKeyVersion::Latest => {
            header.version = SigningKeyVersion::V1;

            let keypair = signing_key_v1::generate_signing_keypair();
            SigningKeyPairPayload::V1(keypair)
        }
    };

    SigningKeyPair { header, payload }
}

impl SigningKeyPair {
    /// Gets the public part `SingingPublicKey` of a `SigningKeyPair`
    /// # Returns
    /// Returns a `SingingPublicKey` containingthe public key.
    /// # Example
    /// ```rust
    /// use devolutions_crypto::signing_key::{generate_signing_keypair, SigningKeyVersion, SigningKeyPair, SigningPublicKey};
    ///
    /// let keypair: SigningKeyPair = generate_signing_keypair(SigningKeyVersion::Latest);
    /// let public: SigningPublicKey = keypair.get_public_key();
    /// ```
    pub fn get_public_key(&self) -> SigningPublicKey {
        let mut header = Header::default();

        let payload = match &self.payload {
            SigningKeyPairPayload::V1(x) => {
                header.version = SigningKeyVersion::V1;

                SigningPublicKeyPayload::V1(x.get_public_key())
            }
        };

        SigningPublicKey { header, payload }
    }
}

impl From<SigningPublicKey> for Vec<u8> {
    /// Serialize the structure into a `Vec<u8>`, for storage, transmission or use in another language.
    fn from(data: SigningPublicKey) -> Self {
        let mut header: Self = data.header.into();
        let mut payload: Self = data.payload.into();
        header.append(&mut payload);
        header
    }
}

impl TryFrom<&[u8]> for SigningPublicKey {
    type Error = Error;

    /// Parses the data. Can return an Error of the data is invalid or unrecognized.
    fn try_from(data: &[u8]) -> Result<Self> {
        if data.len() < Header::len() {
            return Err(Error::InvalidLength);
        };

        let header = Header::try_from(&data[0..Header::len()])?;

        if header.data_subtype != KeySubtype::Public {
            return Err(Error::InvalidDataType);
        }

        let payload = match header.version {
            SigningKeyVersion::V1 => {
                SigningPublicKeyPayload::V1(SigningKeyV1Public::try_from(&data[Header::len()..])?)
            }
            _ => return Err(Error::UnknownVersion),
        };

        Ok(Self { header, payload })
    }
}

impl From<SigningKeyPair> for Vec<u8> {
    /// Serialize the structure into a `Vec<u8>`, for storage, transmission or use in another language.
    fn from(data: SigningKeyPair) -> Self {
        let mut header: Self = data.header.into();
        let mut payload: Self = data.payload.into();
        header.append(&mut payload);
        header
    }
}

impl TryFrom<&[u8]> for SigningKeyPair {
    type Error = Error;

    /// Parses the data. Can return an Error of the data is invalid or unrecognized.
    fn try_from(data: &[u8]) -> Result<Self> {
        if data.len() < Header::len() {
            return Err(Error::InvalidLength);
        };

        let header = Header::try_from(&data[0..Header::len()])?;

        if header.data_subtype != KeySubtype::Private {
            return Err(Error::InvalidDataType);
        }

        let payload = match header.version {
            SigningKeyVersion::V1 => {
                SigningKeyPairPayload::V1(SigningKeyV1Pair::try_from(&data[Header::len()..])?)
            }
            _ => return Err(Error::UnknownVersion),
        };

        Ok(Self { header, payload })
    }
}

impl From<SigningKeyPairPayload> for Vec<u8> {
    fn from(data: SigningKeyPairPayload) -> Self {
        match data {
            SigningKeyPairPayload::V1(x) => x.into(),
        }
    }
}

impl From<SigningPublicKeyPayload> for Vec<u8> {
    fn from(data: SigningPublicKeyPayload) -> Self {
        match data {
            SigningPublicKeyPayload::V1(x) => x.into(),
        }
    }
}

impl From<&SigningPublicKey> for ed25519_dalek::VerifyingKey {
    fn from(data: &SigningPublicKey) -> Self {
        match &data.payload {
            SigningPublicKeyPayload::V1(x) => Self::from(x),
            //_ => Err(DevoCryptoError::InvalidDataType),
        }
    }
}

impl From<&SigningKeyPair> for ed25519_dalek::SigningKey {
    fn from(data: &SigningKeyPair) -> Self {
        match &data.payload {
            SigningKeyPairPayload::V1(x) => Self::from(x),
            //_ => Err(DevoCryptoError::InvalidDataType),
        }
    }
}

#[test]
fn test_signing_keypair_v1() {
    use std::convert::TryInto;

    let keypair = generate_signing_keypair(SigningKeyVersion::V1);
    let public = keypair.get_public_key();

    let keypair_bytes: Vec<u8> = keypair.into();
    let public_bytes: Vec<u8> = public.into();

    let _: SigningKeyPair = (keypair_bytes.as_slice()).try_into().unwrap();
    let _: SigningPublicKey = (public_bytes.as_slice()).try_into().unwrap();
}