prople_did_core/account/
mod.rs

1//! `account` is main module used to generate an [`Account`]
2//!
3//! The generated account will depends on `EdDSA` generated keypairs
4//! and used data is the public key
5use prople_crypto::passphrase::types::SaltBytes;
6use prople_crypto::types::VectorValue;
7use rst_common::with_cryptography::hex;
8use rst_common::with_errors::thiserror::{self, Error};
9
10use prople_crypto::aead::{Key, KeyEncryption, KeyNonce, MessageCipher, AEAD};
11use prople_crypto::keysecure::KeySecure;
12
13use prople_crypto::eddsa::keypair::KeyPair;
14use prople_crypto::eddsa::privkey::PrivKey;
15use prople_crypto::eddsa::pubkey::PubKey;
16use prople_crypto::eddsa::signature::Signature;
17
18use prople_crypto::passphrase::kdf_params::KdfParams;
19use prople_crypto::passphrase::Passphrase;
20
21#[derive(Debug, PartialEq, Error)]
22pub enum AccountError {
23    #[error("unable to decode: {0}")]
24    DecodeError(String),
25
26    #[error("unable to parse: {0}")]
27    ParseHexError(String),
28
29    #[error("invalid public key: {0}")]
30    InvalidPublicKey(String),
31
32    #[error("encode pem failed: {0}")]
33    EncodePEMError(String),
34
35    #[error("decode pem failed: {0}")]
36    DecodePEMError(String),
37}
38
39#[derive(Debug, Clone)]
40pub struct Account {
41    pair: KeyPair,
42}
43
44impl Default for Account {
45    fn default() -> Self {
46        Self::new()
47    }
48}
49
50impl Account {
51    pub fn new() -> Self {
52        let keypair = KeyPair::generate();
53        Self { pair: keypair }
54    }
55
56    pub fn build_pem(&self) -> Result<String, AccountError> {
57        self.pair
58            .priv_key()
59            .to_pem()
60            .map_err(|err| AccountError::EncodePEMError(err.to_string()))
61    }
62
63    pub fn from_pem(val: String) -> Result<Self, AccountError> {
64        let account = KeyPair::from_pem(val)
65            .map(|val| Self { pair: val })
66            .map_err(|err| AccountError::DecodePEMError(err.to_string()))?;
67
68        Ok(account)
69    }
70
71    pub fn from_keysecure(password: String, keysecure: KeySecure) -> Result<Self, AccountError> {
72        let encrypted_text = keysecure.crypto.cipher_text;
73        let decoded_encrypted_text = hex::decode(encrypted_text)
74            .map_err(|err| AccountError::DecodeError(err.to_string()))?;
75
76        let kdf_params = keysecure.crypto.kdf_params;
77        let passphrase_kdf_params = KdfParams {
78            m_cost: kdf_params.params.m_cost,
79            p_cost: kdf_params.params.p_cost,
80            t_cost: kdf_params.params.t_cost,
81            output_len: kdf_params.params.output_len,
82        };
83
84        let kdf = Passphrase::new(passphrase_kdf_params);
85        let salt_vec = kdf_params.salt.as_bytes().to_vec();
86        let kdf_hash = kdf
87            .hash(password, SaltBytes::from(salt_vec.clone()))
88            .map_err(|err| AccountError::DecodeError(err.to_string()))?;
89
90        let nonce = keysecure.crypto.cipher_params.nonce;
91        let nonce_decoded =
92            hex::decode(nonce).map_err(|err| AccountError::DecodeError(err.to_string()))?;
93
94        let nonce_value: [u8; 24] = nonce_decoded
95            .clone()
96            .try_into()
97            .map_err(|_| AccountError::DecodeError("unable to decode nonce".to_string()))?;
98
99        let key = Key::new(KeyEncryption::from(kdf_hash), KeyNonce::from(nonce_value));
100        let decrypted = AEAD::decrypt(&key, &MessageCipher::from(decoded_encrypted_text))
101            .map_err(|err| AccountError::DecodeError(err.to_string()))?;
102
103        let to_pem = String::from_utf8(decrypted.vec())
104            .map_err(|err| AccountError::DecodeError(err.to_string()))?;
105
106        Account::from_pem(to_pem)
107    }
108
109    pub fn pubkey(&self) -> PubKey {
110        self.pair.pub_key()
111    }
112
113    pub fn privkey(&self) -> PrivKey {
114        self.pair.priv_key()
115    }
116
117    pub fn signature(&self, message: &[u8]) -> Signature {
118        self.pair.signature(message)
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use prople_crypto::keysecure::types::{Password, ToKeySecure};
125
126    use super::*;
127
128    #[test]
129    fn test_generate_build_pem() {
130        let account = Account::new();
131        let account_pem = account.build_pem();
132        assert!(!account_pem.is_err());
133        assert!(!account_pem.unwrap().is_empty())
134    }
135
136    #[test]
137    fn test_parse_account_from_encoded() {
138        let account = Account::new();
139        let account_pem = account.build_pem();
140        let account_rebuild = Account::from_pem(account_pem.unwrap());
141        assert!(!account_rebuild.is_err());
142
143        let account_rebuild_pubkey = account_rebuild.unwrap().pubkey();
144        assert_eq!(
145            account_rebuild_pubkey.serialize(),
146            account.pubkey().serialize()
147        )
148    }
149
150    #[test]
151    fn test_parse_account_error_invalid_input() {
152        let account = Account::from_pem(String::from("invalid"));
153        assert!(account.is_err());
154        assert!(matches!(account, Err(AccountError::DecodePEMError(_))))
155    }
156
157    #[test]
158    fn test_build_from_keysecure() {
159        let account = Account::new();
160        let try_pem = account.privkey().to_pem();
161        assert!(!try_pem.is_err());
162
163        let original_pem = try_pem.unwrap();
164        let try_keysecure = account
165            .privkey()
166            .to_keysecure(Password::from("password".to_string()));
167        assert!(!try_keysecure.is_err());
168
169        let keysecure = try_keysecure.unwrap();
170        let try_rebuild_account = Account::from_keysecure("password".to_string(), keysecure);
171        assert!(!try_rebuild_account.is_err());
172
173        let rebuild_account = try_rebuild_account.unwrap();
174        let rebuild_account_pem = rebuild_account.privkey().to_pem().unwrap();
175        assert_eq!(rebuild_account_pem, original_pem)
176    }
177
178    #[test]
179    fn test_build_from_keysecure_invalid_password() {
180        let account = Account::new();
181        let try_keysecure = account
182            .privkey()
183            .to_keysecure(Password::from("password".to_string()));
184        assert!(!try_keysecure.is_err());
185
186        let keysecure = try_keysecure.unwrap();
187        let try_rebuild_account = Account::from_keysecure("invalid".to_string(), keysecure);
188        assert!(try_rebuild_account.is_err());
189    }
190}