prople_did_core/account/
mod.rs1use 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}