mwc_libp2p_core/
identity.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.
22
23pub mod ed25519;
24#[cfg(not(target_arch = "wasm32"))]
25pub mod rsa;
26#[cfg(feature = "secp256k1")]
27pub mod secp256k1;
28
29pub mod error;
30
31use self::error::*;
32use crate::{PeerId, keys_proto};
33
34/// Identity keypair of a node.
35///
36/// # Example: Generating RSA keys with OpenSSL
37///
38/// ```text
39/// openssl genrsa -out private.pem 2048
40/// openssl pkcs8 -in private.pem -inform PEM -topk8 -out private.pk8 -outform DER -nocrypt
41/// rm private.pem      # optional
42/// ```
43///
44/// Loading the keys:
45///
46/// ```text
47/// let mut bytes = std::fs::read("private.pk8").unwrap();
48/// let keypair = Keypair::rsa_from_pkcs8(&mut bytes);
49/// ```
50///
51#[derive(Clone)]
52pub enum Keypair {
53    /// An Ed25519 keypair.
54    Ed25519(ed25519::Keypair),
55    #[cfg(not(target_arch = "wasm32"))]
56    /// An RSA keypair.
57    Rsa(rsa::Keypair),
58    /// A Secp256k1 keypair.
59    #[cfg(feature = "secp256k1")]
60    Secp256k1(secp256k1::Keypair)
61}
62
63impl Keypair {
64    /// Generate a new Ed25519 keypair.
65    pub fn generate_ed25519() -> Keypair {
66        Keypair::Ed25519(ed25519::Keypair::generate())
67    }
68
69    pub fn ed25519_from_secret(sk_bytes: impl AsMut<[u8]>) -> Result<Keypair,DecodingError> {
70        Ok(Keypair::Ed25519(ed25519::Keypair::from_secret(sk_bytes)?))
71    }
72
73    /// Generate a new Secp256k1 keypair.
74    #[cfg(feature = "secp256k1")]
75    pub fn generate_secp256k1() -> Keypair {
76        Keypair::Secp256k1(secp256k1::Keypair::generate())
77    }
78
79    /// Decode an keypair from a DER-encoded secret key in PKCS#8 PrivateKeyInfo
80    /// format (i.e. unencrypted) as defined in [RFC5208].
81    ///
82    /// [RFC5208]: https://tools.ietf.org/html/rfc5208#section-5
83    #[cfg(not(target_arch = "wasm32"))]
84    pub fn rsa_from_pkcs8(pkcs8_der: &mut [u8]) -> Result<Keypair, DecodingError> {
85        rsa::Keypair::from_pkcs8(pkcs8_der).map(Keypair::Rsa)
86    }
87
88    /// Decode a keypair from a DER-encoded Secp256k1 secret key in an ECPrivateKey
89    /// structure as defined in [RFC5915].
90    ///
91    /// [RFC5915]: https://tools.ietf.org/html/rfc5915
92    #[cfg(feature = "secp256k1")]
93    pub fn secp256k1_from_der(der: &mut [u8]) -> Result<Keypair, DecodingError> {
94        secp256k1::SecretKey::from_der(der)
95            .map(|sk| Keypair::Secp256k1(secp256k1::Keypair::from(sk)))
96    }
97
98    /// Sign a message using the private key of this keypair, producing
99    /// a signature that can be verified using the corresponding public key.
100    pub fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, SigningError> {
101        use Keypair::*;
102        match self {
103            Ed25519(ref pair) => Ok(pair.sign(msg)),
104            #[cfg(not(target_arch = "wasm32"))]
105            Rsa(ref pair) => pair.sign(msg),
106            #[cfg(feature = "secp256k1")]
107            Secp256k1(ref pair) => pair.secret().sign(msg)
108        }
109    }
110
111    /// Get the public key of this keypair.
112    pub fn public(&self) -> PublicKey {
113        use Keypair::*;
114        match self {
115            Ed25519(pair) => PublicKey::Ed25519(pair.public()),
116            #[cfg(not(target_arch = "wasm32"))]
117            Rsa(pair) => PublicKey::Rsa(pair.public()),
118            #[cfg(feature = "secp256k1")]
119            Secp256k1(pair) => PublicKey::Secp256k1(pair.public().clone()),
120        }
121    }
122}
123
124/// The public key of a node's identity keypair.
125#[derive(Clone, Debug, PartialEq, Eq)]
126pub enum PublicKey {
127    /// A public Ed25519 key.
128    Ed25519(ed25519::PublicKey),
129    #[cfg(not(target_arch = "wasm32"))]
130    /// A public RSA key.
131    Rsa(rsa::PublicKey),
132    #[cfg(feature = "secp256k1")]
133    /// A public Secp256k1 key.
134    Secp256k1(secp256k1::PublicKey)
135}
136
137impl PublicKey {
138    /// Verify a signature for a message using this public key, i.e. check
139    /// that the signature has been produced by the corresponding
140    /// private key (authenticity), and that the message has not been
141    /// tampered with (integrity).
142    pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
143        use PublicKey::*;
144        match self {
145            Ed25519(pk) => pk.verify(msg, sig),
146            #[cfg(not(target_arch = "wasm32"))]
147            Rsa(pk) => pk.verify(msg, sig),
148            #[cfg(feature = "secp256k1")]
149            Secp256k1(pk) => pk.verify(msg, sig)
150        }
151    }
152
153    /// Encode the public key into a protobuf structure for storage or
154    /// exchange with other nodes.
155    pub fn into_protobuf_encoding(self) -> Vec<u8> {
156        use prost::Message;
157
158        let public_key = match self {
159            PublicKey::Ed25519(key) =>
160                keys_proto::PublicKey {
161                    r#type: keys_proto::KeyType::Ed25519 as i32,
162                    data: key.encode().to_vec()
163                },
164            #[cfg(not(target_arch = "wasm32"))]
165            PublicKey::Rsa(key) =>
166                keys_proto::PublicKey {
167                    r#type: keys_proto::KeyType::Rsa as i32,
168                    data: key.encode_x509()
169                },
170            #[cfg(feature = "secp256k1")]
171            PublicKey::Secp256k1(key) =>
172                keys_proto::PublicKey {
173                    r#type: keys_proto::KeyType::Secp256k1 as i32,
174                    data: key.encode().to_vec()
175                }
176        };
177
178        let mut buf = Vec::with_capacity(public_key.encoded_len());
179        public_key.encode(&mut buf).expect("Vec<u8> provides capacity as needed");
180        buf
181    }
182
183    /// Decode a public key from a protobuf structure, e.g. read from storage
184    /// or received from another node.
185    pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<PublicKey, DecodingError> {
186        use prost::Message;
187
188        #[allow(unused_mut)] // Due to conditional compilation.
189        let mut pubkey = keys_proto::PublicKey::decode(bytes)
190            .map_err(|e| DecodingError::new("Protobuf").source(e))?;
191
192        let key_type = keys_proto::KeyType::from_i32(pubkey.r#type)
193            .ok_or_else(|| DecodingError::new(format!("unknown key type: {}", pubkey.r#type)))?;
194
195        match key_type {
196            keys_proto::KeyType::Ed25519 => {
197                ed25519::PublicKey::decode(&pubkey.data).map(PublicKey::Ed25519)
198            },
199            #[cfg(not(target_arch = "wasm32"))]
200            keys_proto::KeyType::Rsa => {
201                rsa::PublicKey::decode_x509(&pubkey.data).map(PublicKey::Rsa)
202            }
203            #[cfg(target_arch = "wasm32")]
204            keys_proto::KeyType::Rsa => {
205                log::debug!("support for RSA was disabled at compile-time");
206                Err(DecodingError::new("Unsupported"))
207            },
208            #[cfg(feature = "secp256k1")]
209            keys_proto::KeyType::Secp256k1 => {
210                secp256k1::PublicKey::decode(&pubkey.data).map(PublicKey::Secp256k1)
211            }
212            #[cfg(not(feature = "secp256k1"))]
213            keys_proto::KeyType::Secp256k1 => {
214                log::debug!("support for secp256k1 was disabled at compile-time");
215                Err("Unsupported".to_string().into())
216            }
217        }
218    }
219
220    /// Convert the `PublicKey` into the corresponding `PeerId`.
221    pub fn into_peer_id(self) -> PeerId {
222        PeerId::from_public_key(self)
223    }
224}
225