-
Notifications
You must be signed in to change notification settings - Fork 7
/
decrypt.rs
146 lines (135 loc) · 5 KB
/
decrypt.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2020 David Egan
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
extern crate crypto;
use crate::data_process::Data;
use crypto::scrypt::ScryptParams;
use crypto::scrypt::scrypt;
use self::crypto::digest::Digest;
use self::crypto::sha3::Sha3;
/**
* Derive key for decryption by means of scrypt with the provided parameters from the original
* keyfile along with the user-supplied password (`data.password`).
* */
pub fn derive_key(data: &Data) -> Result<Vec<u8>, &'static str> {
let mut n = data.n as f64;
n = n.log2();
let log_2_n = n as u8;
let params = ScryptParams::new(log_2_n, data.r, data.p);
let mut result: Vec<u8> = vec![0; data.dklen as usize];
scrypt(&data.password, &data.salt, ¶ms, &mut result);
Ok(result.to_vec())
}
/**
* Establish authenticity of the derived key.
* This is achieved by comparing the given message authentication code (data.mac) with the
* sha3 keccak256 hash of the ciphertext concatenated with last 16 bytes of the derived key.
* */
pub fn check_key(data: &Data, key: &Vec<u8>) -> bool {
// Last 16 bytes of the derived key
let mut k: Vec<u8> = key.split_at(16).1.to_vec();
// Concatenate the ciphertext
for el in data.ct.iter() {
k.push(*el);
}
let mut hasher = Sha3::keccak256();
hasher.input(&k);
let result_slice = &mut vec![0;32];
hasher.result(result_slice);
return result_slice == &data.mac;
}
/**
* Decrypt ciphertext (`data.ct`) using the provided key.
* Note that for AES 128 bit counter mode the aes_key must be 16 bytes, but the Ethereum keyfile
* key derivation algorithm uses scrypt to derive a 32 byte key from a user-supplied password.
* Use the first 16 bytes of this derived key to AES decrypt ciphertext in AES-128 counter mode.
* */
pub fn decrypt(data: &Data, key: &Vec<u8>) -> Result<Vec<u8>, &'static str> {
use aes_ctr::Aes128Ctr;
use aes_ctr::stream_cipher::generic_array::GenericArray;
use aes_ctr::stream_cipher::{
NewStreamCipher, SyncStreamCipher
};
let aes_key = GenericArray::from_slice(key.split_at(16).0);
let initialization_vector = GenericArray::from_slice(&data.iv);
let mut ct = (data.ct).clone();
let mut cipher = Aes128Ctr::new(&aes_key, &initialization_vector);
cipher.apply_keystream(&mut ct);
Ok(ct.to_vec())
}
#[cfg(test)]
mod tests {
use super::*;
/**
* Data from the provided test keyfile, with a known private key and password
* */
fn test_data() -> Data {
Data {
ct: vec![
0x05, 0x0d, 0x93, 0xd6, 0xa4, 0xe3, 0x96, 0xa0,
0xcb, 0x74, 0xd0, 0x21, 0xd0, 0xde, 0x9b, 0x1e,
0xd7, 0x86, 0x0c, 0x0f, 0xd8, 0x43, 0xb2, 0x8a,
0xce, 0xfb, 0xd3, 0xdc, 0x61, 0x31, 0x4a, 0x19,
],
salt: vec![
0xb0, 0x4d, 0xcc, 0xcf, 0x35, 0x1d, 0xba, 0x67,
0x46, 0x0e, 0x5b, 0xf3, 0x22, 0x49, 0x3a, 0xb2,
0x5b, 0x4e, 0x1b, 0x31, 0x4d, 0xf9, 0x70, 0x50,
0x3e, 0xd4, 0x3c, 0x39, 0x21, 0x66, 0xd4, 0xc8,
],
mac: vec![
0xc9, 0xa7, 0xa0, 0xc8, 0x80, 0x28, 0x9d, 0x26,
0x7c, 0x49, 0xbf, 0x82, 0x8a, 0xce, 0x98, 0xec,
0xb8, 0x9c, 0x64, 0xd6, 0x00, 0xbb, 0xee, 0xd7,
0x18, 0xda, 0xc9, 0xf6, 0x05, 0x08, 0x3e, 0x61,
],
iv: vec![
0x6a, 0xa1, 0xde, 0x28, 0xf8, 0xf4, 0x3a, 0x52,
0x2e, 0x6a, 0xc9, 0x87, 0xc1, 0x8b, 0xf6, 0x6e,
],
password: b"password123".to_vec(),
..Default::default()
}
}
/**
* The key which should be derived from the correct password "password123"
* an the given scrypt parameters.
* */
fn test_key() -> Vec<u8> {
vec![
0x5a, 0xe6, 0xf8, 0x78, 0x53, 0x37, 0x64, 0x5b,
0x7c, 0xed, 0xd5, 0x3f, 0x71, 0x28, 0x63, 0xb7,
0x0c, 0xc0, 0x61, 0x5f, 0x48, 0xf1, 0x8a, 0x3e,
0x27, 0xa8, 0xf9, 0x22, 0xed, 0xc1, 0x3a, 0x84,
]
}
#[test]
fn correct_derive_key() {
let key = test_key();
let data = test_data();
println!("{:?}", data);
assert_eq!(key, derive_key(&data).unwrap());
}
#[test]
fn correct_decrypt() {
let private_key = vec![
0x82, 0x63, 0x39, 0x60, 0xe2, 0xa7, 0x25, 0xab,
0x64, 0x10, 0x67, 0xa1, 0x2b, 0x05, 0xfc, 0xae,
0xca, 0x86, 0x0d, 0x45, 0xba, 0x78, 0x5f, 0x63,
0x43, 0x18, 0x49, 0x02, 0x61, 0xe5, 0xd1, 0xa1,
];
let key = test_key();
let data = test_data();
assert_eq!(private_key, decrypt(&data, &key).unwrap());
}
#[test]
fn correct_check_key() {
let key = test_key();
let data = test_data();
assert!(check_key(&data, &key));
}
}