cfx_crypto/
crypto.rs

1// Copyright 2015-2019 Parity Technologies (UK) Ltd.
2// This file is part of Parity Ethereum.
3//
4// Parity Ethereum is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Parity Ethereum is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Parity Ethereum.  If not, see <http://www.gnu.org/licenses/>.
16
17// Copyright 2020 Parity Technologies
18//
19// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
20// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
21// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
22// option. This file may not be copied, modified, or distributed
23// except according to those terms.
24
25use crate::{KeyPair, RandomKeyPairGenerator, SecretKey, SECP256K1};
26use std::io;
27use subtle::ConstantTimeEq;
28
29pub const KEY_LENGTH: usize = 32;
30pub const KEY_ITERATIONS: usize = 10240;
31pub const KEY_LENGTH_AES: usize = KEY_LENGTH / 2;
32
33#[derive(Debug, thiserror::Error)]
34pub enum Error {
35    #[error("secp256k1 error: {0}")]
36    Secp(#[from] secp256k1::Error),
37    #[error("i/o error: {0}")]
38    Io(#[from] io::Error),
39    #[error("invalid message")]
40    InvalidMessage,
41    #[error("aes error")]
42    Aes,
43}
44
45/// ECDH functions
46pub mod ecdh {
47    use super::{Error, SecretKey, SECP256K1};
48    use secp256k1::{self, ecdh, key};
49
50    /// Agree on a shared secret
51    pub fn agree<S, P>(secret: &S, public: &P) -> Result<S, Error>
52    where
53        S: SecretKey,
54        P: AsRef<[u8]>,
55    {
56        let context = &SECP256K1;
57        let pdata = {
58            let mut temp = [4u8; 65];
59            let pub_bytes = public.as_ref();
60            if pub_bytes.len() < 64 {
61                return Err(Error::Secp(secp256k1::Error::InvalidPublicKey));
62            }
63            (&mut temp[1..65]).copy_from_slice(&pub_bytes[0..64]);
64            temp
65        };
66
67        let publ = key::PublicKey::from_slice(context, &pdata)?;
68        let sec = key::SecretKey::from_slice(context, secret.as_ref())?;
69        let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec);
70
71        S::from_unsafe_slice(&shared[0..32])
72            .map_err(|_| Error::Secp(secp256k1::Error::InvalidSecretKey))
73    }
74}
75
76/// ECIES function
77pub mod ecies {
78    use super::{
79        ecdh, is_equal, Error, KeyPair, RandomKeyPairGenerator, SecretKey,
80    };
81    use cfx_types::H128;
82    use hmac::{Hmac, Mac};
83    use sha2::{Digest, Sha256};
84
85    type HmacSha256 = Hmac<Sha256>;
86
87    /// Encrypt a message with a public key, writing an HMAC covering both
88    /// the plaintext and authenticated data.
89    ///
90    /// Authenticated data may be empty.
91    pub fn encrypt<G, KP, S, P>(
92        generator: &mut G, public: &P, auth_data: &[u8], plain: &[u8],
93    ) -> Result<Vec<u8>, Error>
94    where
95        G: RandomKeyPairGenerator<KeyPair = KP, Error = std::io::Error>,
96        KP: KeyPair<Secret = S, Public = P>,
97        S: SecretKey,
98        P: AsRef<[u8]>,
99    {
100        let r = generator.generate()?;
101        let z = ecdh::agree(r.secret(), public)?;
102        let mut key = [0u8; 32];
103        kdf(&z, &[0u8; 0], &mut key);
104
105        let ekey = &key[0..16];
106        let mkey = Sha256::digest(&key[16..32]);
107
108        let mut msg = vec![0u8; 1 + 64 + 16 + plain.len() + 32];
109        msg[0] = 0x04u8;
110        {
111            let msgd = &mut msg[1..];
112            let pub_bytes = r.public().as_ref();
113            if pub_bytes.len() < 64 {
114                return Err(Error::InvalidMessage);
115            }
116            msgd[0..64].copy_from_slice(&pub_bytes[0..64]);
117            let iv = H128::random();
118            msgd[64..80].copy_from_slice(iv.as_bytes());
119            {
120                let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())];
121                super::aes::encrypt_128_ctr(
122                    ekey,
123                    iv.as_bytes(),
124                    plain,
125                    cipher,
126                )?;
127            }
128            let mut hmac = HmacSha256::new_from_slice(mkey.as_slice())
129                .expect("output of Sha256 has invalid length");
130            {
131                let cipher_iv = &msgd[64..(64 + 16 + plain.len())];
132                hmac.update(cipher_iv);
133            }
134            hmac.update(auth_data);
135            let sig = hmac.finalize().into_bytes();
136            msgd[(64 + 16 + plain.len())..].copy_from_slice(&sig);
137        }
138        Ok(msg)
139    }
140
141    /// Decrypt a message with a secret key, checking HMAC for ciphertext
142    /// and authenticated data validity.
143    pub fn decrypt<S>(
144        secret: &S, auth_data: &[u8], encrypted: &[u8],
145    ) -> Result<Vec<u8>, Error>
146    where S: SecretKey {
147        let meta_len = 1 + 64 + 16 + 32;
148        if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 {
149            return Err(Error::InvalidMessage); //invalid message: publickey
150        }
151
152        let e = &encrypted[1..];
153        // Extract public key bytes directly - use a fixed-size array reference
154        let mut pub_array = [0u8; 64];
155        pub_array.copy_from_slice(&e[0..64]);
156        let z = ecdh::agree(secret, &pub_array)?;
157        let mut key = [0u8; 32];
158        kdf(&z, &[0u8; 0], &mut key);
159
160        let ekey = &key[0..16];
161        let mkey = Sha256::digest(&key[16..32]);
162
163        let clen = encrypted.len() - meta_len;
164        let cipher_with_iv = &e[64..(64 + 16 + clen)];
165        let cipher_iv = &cipher_with_iv[0..16];
166        let cipher_no_iv = &cipher_with_iv[16..];
167        let msg_mac = &e[(64 + 16 + clen)..];
168
169        // Verify tag
170        let mut hmac = HmacSha256::new_from_slice(mkey.as_slice())
171            .expect("output of Sha256 has invalid length");
172        hmac.update(cipher_with_iv);
173        hmac.update(auth_data);
174        let mac = hmac.finalize().into_bytes();
175
176        if !is_equal(mac.as_slice(), msg_mac) {
177            return Err(Error::InvalidMessage);
178        }
179
180        let mut msg = vec![0u8; clen];
181        super::aes::decrypt_128_ctr(
182            ekey,
183            cipher_iv,
184            cipher_no_iv,
185            &mut msg[..],
186        )?;
187        Ok(msg)
188    }
189
190    fn kdf<S: SecretKey>(secret: &S, s1: &[u8], dest: &mut [u8]) {
191        // SEC/ISO/Shoup specify counter size SHOULD be equivalent
192        // to size of hash output, however, it also notes that
193        // the 4 bytes is okay. NIST specifies 4 bytes.
194        let mut ctr = 1u32;
195        let mut written = 0usize;
196        while written < dest.len() {
197            let mut hasher = Sha256::new();
198            let ctrs = [
199                (ctr >> 24) as u8,
200                (ctr >> 16) as u8,
201                (ctr >> 8) as u8,
202                ctr as u8,
203            ];
204            hasher.update(&ctrs);
205            hasher.update(secret.as_ref());
206            hasher.update(s1);
207            let d = hasher.finalize();
208            dest[written..(written + 32)].copy_from_slice(&d);
209            written += 32;
210            ctr += 1;
211        }
212    }
213}
214
215pub mod aes {
216    use super::Error;
217    use aes::Aes128;
218    use cbc::{cipher::BlockDecryptMut, Decryptor};
219    use ctr::{
220        cipher::{KeyIvInit as CtrKeyIvInit, StreamCipher},
221        Ctr128BE,
222    };
223
224    type Aes128Ctr = Ctr128BE<Aes128>;
225    type Aes128CbcDec = Decryptor<Aes128>;
226
227    pub fn encrypt_128_ctr(
228        key: &[u8], iv: &[u8], plain: &[u8], ciphertext: &mut [u8],
229    ) -> Result<(), Error> {
230        let mut cipher = Aes128Ctr::new(key.into(), iv.into());
231        ciphertext[..plain.len()].copy_from_slice(plain);
232        cipher
233            .try_apply_keystream(ciphertext)
234            .map_err(|_| Error::Aes)?;
235        Ok(())
236    }
237
238    pub fn decrypt_128_ctr(
239        key: &[u8], iv: &[u8], ciphertext: &[u8], plain: &mut [u8],
240    ) -> Result<(), Error> {
241        let mut cipher = Aes128Ctr::new(key.into(), iv.into());
242        plain[..ciphertext.len()].copy_from_slice(ciphertext);
243        cipher.try_apply_keystream(plain).map_err(|_| Error::Aes)?;
244        Ok(())
245    }
246
247    pub fn decrypt_128_cbc<'a>(
248        key: &[u8], iv: &[u8], data: &[u8], dest: &'a mut [u8],
249    ) -> Result<&'a [u8], String> {
250        if key.len() != 16 {
251            return Err("Key must be exactly 16 bytes for AES-128".to_string());
252        }
253
254        if iv.len() != 16 {
255            return Err("IV must be exactly 16 bytes".to_string());
256        }
257
258        if data.is_empty() {
259            return Err("Data cannot be empty".to_string());
260        }
261
262        if data.len() % 16 != 0 {
263            return Err(
264                "Data length must be a multiple of 16 bytes".to_string()
265            );
266        }
267
268        // Create decryptor
269        let decryptor = Aes128CbcDec::new(key.into(), iv.into());
270        dest[..data.len()].copy_from_slice(data);
271
272        // Decrypt and remove PKCS7 padding
273        let plaintext = decryptor
274            .decrypt_padded_mut::<cbc::cipher::block_padding::Pkcs7>(dest)
275            .map_err(|e| format!("Decryption failed: {}", e))?;
276
277        Ok(plaintext)
278    }
279}
280
281pub mod keccak {
282    use tiny_keccak::{Hasher, Keccak};
283
284    pub trait Keccak256<T> {
285        fn keccak256(&self) -> T
286        where T: Sized;
287    }
288
289    impl<T> Keccak256<[u8; 32]> for T
290    where T: AsRef<[u8]>
291    {
292        fn keccak256(&self) -> [u8; 32] {
293            let mut keccak = Keccak::v256();
294            let mut result = [0u8; 32];
295            keccak.update(self.as_ref());
296            keccak.finalize(&mut result);
297            result
298        }
299    }
300}
301
302pub mod scrypt {
303    use super::{KEY_LENGTH, KEY_LENGTH_AES};
304    use scrypt::{errors, scrypt, Params};
305
306    pub fn derive_key(
307        pass: &[u8], salt: &[u8], n: u32, p: u32, r: u32,
308    ) -> Result<(Vec<u8>, Vec<u8>), String> {
309        // sanity checks
310        let log_n = (32 - n.leading_zeros() - 1) as u8;
311        if log_n as u32 >= r * 16 {
312            return Err(errors::InvalidParams.to_string());
313        }
314
315        if p as u64 > ((u32::MAX as u64 - 1) * 32) / (128 * (r as u64)) {
316            return Err(errors::InvalidParams.to_string());
317        }
318
319        let mut derived_key = vec![0u8; KEY_LENGTH];
320        let scrypt_params =
321            Params::new(log_n, r, p, KEY_LENGTH).map_err(|e| e.to_string())?;
322        scrypt(pass, salt, &scrypt_params, &mut derived_key)
323            .map_err(|e| e.to_string())?;
324        let derived_right_bits = &derived_key[0..KEY_LENGTH_AES];
325        let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH];
326        Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec()))
327    }
328}
329
330pub mod pbkdf2 {
331    use super::{KEY_LENGTH, KEY_LENGTH_AES};
332    use hmac;
333    use pbkdf2;
334    use sha2;
335
336    pub struct Salt<'a>(pub &'a [u8]);
337    pub struct Secret<'a>(pub &'a [u8]);
338
339    pub fn sha256(
340        iter: u32, salt: Salt<'_>, sec: Secret<'_>, out: &mut [u8; 32],
341    ) -> Result<(), String> {
342        pbkdf2::pbkdf2::<hmac::Hmac<sha2::Sha256>>(sec.0, salt.0, iter, out)
343            .map_err(|e| e.to_string())
344    }
345
346    pub fn sha512(
347        iter: u32, salt: Salt<'_>, sec: Secret<'_>, out: &mut [u8; 64],
348    ) -> Result<(), String> {
349        pbkdf2::pbkdf2::<hmac::Hmac<sha2::Sha512>>(sec.0, salt.0, iter, out)
350            .map_err(|e| e.to_string())
351    }
352
353    pub fn derive_key_iterations(
354        password: &[u8], salt: &[u8], c: u32,
355    ) -> Result<(Vec<u8>, Vec<u8>), String> {
356        let mut derived_key = [0u8; KEY_LENGTH];
357        sha256(c, Salt(salt), Secret(password), &mut derived_key)?;
358        let derived_right_bits = &derived_key[0..KEY_LENGTH_AES];
359        let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH];
360        Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec()))
361    }
362}
363
364pub mod digest {
365    use std::{marker::PhantomData, ops::Deref};
366
367    use digest::generic_array::{
368        typenum::{U20, U32, U64},
369        GenericArray,
370    };
371    use ripemd;
372    use sha2::Digest as RDigest;
373
374    /// The message digest.
375    pub struct Digest<T>(InnerDigest, PhantomData<T>);
376
377    enum InnerDigest {
378        Sha256(GenericArray<u8, U32>),
379        Sha512(GenericArray<u8, U64>),
380        Ripemd160(GenericArray<u8, U20>),
381    }
382
383    impl<T> Deref for Digest<T> {
384        type Target = [u8];
385
386        fn deref(&self) -> &Self::Target {
387            match self.0 {
388                InnerDigest::Sha256(ref d) => &d[..],
389                InnerDigest::Sha512(ref d) => &d[..],
390                InnerDigest::Ripemd160(ref d) => &d[..],
391            }
392        }
393    }
394
395    /// Single-step sha256 digest computation.
396    pub fn sha256(data: &[u8]) -> Digest<Sha256> {
397        let mut hasher = Hasher::sha256();
398        hasher.update(data);
399        hasher.finish()
400    }
401
402    /// Single-step sha512 digest computation.
403    pub fn sha512(data: &[u8]) -> Digest<Sha512> {
404        let mut hasher = Hasher::sha512();
405        hasher.update(data);
406        hasher.finish()
407    }
408
409    /// Single-step ripemd160 digest computation.
410    pub fn ripemd160(data: &[u8]) -> Digest<Ripemd160> {
411        let mut hasher = Hasher::ripemd160();
412        hasher.update(data);
413        hasher.finish()
414    }
415
416    #[derive(Debug)]
417    pub enum Sha256 {}
418    #[derive(Debug)]
419    pub enum Sha512 {}
420    #[derive(Debug)]
421    pub enum Ripemd160 {}
422
423    /// Stateful digest computation.
424    pub struct Hasher<T>(Inner, PhantomData<T>);
425
426    enum Inner {
427        Sha256(sha2::Sha256),
428        Sha512(sha2::Sha512),
429        Ripemd160(ripemd::Ripemd160),
430    }
431
432    impl Hasher<Sha256> {
433        pub fn sha256() -> Hasher<Sha256> {
434            Hasher(Inner::Sha256(sha2::Sha256::default()), PhantomData)
435        }
436    }
437
438    impl Hasher<Sha512> {
439        pub fn sha512() -> Hasher<Sha512> {
440            Hasher(Inner::Sha512(sha2::Sha512::default()), PhantomData)
441        }
442    }
443
444    impl Hasher<Ripemd160> {
445        pub fn ripemd160() -> Hasher<Ripemd160> {
446            Hasher(Inner::Ripemd160(ripemd::Ripemd160::default()), PhantomData)
447        }
448    }
449
450    impl<T> Hasher<T> {
451        pub fn update(&mut self, data: &[u8]) {
452            match self.0 {
453                Inner::Sha256(ref mut ctx) => ctx.update(data),
454                Inner::Sha512(ref mut ctx) => ctx.update(data),
455                Inner::Ripemd160(ref mut ctx) => ctx.update(data),
456            }
457        }
458
459        pub fn finish(self) -> Digest<T> {
460            match self.0 {
461                Inner::Sha256(ctx) => {
462                    Digest(InnerDigest::Sha256(ctx.finalize()), PhantomData)
463                }
464                Inner::Sha512(ctx) => {
465                    Digest(InnerDigest::Sha512(ctx.finalize()), PhantomData)
466                }
467                Inner::Ripemd160(ctx) => {
468                    Digest(InnerDigest::Ripemd160(ctx.finalize()), PhantomData)
469                }
470            }
471        }
472    }
473}
474
475pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec<u8> {
476    let mut mac = vec![0u8; KEY_LENGTH_AES + cipher_text.len()];
477    mac[0..KEY_LENGTH_AES].copy_from_slice(derived_left_bits);
478    mac[KEY_LENGTH_AES..cipher_text.len() + KEY_LENGTH_AES]
479        .copy_from_slice(cipher_text);
480    mac
481}
482
483pub fn is_equal(a: &[u8], b: &[u8]) -> bool { a.ct_eq(b).into() }