1use ave_common::identity::KeyPair;
2use pkcs8::{Document, EncryptedPrivateKeyInfo, PrivateKeyInfo, pkcs5};
3
4use getrandom::fill;
5use std::fs;
6
7use crate::config::Config;
8use crate::error::BridgeError;
9
10const PBKDF2_ITERATIONS: u32 = 200_000;
11
12pub fn key_pair(
13 config: &Config,
14 password: &str,
15) -> Result<KeyPair, BridgeError> {
16 if fs::metadata(&config.keys_path).is_err() {
17 fs::create_dir_all(&config.keys_path)
18 .map_err(|e| BridgeError::KeyDirectoryCreation(e.to_string()))?;
19 }
20
21 let path = config.keys_path.join("node_private.der");
22 match fs::metadata(&path) {
23 Ok(_) => {
24 let document = Document::read_der_file(path)
25 .map_err(|e| BridgeError::KeyRead(e.to_string()))?;
26 let enc_pk = EncryptedPrivateKeyInfo::try_from(document.as_bytes())
27 .map_err(|e| BridgeError::KeyRead(e.to_string()))?;
28 let dec_pk = enc_pk
29 .decrypt(password)
30 .map_err(|e| BridgeError::KeyDecrypt(e.to_string()))?;
31
32 let key_pair = KeyPair::from_secret_der(dec_pk.as_bytes())
33 .map_err(|e| BridgeError::KeyRestore(e.to_string()))?;
34 Ok(key_pair)
35 }
36 Err(_) => {
37 let key_pair = config
38 .node
39 .keypair_algorithm
40 .generate_keypair()
41 .map_err(|e| BridgeError::KeyGeneration(e.to_string()))?;
42
43 let der = key_pair
44 .to_secret_der()
45 .map_err(|e| BridgeError::KeyGeneration(e.to_string()))?;
46 let pk = PrivateKeyInfo::try_from(der.as_slice())
47 .map_err(|e| BridgeError::KeyGeneration(e.to_string()))?;
48 let mut salt = [0u8; 32];
49 let mut iv = [0u8; 16];
50 fill(&mut salt)
51 .map_err(|e| BridgeError::KeyEncrypt(e.to_string()))?;
52 fill(&mut iv)
53 .map_err(|e| BridgeError::KeyEncrypt(e.to_string()))?;
54
55 let params = pkcs5::pbes2::Parameters::pbkdf2_sha256_aes256cbc(
56 PBKDF2_ITERATIONS,
57 &salt,
58 &iv,
59 )
60 .map_err(|e| BridgeError::KeyEncrypt(e.to_string()))?;
61 let enc_pk =
62 pk.encrypt_with_params(params, password).map_err(|_| {
63 BridgeError::KeyEncrypt(
64 "encryption algorithm failed".to_owned(),
65 )
66 })?;
67 enc_pk
68 .write_der_file(path)
69 .map_err(|e| BridgeError::KeyWrite(e.to_string()))?;
70 Ok(key_pair)
71 }
72 }
73}