keyplace/keys/
private.rs

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// dalek::Keypair already derives Zeroize
16#[derive(Debug, Serialize, Deserialize)]
17pub struct AgentKey {
18    pub keypair: Keypair,
19    pub email: Option<String>,
20}
21
22// impl Eq for AgentKey{
23//     fn assert_receiver_is_total_eq(&self) {}
24// }
25impl 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        // TODO 2 - Reconcile differences between the above
38        // and the old code removed from minbase core (below)
39        // let mut csprng: OsRng = OsRng::new().unwrap();
40        // let keypair: Keypair = Keypair::generate::<Sha512>(&mut csprng);
41
42        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        // use std::convert::TryInto;
68
69        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        // Consume the PassKey to discourage the implementer from storing it
83
84        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        // Consume the PassKey to discourage the implementer from storing it
93
94        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// DO NOT ALLOW SERIALIZATION
121#[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, &params, &mut dk).expect("32 bytes always satisfy output length requirements");
133
134        PassKey { c: dk }
135    }
136    // Use this to authenticate with the server
137    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, &params, &mut auth).expect("32 bytes always satisfy output length requirements");
143
144        UserAuthKey { auth }
145    }
146}