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
use std::path::Path;

use anyhow::{anyhow, Result};
use pkcs8::{
    AlgorithmIdentifier, EncryptedPrivateKeyDocument, ObjectIdentifier,
    PrivateKeyInfo,
};
use rand::{prelude::StdRng, rngs::OsRng, SeedableRng};
use serde::{de::DeserializeOwned, Serialize};

const OID: &str = "1.0.0";

// TODO(lpl): Store crypto parameters.
fn algorithm_identifier() -> AlgorithmIdentifier<'static> {
    AlgorithmIdentifier {
        oid: ObjectIdentifier::new(OID),
        parameters: None,
    }
}

/// Encrypt `pri_key` with `passwd`, and save it to `path`.
pub fn save_pri_key<P: AsRef<Path>, K: Serialize>(
    path: P, passwd: impl AsRef<[u8]>, pri_key: &K,
) -> Result<()> {
    let encoded_pri_keys = bcs::to_bytes(pri_key)?;
    let pri_key_info =
        PrivateKeyInfo::new(algorithm_identifier(), encoded_pri_keys.as_ref());
    let encrypted =
        pri_key_info.encrypt(StdRng::from_rng(OsRng).unwrap(), passwd)?;
    encrypted.write_der_file(path)?;
    Ok(())
}

/// Load `passwd` encrypted private key from `path`.
pub fn load_pri_key<'de, P: AsRef<Path>, K: DeserializeOwned>(
    path: P, passwd: impl AsRef<[u8]>,
) -> Result<K> {
    let encrypted = EncryptedPrivateKeyDocument::read_der_file(path)
        .map_err(|e| anyhow!("read file with error {}", e))?;
    let encoded_keys = encrypted
        .decrypt(passwd)
        .map_err(|e| anyhow!("decrypt with error {}", e))?;
    Ok(bcs::from_bytes(
        encoded_keys.private_key_info().private_key,
    )?)
}