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