1use crate::AgentId;
2
3use super::{
4 custodian::{CustodialAgentKey, KeyMask, UserAuthKey},
5 AgentIdentity,
6};
7use ed25519_dalek::Keypair;
8use hmac::{Hmac, Mac, NewMac};
9use rand::rngs::OsRng;
10use scrypt::{scrypt, ScryptParams};
11use serde::{Deserialize, Serialize};
12use sha2::Sha512Trunc256;
13use zeroize::Zeroize;
14
15#[derive(Debug, Serialize, Deserialize)]
17pub struct AgentKey {
18 pub keypair: Keypair,
19 pub email: Option<String>,
20}
21
22impl PartialEq for AgentKey {
26 fn eq(&self, other: &Self) -> bool {
27 self.keypair.secret.as_bytes().eq(other.keypair.secret.as_bytes())
28 && self.keypair.public.as_bytes().eq(other.keypair.public.as_bytes())
29 }
30}
31
32impl AgentKey {
33 pub fn create(email: Option<String>) -> AgentKey {
34 let mut csprng = OsRng {};
35 let keypair = Keypair::generate(&mut csprng);
36
37 AgentKey { keypair, email }
43 }
44 pub fn hmac(&self) -> [u8; 32] {
45 let mut mac = Hmac::<Sha512Trunc256>::new_varkey(b"agentkey").unwrap();
46 mac.update(self.keypair.secret.as_bytes());
47 mac.update(self.keypair.public.as_bytes());
48 let result = mac.finalize();
49
50 result.into_bytes().into()
51 }
52 pub fn id(&self) -> AgentId {
53 let pubkey = self.keypair.public.as_bytes().clone();
54 AgentId { pubkey }
55 }
56 pub fn identity(&self) -> AgentIdentity {
57 let pubkey = self.keypair.public.as_bytes().clone();
58 AgentIdentity {
59 pubkey,
60 email: self.email.clone(),
61 }
62 }
63 pub fn pubkey(&self) -> [u8; 32] {
64 self.keypair.public.as_bytes().clone()
65 }
66 pub fn keymask(&self, passkey: &PassKey) -> KeyMask {
67 let mut mask = [0u8; 32];
70
71 self.keypair
72 .secret
73 .as_bytes()
74 .iter()
75 .zip(passkey.c.iter())
76 .enumerate()
77 .for_each(|(i, (bk, bc))| mask[i] = bk ^ bc);
78
79 KeyMask { mask }
80 }
81 pub fn custodial_key(&self, passkey: PassKey) -> CustodialAgentKey {
82 CustodialAgentKey {
85 pubkey: self.keypair.public.as_bytes().clone(),
86 mask: self.keymask(&passkey),
87 check: self.hmac(),
88 email: self.email.clone(),
89 }
90 }
91 pub fn from_custodial_key(custodial_key: CustodialAgentKey, passkey: PassKey) -> Result<Self, crate::Error> {
92 let mut secret = [0u8; 32];
95
96 custodial_key
97 .mask
98 .as_bytes()
99 .iter()
100 .zip(passkey.c.iter())
101 .enumerate()
102 .for_each(|(i, (m, p))| secret[i] = m ^ p);
103
104 let mut mac = Hmac::<Sha512Trunc256>::new_varkey(b"agentkey").unwrap();
105 mac.update(&secret);
106 mac.update(&custodial_key.pubkey);
107
108 mac.verify(&custodial_key.check)?;
109
110 Ok(Self {
111 keypair: Keypair {
112 secret: ed25519_dalek::SecretKey::from_bytes(&secret)?,
113 public: ed25519_dalek::PublicKey::from_bytes(&custodial_key.pubkey)?,
114 },
115 email: custodial_key.email.clone(),
116 })
117 }
118}
119
120#[derive(Zeroize)]
122#[zeroize(drop)]
123pub struct PassKey {
124 c: [u8; 32],
125}
126
127impl PassKey {
128 pub fn new(passphrase: &str) -> PassKey {
129 let salt = b"mindbase passkey";
130 let params = ScryptParams::recommended();
131 let mut dk = [0u8; 32];
132 scrypt(passphrase.as_bytes(), salt, ¶ms, &mut dk).expect("32 bytes always satisfy output length requirements");
133
134 PassKey { c: dk }
135 }
136 pub fn auth(&self) -> UserAuthKey {
138 let salt = b"mindbase authkey";
139 let params = ScryptParams::recommended();
140
141 let mut auth = [0u8; 32];
142 scrypt(&self.c, salt, ¶ms, &mut auth).expect("32 bytes always satisfy output length requirements");
143
144 UserAuthKey { auth }
145 }
146}