fluence_identity/
key_pair.rs

1// Copyright 2019 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21//! A node's network identity keys.
22use crate::ed25519;
23#[cfg(not(target_arch = "wasm32"))]
24use crate::rsa;
25use crate::secp256k1;
26use crate::public_key::PublicKey;
27use crate::signature::Signature;
28use crate::error::{Error, DecodingError, SigningError};
29use std::str::FromStr;
30use std::convert::TryFrom;
31
32/// Identity keypair of a node.
33///
34/// # Example: Generating RSA keys with OpenSSL
35///
36/// ```text
37/// openssl genrsa -out private.pem 2048
38/// openssl pkcs8 -in private.pem -inform PEM -topk8 -out private.pk8 -outform DER -nocrypt
39/// rm private.pem      # optional
40/// ```
41///
42/// Loading the keys:
43///
44/// ```text
45/// let mut bytes = std::fs::read("private.pk8").unwrap();
46/// let keypair = Keypair::rsa_from_pkcs8(&mut bytes);
47/// ```
48///
49
50
51pub enum KeyFormat {
52    Ed25519,
53    #[cfg(not(target_arch = "wasm32"))]
54    Rsa,
55    Secp256k1,
56}
57
58impl FromStr for KeyFormat {
59    type Err = Error;
60
61    #[inline]
62    fn from_str(s: &str) -> Result<Self, Self::Err> {
63        match s {
64            "ed25519" => Ok(KeyFormat::Ed25519),
65            "secp256k1" => Ok(KeyFormat::Secp256k1),
66            #[cfg(not(target_arch = "wasm32"))]
67            "rsa" => Ok(KeyFormat::Rsa),
68            _ => Err(Error::InvalidKeyFormat(s.to_string()))
69        }
70    }
71}
72
73impl TryFrom<u8> for KeyFormat {
74    type Error = DecodingError;
75
76    fn try_from(value: u8) -> Result<Self, Self::Error> {
77        match value {
78            0 => Ok(KeyFormat::Ed25519),
79            #[cfg(not(target_arch = "wasm32"))]
80            1 => Ok(KeyFormat::Rsa),
81            2 => Ok(KeyFormat::Secp256k1),
82            _ => Err(DecodingError::InvalidTypeByte)
83        }
84    }
85}
86
87impl From<KeyFormat> for u8 {
88    fn from(kf: KeyFormat) -> Self {
89        match kf {
90            KeyFormat::Ed25519 => 0,
91            #[cfg(not(target_arch = "wasm32"))]
92            KeyFormat::Rsa => 1,
93            KeyFormat::Secp256k1 => 2,
94        }
95    }
96}
97
98#[derive(Clone)]
99pub enum KeyPair {
100    /// An Ed25519 keypair.
101    Ed25519(ed25519::Keypair),
102    #[cfg(not(target_arch = "wasm32"))]
103    /// An RSA keypair.
104    Rsa(rsa::Keypair),
105    /// A Secp256k1 keypair.
106    Secp256k1(secp256k1::Keypair),
107}
108
109impl KeyPair {
110    pub fn generate(format: KeyFormat) -> KeyPair {
111        match format {
112            KeyFormat::Ed25519 => KeyPair::generate_ed25519(),
113            KeyFormat::Secp256k1 => KeyPair::generate_secp256k1(),
114            #[cfg(not(target_arch = "wasm32"))]
115            KeyFormat::Rsa => todo!("rsa generation is not supported yet!"),
116        }
117    }
118
119    /// Generate a new Ed25519 keypair.
120    pub fn generate_ed25519() -> KeyPair {
121        KeyPair::Ed25519(ed25519::Keypair::generate())
122    }
123
124    /// Generate a new Secp256k1 keypair.
125    pub fn generate_secp256k1() -> KeyPair {
126        KeyPair::Secp256k1(secp256k1::Keypair::generate())
127    }
128
129    /// Decode an keypair from a DER-encoded secret key in PKCS#8 PrivateKeyInfo
130    /// format (i.e. unencrypted) as defined in [RFC5208].
131    ///
132    /// [RFC5208]: https://tools.ietf.org/html/rfc5208#section-5
133    #[cfg(not(target_arch = "wasm32"))]
134    pub fn rsa_from_pkcs8(pkcs8_der: &mut [u8]) -> Result<KeyPair, DecodingError> {
135        rsa::Keypair::from_pkcs8(pkcs8_der).map(KeyPair::Rsa)
136    }
137
138    /// Decode a keypair from a DER-encoded Secp256k1 secret key in an ECPrivateKey
139    /// structure as defined in [RFC5915].
140    ///
141    /// [RFC5915]: https://tools.ietf.org/html/rfc5915
142    pub fn secp256k1_from_der(der: &mut [u8]) -> Result<KeyPair, DecodingError> {
143        secp256k1::SecretKey::from_der(der)
144            .map(|sk| KeyPair::Secp256k1(secp256k1::Keypair::from(sk)))
145    }
146
147    /// Sign a message using the private key of this keypair, producing
148    /// a signature that can be verified using the corresponding public key.
149    pub fn sign(&self, msg: &[u8]) -> Result<Signature, SigningError> {
150        use KeyPair::*;
151        match self {
152            Ed25519(ref pair) => Ok(Signature::Ed25519(ed25519::Signature(pair.sign(msg)?))),
153            #[cfg(not(target_arch = "wasm32"))]
154            Rsa(ref pair) => Ok(Signature::Rsa(rsa::Signature(pair.sign(msg)?))),
155            Secp256k1(ref pair) => Ok(Signature::Secp256k1(secp256k1::Signature(pair.secret().sign(msg)?)))
156        }
157    }
158
159    /// Get the public key of this keypair.
160    pub fn public(&self) -> PublicKey {
161        use KeyPair::*;
162        match self {
163            Ed25519(pair) => PublicKey::Ed25519(pair.public()),
164            #[cfg(not(target_arch = "wasm32"))]
165            Rsa(pair) => PublicKey::Rsa(pair.public()),
166            Secp256k1(pair) => PublicKey::Secp256k1(pair.public().clone()),
167        }
168    }
169
170    /// Verify the signature on a message using the public key.
171    pub fn verify(pk: &PublicKey, msg: &[u8], signature: &Signature) -> Result<(), SigningError> {
172        pk.verify(msg, signature)
173    }
174
175    pub fn to_vec(&self) -> Vec<u8> {
176        use KeyPair::*;
177        match self {
178            Ed25519(kp) => kp.encode().to_vec(),
179            #[cfg(not(target_arch = "wasm32"))]
180            Rsa(_) => todo!("rsa encoding is not supported yet!"),
181            Secp256k1(kp) => kp.secret().to_bytes().to_vec(),
182        }
183    }
184
185    pub fn from_vec(mut bytes: Vec<u8>, format: KeyFormat) -> Result<Self, DecodingError> {
186        use KeyPair::*;
187
188        match format {
189            KeyFormat::Ed25519 => Ok(Ed25519(ed25519::Keypair::decode(&mut bytes)?)),
190            KeyFormat::Secp256k1 => Ok(Secp256k1(secp256k1::SecretKey::from_bytes(bytes)?.into())),
191            #[cfg(not(target_arch = "wasm32"))]
192            KeyFormat::Rsa => Err(DecodingError::KeypairDecodingIsNotSupported)
193        }
194    }
195}
196
197impl From<libp2p_core::identity::Keypair> for KeyPair {
198    fn from(key: libp2p_core::identity::Keypair) -> Self {
199        use libp2p_core::identity::Keypair::*;
200
201        match key {
202            Ed25519(kp) => KeyPair::Ed25519(ed25519::Keypair::decode(&mut kp.encode()).unwrap()),
203            #[cfg(not(target_arch = "wasm32"))]
204            // safety: these Keypair structures are identical
205            Rsa(kp) => KeyPair::Rsa(unsafe { std::mem::transmute::<libp2p_core::identity::rsa::Keypair, rsa::Keypair>(kp) }),
206            Secp256k1(kp) => KeyPair::Secp256k1(secp256k1::Keypair::from(secp256k1::SecretKey::from_bytes(kp.secret().to_bytes()).unwrap())),
207        }
208    }
209}
210
211impl From<KeyPair> for libp2p_core::identity::Keypair {
212    fn from(key: KeyPair) -> Self {
213        use KeyPair::*;
214        use libp2p_core::identity::Keypair;
215        use libp2p_core::identity;
216
217        match key {
218            Ed25519(kp) => Keypair::Ed25519(identity::ed25519::Keypair::decode(kp.encode().to_vec().as_mut_slice()).unwrap()),
219            #[cfg(not(target_arch = "wasm32"))]
220            Rsa(kp) => Keypair::Rsa(unsafe { std::mem::transmute::<rsa::Keypair, libp2p_core::identity::rsa::Keypair>(kp) }),
221            Secp256k1(kp) => Keypair::Secp256k1(identity::secp256k1::Keypair::from(identity::secp256k1::SecretKey::from_bytes(kp.secret().to_bytes()).unwrap())),
222        }
223    }
224}