metamorphic_crypto/
keys.rs1use crypto_box::SecretKey;
4use zeroize::Zeroize;
5
6use crate::CryptoError;
7use crate::b64;
8use crate::secretbox::{decrypt_secretbox_to_string, encrypt_secretbox_string};
9
10const KEY_LEN: usize = 32;
12const SALT_LEN: usize = 16;
14
15#[derive(Debug, Clone)]
17pub struct KeyPair {
18 pub public_key: String,
20 pub private_key: String,
22}
23
24#[inline]
26fn random_bytes(buf: &mut [u8]) {
27 getrandom::getrandom(buf).expect("OS CSPRNG unavailable");
28}
29
30pub fn generate_key() -> String {
34 let mut key = [0u8; KEY_LEN];
35 random_bytes(&mut key);
36 let encoded = b64::encode(&key);
37 key.zeroize();
38 encoded
39}
40
41pub fn generate_keypair() -> KeyPair {
43 let mut sk_bytes = [0u8; KEY_LEN];
44 random_bytes(&mut sk_bytes);
45 let sk = SecretKey::from_slice(&sk_bytes).expect("valid 32-byte key");
46 let pk = sk.public_key();
47
48 let kp = KeyPair {
49 public_key: b64::encode(pk.as_bytes()),
50 private_key: b64::encode(&sk_bytes),
51 };
52 sk_bytes.zeroize();
53 kp
54}
55
56pub fn generate_salt() -> String {
58 let mut salt = [0u8; SALT_LEN];
59 random_bytes(&mut salt);
60 b64::encode(&salt)
61}
62
63pub fn encrypt_private_key(
68 private_key_b64: &str,
69 session_key_b64: &str,
70) -> Result<String, CryptoError> {
71 encrypt_secretbox_string(private_key_b64, session_key_b64)
72}
73
74pub fn decrypt_private_key(ct_b64: &str, session_key_b64: &str) -> Result<String, CryptoError> {
76 decrypt_secretbox_to_string(ct_b64, session_key_b64)
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn key_is_32_bytes() {
85 let key = generate_key();
86 assert_eq!(b64::decode(&key).unwrap().len(), 32);
87 }
88
89 #[test]
90 fn keys_are_unique() {
91 assert_ne!(generate_key(), generate_key());
92 }
93
94 #[test]
95 fn keypair_sizes() {
96 let kp = generate_keypair();
97 assert_eq!(b64::decode(&kp.public_key).unwrap().len(), 32);
98 assert_eq!(b64::decode(&kp.private_key).unwrap().len(), 32);
99 }
100
101 #[test]
102 fn salt_is_16_bytes() {
103 assert_eq!(b64::decode(&generate_salt()).unwrap().len(), 16);
104 }
105
106 #[test]
107 fn private_key_encrypt_decrypt() {
108 let kp = generate_keypair();
109 let session_key = generate_key();
110 let ct = encrypt_private_key(&kp.private_key, &session_key).unwrap();
111 let pt = decrypt_private_key(&ct, &session_key).unwrap();
112 assert_eq!(pt, kp.private_key);
113 }
114
115 #[test]
116 fn private_key_wrong_session_key() {
117 let kp = generate_keypair();
118 let k1 = generate_key();
119 let k2 = generate_key();
120 let ct = encrypt_private_key(&kp.private_key, &k1).unwrap();
121 assert!(decrypt_private_key(&ct, &k2).is_err());
122 }
123}