nomad_protocol/crypto/
keys.rs1use crate::core::{PRIVATE_KEY_SIZE, PUBLIC_KEY_SIZE, SESSION_ID_SIZE};
6use rand::{rngs::OsRng, RngCore};
7use x25519_dalek::{PublicKey, StaticSecret};
8use zeroize::Zeroize;
9
10#[derive(Clone)]
14pub struct StaticKeypair {
15 private: [u8; PRIVATE_KEY_SIZE],
17 public: [u8; PUBLIC_KEY_SIZE],
19}
20
21impl StaticKeypair {
22 pub fn generate() -> Self {
24 let builder = snow::Builder::new("Noise_IK_25519_ChaChaPoly_BLAKE2s".parse().unwrap());
26 let keypair = builder.generate_keypair().unwrap();
27
28 let mut private_key = [0u8; PRIVATE_KEY_SIZE];
29 let mut public_key = [0u8; PUBLIC_KEY_SIZE];
30 private_key.copy_from_slice(&keypair.private);
31 public_key.copy_from_slice(&keypair.public);
32
33 Self {
34 private: private_key,
35 public: public_key,
36 }
37 }
38
39 pub fn from_bytes(private: [u8; PRIVATE_KEY_SIZE], public: [u8; PUBLIC_KEY_SIZE]) -> Self {
44 Self { private, public }
45 }
46
47 pub fn public_key(&self) -> &[u8; PUBLIC_KEY_SIZE] {
49 &self.public
50 }
51
52 pub fn private_key(&self) -> &[u8; PRIVATE_KEY_SIZE] {
57 &self.private
58 }
59
60 pub fn compute_static_dh(&self, remote_public: &[u8; PUBLIC_KEY_SIZE]) -> [u8; 32] {
71 let secret = StaticSecret::from(self.private);
72 let public = PublicKey::from(*remote_public);
73 let shared = secret.diffie_hellman(&public);
74 *shared.as_bytes()
75 }
76}
77
78impl Drop for StaticKeypair {
79 fn drop(&mut self) {
80 self.private.zeroize();
81 }
82}
83
84#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
86pub struct SessionId(pub [u8; SESSION_ID_SIZE]);
87
88impl SessionId {
89 pub fn generate() -> Self {
91 let mut id = [0u8; SESSION_ID_SIZE];
92 OsRng.fill_bytes(&mut id);
93 Self(id)
94 }
95
96 pub fn from_bytes(bytes: [u8; SESSION_ID_SIZE]) -> Self {
98 Self(bytes)
99 }
100
101 pub fn as_bytes(&self) -> &[u8; SESSION_ID_SIZE] {
103 &self.0
104 }
105}
106
107impl AsRef<[u8]> for SessionId {
108 fn as_ref(&self) -> &[u8] {
109 &self.0
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn test_keypair_generation() {
119 let kp1 = StaticKeypair::generate();
120 let kp2 = StaticKeypair::generate();
121
122 assert_ne!(kp1.public_key(), kp2.public_key());
124 assert_ne!(kp1.private_key(), kp2.private_key());
125
126 assert_eq!(kp1.public_key().len(), PUBLIC_KEY_SIZE);
128 assert_eq!(kp1.private_key().len(), PRIVATE_KEY_SIZE);
129 }
130
131 #[test]
132 fn test_session_id_generation() {
133 let id1 = SessionId::generate();
134 let id2 = SessionId::generate();
135
136 assert_ne!(id1, id2);
138 assert_eq!(id1.as_bytes().len(), SESSION_ID_SIZE);
139 }
140
141 #[test]
142 fn test_session_id_from_bytes() {
143 let bytes = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06];
144 let id = SessionId::from_bytes(bytes);
145 assert_eq!(id.as_bytes(), &bytes);
146 }
147}