libp2p_identity/
ecdsa.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//! ECDSA keys with secp256r1 curve support.
22
23use core::{cmp, fmt, hash};
24use std::convert::Infallible;
25
26use p256::{
27    ecdsa::{
28        signature::{Signer, Verifier},
29        Signature, SigningKey, VerifyingKey,
30    },
31    EncodedPoint,
32};
33use sec1::{DecodeEcPrivateKey, EncodeEcPrivateKey};
34use zeroize::Zeroize;
35
36use super::error::DecodingError;
37
38/// An ECDSA keypair generated using `secp256r1` curve.
39#[derive(Clone)]
40pub struct Keypair {
41    secret: SecretKey,
42    public: PublicKey,
43}
44
45impl Keypair {
46    /// Generate a new random ECDSA keypair.
47    #[cfg(feature = "rand")]
48    pub fn generate() -> Keypair {
49        Keypair::from(SecretKey::generate())
50    }
51
52    /// Sign a message using the private key of this keypair.
53    pub fn sign(&self, msg: &[u8]) -> Vec<u8> {
54        self.secret.sign(msg)
55    }
56
57    /// Get the public key of this keypair.
58    pub fn public(&self) -> &PublicKey {
59        &self.public
60    }
61
62    /// Get the secret key of this keypair.
63    pub fn secret(&self) -> &SecretKey {
64        &self.secret
65    }
66}
67
68impl fmt::Debug for Keypair {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        f.debug_struct("Keypair")
71            .field("public", &self.public())
72            .finish()
73    }
74}
75
76/// Promote an ECDSA secret key into a keypair.
77impl From<SecretKey> for Keypair {
78    fn from(secret: SecretKey) -> Keypair {
79        let public = PublicKey(VerifyingKey::from(&secret.0));
80        Keypair { secret, public }
81    }
82}
83
84/// Demote an ECDSA keypair to a secret key.
85impl From<Keypair> for SecretKey {
86    fn from(kp: Keypair) -> SecretKey {
87        kp.secret
88    }
89}
90
91/// An ECDSA secret key generated using `secp256r1` curve.
92#[derive(Clone)]
93pub struct SecretKey(SigningKey);
94
95impl SecretKey {
96    /// Generate a new random ECDSA secret key.
97    #[cfg(feature = "rand")]
98    pub fn generate() -> SecretKey {
99        SecretKey(SigningKey::random(&mut rand::thread_rng()))
100    }
101
102    /// Sign a message with this secret key, producing a DER-encoded ECDSA signature.
103    pub fn sign(&self, msg: &[u8]) -> Vec<u8> {
104        let signature: p256::ecdsa::DerSignature = self.0.sign(msg);
105
106        signature.as_bytes().to_owned()
107    }
108
109    /// Convert a secret key into a byte buffer containing raw scalar of the key.
110    pub fn to_bytes(&self) -> Vec<u8> {
111        self.0.to_bytes().to_vec()
112    }
113
114    /// Try to parse a secret key from a byte buffer containing raw scalar of the key.
115    pub fn try_from_bytes(buf: impl AsRef<[u8]>) -> Result<SecretKey, DecodingError> {
116        SigningKey::from_bytes(buf.as_ref().into())
117            .map_err(|err| DecodingError::failed_to_parse("ecdsa p256 secret key", err))
118            .map(SecretKey)
119    }
120
121    /// Encode the secret key into DER-encoded byte buffer.
122    pub(crate) fn encode_der(&self) -> Vec<u8> {
123        self.0
124            .to_sec1_der()
125            .expect("Encoding to pkcs#8 format to succeed")
126            .to_bytes()
127            .to_vec()
128    }
129
130    /// Try to decode a secret key from a DER-encoded byte buffer, zeroize the buffer on success.
131    pub(crate) fn try_decode_der(buf: &mut [u8]) -> Result<Self, DecodingError> {
132        match SigningKey::from_sec1_der(buf) {
133            Ok(key) => {
134                buf.zeroize();
135                Ok(SecretKey(key))
136            }
137            Err(e) => Err(DecodingError::failed_to_parse("ECDSA", e)),
138        }
139    }
140}
141
142impl fmt::Debug for SecretKey {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        write!(f, "SecretKey")
145    }
146}
147
148/// An ECDSA public key.
149#[derive(Clone, Eq, PartialOrd, Ord)]
150pub struct PublicKey(VerifyingKey);
151
152impl PublicKey {
153    /// Verify an ECDSA signature on a message using the public key.
154    pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
155        let Ok(sig) = Signature::from_der(sig) else {
156            return false;
157        };
158        self.0.verify(msg, &sig).is_ok()
159    }
160
161    /// Try to parse a public key from a byte buffer containing raw
162    /// components of a key with or without compression.
163    pub fn try_from_bytes(k: &[u8]) -> Result<PublicKey, DecodingError> {
164        let enc_pt = EncodedPoint::from_bytes(k)
165            .map_err(|e| DecodingError::failed_to_parse("ecdsa p256 encoded point", e))?;
166
167        VerifyingKey::from_encoded_point(&enc_pt)
168            .map_err(|err| DecodingError::failed_to_parse("ecdsa p256 public key", err))
169            .map(PublicKey)
170    }
171
172    /// Convert a public key into a byte buffer containing
173    /// raw components of the key without compression.
174    pub fn to_bytes(&self) -> Vec<u8> {
175        self.0.to_encoded_point(false).as_bytes().to_owned()
176    }
177
178    /// Encode a public key into a DER encoded byte buffer as defined by SEC1 standard.
179    pub fn encode_der(&self) -> Vec<u8> {
180        let buf = self.to_bytes();
181        Self::add_asn1_header(&buf)
182    }
183
184    /// Try to decode a public key from a DER encoded byte buffer as defined by SEC1 standard.
185    pub fn try_decode_der(k: &[u8]) -> Result<PublicKey, DecodingError> {
186        let buf = Self::del_asn1_header(k).ok_or_else(|| {
187            DecodingError::failed_to_parse::<Infallible, _>(
188                "ASN.1-encoded ecdsa p256 public key",
189                None,
190            )
191        })?;
192        Self::try_from_bytes(buf)
193    }
194
195    // ecPublicKey (ANSI X9.62 public key type) OID: 1.2.840.10045.2.1
196    const EC_PUBLIC_KEY_OID: [u8; 9] = [0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
197    // secp256r1 OID: 1.2.840.10045.3.1.7
198    const SECP_256_R1_OID: [u8; 10] = [0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07];
199
200    // Add ASN1 header.
201    fn add_asn1_header(key_buf: &[u8]) -> Vec<u8> {
202        // ASN.1 struct type and length.
203        let mut asn1_buf = vec![
204            0x30,
205            0x00,
206            0x30,
207            (Self::EC_PUBLIC_KEY_OID.len() + Self::SECP_256_R1_OID.len()) as u8,
208        ];
209        // Append OIDs.
210        asn1_buf.extend_from_slice(&Self::EC_PUBLIC_KEY_OID);
211        asn1_buf.extend_from_slice(&Self::SECP_256_R1_OID);
212        // Append key bitstring type and length.
213        asn1_buf.extend_from_slice(&[0x03, (key_buf.len() + 1) as u8, 0x00]);
214        // Append key bitstring value.
215        asn1_buf.extend_from_slice(key_buf);
216        // Update overall length field.
217        asn1_buf[1] = (asn1_buf.len() - 2) as u8;
218
219        asn1_buf
220    }
221
222    // Check and remove ASN.1 header.
223    fn del_asn1_header(asn1_buf: &[u8]) -> Option<&[u8]> {
224        let oids_len = Self::EC_PUBLIC_KEY_OID.len() + Self::SECP_256_R1_OID.len();
225        let asn1_head = asn1_buf.get(..4)?;
226        let oids_buf = asn1_buf.get(4..4 + oids_len)?;
227        let bitstr_head = asn1_buf.get(4 + oids_len..4 + oids_len + 3)?;
228
229        // Sanity check
230        if asn1_head[0] != 0x30
231            || asn1_head[2] != 0x30
232            || asn1_head[3] as usize != oids_len
233            || oids_buf[..Self::EC_PUBLIC_KEY_OID.len()] != Self::EC_PUBLIC_KEY_OID
234            || oids_buf[Self::EC_PUBLIC_KEY_OID.len()..] != Self::SECP_256_R1_OID
235            || bitstr_head[0] != 0x03
236            || bitstr_head[2] != 0x00
237        {
238            return None;
239        }
240
241        let key_len = bitstr_head[1].checked_sub(1)? as usize;
242        let key_buf = asn1_buf.get(4 + oids_len + 3..4 + oids_len + 3 + key_len)?;
243        Some(key_buf)
244    }
245}
246
247impl fmt::Debug for PublicKey {
248    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
249        f.write_str("PublicKey(asn.1 uncompressed): ")?;
250        for byte in &self.encode_der() {
251            write!(f, "{byte:x}")?;
252        }
253        Ok(())
254    }
255}
256
257impl cmp::PartialEq for PublicKey {
258    fn eq(&self, other: &Self) -> bool {
259        self.to_bytes().eq(&other.to_bytes())
260    }
261}
262
263impl hash::Hash for PublicKey {
264    fn hash<H: hash::Hasher>(&self, state: &mut H) {
265        self.to_bytes().hash(state);
266    }
267}
268
269#[cfg(test)]
270mod tests {
271    use super::*;
272
273    #[test]
274    #[cfg(feature = "rand")]
275    fn sign_verify() {
276        let pair = Keypair::generate();
277        let pk = pair.public();
278
279        let msg = "hello world".as_bytes();
280        let sig = pair.sign(msg);
281        assert!(pk.verify(msg, &sig));
282
283        let mut invalid_sig = sig.clone();
284        invalid_sig[3..6].copy_from_slice(&[10, 23, 42]);
285        assert!(!pk.verify(msg, &invalid_sig));
286
287        let invalid_msg = "h3ll0 w0rld".as_bytes();
288        assert!(!pk.verify(invalid_msg, &sig));
289    }
290}