ethsign_crypto/
lib.rs

1//! Pure Rust drop-in replacement for the `parity-crypto` crate.
2
3pub mod aes;
4pub mod error;
5pub mod scrypt;
6
7pub use error::Error;
8
9use hmac::Hmac;
10use pbkdf2::pbkdf2;
11use sha2::Sha256;
12use tiny_keccak::{Hasher, Keccak};
13
14pub const KEY_LENGTH: usize = 32;
15pub const KEY_LENGTH_AES: usize = KEY_LENGTH / 2;
16
17/// Helper trait for conveniently hashing byte slices
18pub trait Keccak256<T: Sized> {
19    /// Hash self to a hash type `T`.
20    fn keccak256(&self) -> T;
21}
22
23impl Keccak256<[u8; 32]> for [u8] {
24    fn keccak256(&self) -> [u8; 32] {
25        let mut keccak = Keccak::v256();
26        let mut result = [0u8; 32];
27        keccak.update(self);
28        keccak.finalize(&mut result);
29        result
30    }
31}
32
33impl<T: AsRef<[u8]>> Keccak256<[u8; 32]> for T {
34    fn keccak256(&self) -> [u8; 32] {
35        self.as_ref().keccak256()
36    }
37}
38
39pub fn derive_key_iterations(password: &[u8], salt: &[u8], c: u32) -> (Vec<u8>, Vec<u8>) {
40    let mut derived_key = [0u8; KEY_LENGTH];
41    pbkdf2::<Hmac<Sha256>>(password, salt, c, &mut derived_key).expect("Length is valid; qed");
42    let derived_right_bits = &derived_key[0..KEY_LENGTH_AES];
43    let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH];
44    (derived_right_bits.to_vec(), derived_left_bits.to_vec())
45}
46
47pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec<u8> {
48    let mut mac = vec![0u8; KEY_LENGTH_AES + cipher_text.len()];
49    mac[0..KEY_LENGTH_AES].copy_from_slice(derived_left_bits);
50    mac[KEY_LENGTH_AES..cipher_text.len() + KEY_LENGTH_AES].copy_from_slice(cipher_text);
51    mac
52}
53
54/// Check if two slices are equal, this is equivalent to `a == b` and is only exposed here
55/// as a replacement for `parity-crypto` version which uses constant time compare from `ring`.
56pub fn is_equal(a: &[u8], b: &[u8]) -> bool {
57    a == b
58}
59
60#[cfg(test)]
61mod test {
62    #[test]
63    fn derive_behaves_like_parity_crypto() {
64        let password = b"amazing password";
65        let salt = b"salty sailor";
66        let c = 2048;
67
68        let rust_derive = super::derive_key_iterations(password, salt, c);
69        let ring_derive = parity_crypto::derive_key_iterations(password, salt, c);
70
71        assert_eq!(rust_derive, ring_derive);
72    }
73
74    #[test]
75    fn aes_behaves_like_parity_crypto() {
76        let key = b"very secret key.";
77        let nonce = b"and secret nonce";
78
79        let data = b"some bytes over here!";
80        let encrypted = b"\x74\x98\x10\x1d\x91\xf6\x5b\x89\xe4\xb9\x71\x96\x45\x4f\x02\xc3\xb4\x2f\xa3\xe4\x9b";
81
82        let mut dest_rust = [0u8; 21];
83        let mut dest_ring = [0u8; 21];
84
85        super::aes::encrypt_128_ctr(key, nonce, data, &mut dest_rust).unwrap();
86        parity_crypto::aes::encrypt_128_ctr(key, nonce, data, &mut dest_ring).unwrap();
87
88        assert_eq!(&dest_rust, encrypted);
89        assert_eq!(&dest_ring, encrypted);
90
91        super::aes::decrypt_128_ctr(key, nonce, encrypted, &mut dest_rust).unwrap();
92        parity_crypto::aes::decrypt_128_ctr(key, nonce, encrypted, &mut dest_ring).unwrap();
93
94        assert_eq!(&dest_rust, data);
95        assert_eq!(&dest_ring, data);
96    }
97}