Skip to main content

voltlane_enc/
lib.rs

1use chacha20poly1305::{
2    aead::{Aead, OsRng},
3    AeadCore, KeyInit, XChaCha20Poly1305, XNonce,
4};
5
6const APP_SALT: &[u8] = b"VOLTLANE.NET";
7
8pub fn generate_keypair() -> (
9    k256::ecdh::EphemeralSecret, /* private key */
10    k256::EncodedPoint,          /* public key */
11) {
12    let private_key = k256::ecdh::EphemeralSecret::random(&mut OsRng);
13    let public_key = k256::EncodedPoint::from(private_key.public_key());
14    (private_key, public_key)
15}
16
17pub fn generate_shared_secret(
18    their_pubkey: &k256::PublicKey,
19    my_privkey: &k256::ecdh::EphemeralSecret,
20) -> k256::ecdh::SharedSecret {
21    my_privkey.diffie_hellman(their_pubkey)
22}
23
24pub fn encrypt(key: &k256::ecdh::SharedSecret, data: Vec<u8>) -> Vec<u8> {
25    let hkdf = key.extract::<k256::sha2::Sha256>(Some(APP_SALT));
26    let mut okm = [0u8; 32];
27    hkdf.expand(APP_SALT, &mut okm).unwrap();
28    let cipher = XChaCha20Poly1305::new(&okm.into());
29    let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
30    let mut result = cipher.encrypt(&nonce, data.as_ref()).unwrap();
31    result.extend_from_slice(&nonce);
32    result
33}
34
35pub fn decrypt(
36    key: &k256::ecdh::SharedSecret,
37    data: Vec<u8>,
38) -> Result<Vec<u8>, chacha20poly1305::Error> {
39    let hkdf = key.extract::<k256::sha2::Sha256>(Some(APP_SALT));
40    let mut okm = [0u8; 32];
41    hkdf.expand(APP_SALT, &mut okm).unwrap();
42    let cipher = XChaCha20Poly1305::new(&okm.into());
43    // 192 bit for the nonce
44    let (msg, nonce) = data.split_at(data.len() - 24);
45    let nonce = XNonce::from_slice(&nonce);
46    cipher.decrypt(nonce, msg)
47}
48
49pub fn pubkey_from_bytes(bytes: &[u8]) -> k256::PublicKey {
50    k256::PublicKey::from_sec1_bytes(bytes).unwrap()
51}
52
53/// Easy to use API for encryption/decryption
54///
55/// To use this, create a new `Keys` instance, then call `create_encryption`
56/// once you have the other party's public key. This will give you an `Encryption`
57/// instance, which you can use to encrypt and decrypt messages to/from that party.
58pub mod easy {
59    pub fn random_bytes(size: usize) -> Vec<u8> {
60        use chacha20poly1305::aead::OsRng;
61        use k256::elliptic_curve::rand_core::RngCore;
62        let mut bytes = vec![0u8; size];
63        let mut rng = OsRng {};
64        rng.fill_bytes(&mut bytes);
65        bytes
66    }
67
68    pub type PubKey = k256::PublicKey;
69
70    pub fn pubkey_from_bytes(bytes: &[u8]) -> Result<PubKey, k256::elliptic_curve::Error> {
71        k256::PublicKey::from_sec1_bytes(bytes)
72    }
73
74    pub struct Keys {
75        pub pubkey: k256::PublicKey,
76        privkey: k256::ecdh::EphemeralSecret,
77    }
78
79    impl Keys {
80        pub fn new() -> Self {
81            let (privkey, pubkey) = super::generate_keypair();
82            Self {
83                pubkey: k256::PublicKey::from_sec1_bytes(pubkey.as_bytes()).unwrap(),
84                privkey,
85            }
86        }
87
88        /// Create
89        pub fn create_encryption(&self, their_pubkey: &PubKey) -> Encryption {
90            let shared_secret = super::generate_shared_secret(&their_pubkey, &self.privkey);
91            Encryption { shared_secret }
92        }
93
94        pub fn pubkey_to_bytes(&self) -> Vec<u8> {
95            self.pubkey.to_sec1_bytes().to_vec()
96        }
97    }
98
99    pub struct Encryption {
100        shared_secret: k256::ecdh::SharedSecret,
101    }
102
103    impl Encryption {
104        // Hi! there's no ::new! Make one via Keys::into_encryption
105
106        pub fn encrypt(&self, data: Vec<u8>) -> Vec<u8> {
107            super::encrypt(&self.shared_secret, data)
108        }
109
110        pub fn decrypt(&self, data: Vec<u8>) -> Result<Vec<u8>, chacha20poly1305::Error> {
111            super::decrypt(&self.shared_secret, data)
112        }
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn test_encrypt_decrypt() {
122        let (my_privkey, my_pubkey) = generate_keypair();
123        let (their_privkey, their_pubkey) = generate_keypair();
124
125        let their_pubkey = k256::PublicKey::from_sec1_bytes(&their_pubkey.as_bytes()).unwrap();
126
127        let my_shared_secret = generate_shared_secret(&their_pubkey, &my_privkey);
128        let data = b"Hello, world!".to_vec();
129
130        let my_pubkey = k256::PublicKey::from_sec1_bytes(&my_pubkey.as_bytes()).unwrap();
131        let their_shared_secret = generate_shared_secret(&my_pubkey, &their_privkey);
132
133        let encrypted_data = encrypt(&my_shared_secret, data.clone());
134        let decrypted_data = decrypt(&their_shared_secret, encrypted_data.clone()).unwrap();
135
136        assert_eq!(data, decrypted_data);
137    }
138
139    #[test]
140    fn test_easy_encrypt_decrypt() {
141        let keys = easy::Keys::new();
142        let their_keys = easy::Keys::new();
143        let data = b"Hello, world!".to_vec();
144
145        let encryption = keys.create_encryption(&their_keys.pubkey);
146        let encrypted_data = encryption.encrypt(data.clone());
147
148        let their_encryption = their_keys.create_encryption(&keys.pubkey);
149        let decrypted_data = their_encryption.decrypt(encrypted_data).unwrap();
150
151        assert_eq!(data, decrypted_data);
152    }
153}