1extern crate rand;
3use std::error;
4
5use chacha20poly1305::aead::Aead;
7use chacha20poly1305::{ChaCha20Poly1305, KeyInit, Nonce};
8use thiserror::Error;
11
12use rand::RngCore;
13use rand::{rngs::OsRng, Rng};
14use x25519_dalek::x25519;
15#[derive(Error, Debug)]
19pub enum EncryptError {
20 #[error("encryption failed")]
23 EncryptionFailure,
24}
25pub fn x25519_base(a: [u8; 32]) -> [u8; 32] {
26 return x25519(a, x25519_dalek::X25519_BASEPOINT_BYTES);
27}
28
29pub fn encrypt(
30 public_key: &[u8; 32],
31 message: &[u8],
32 mut rng: impl Rng,
33) -> Result<Vec<u8>, EncryptError> {
34 let mut ephemeral_secret_key = [0u8; 32];
37 rng.fill_bytes(&mut ephemeral_secret_key[..]);
38
39 let ephemeral_public_key: [u8; 32] = x25519_base(ephemeral_secret_key);
40 let symmetric_key = x25519_dalek::x25519(ephemeral_secret_key, *public_key);
41
42 let mut c = ChaCha20Poly1305::new_from_slice(&symmetric_key).unwrap();
43
44 let mut output = vec![0; 32 + 16];
45 let mut tag: [u8; 16] = rng.gen();
46 output.append(
47 &mut c
48 .encrypt(&Nonce::from_slice(&tag[..12]), message)
49 .map_err(|_| EncryptError::EncryptionFailure)?,
50 );
51 for (dest, src) in (&mut output[0..32])
54 .iter_mut()
55 .zip(ephemeral_public_key.iter())
56 {
57 *dest = *src;
58 }
59
60 for (dest, src) in (&mut output[32..48]).iter_mut().zip(tag.iter()) {
61 *dest = *src;
62 }
63
64 Ok(output)
65}
66#[derive(Error, Debug)]
67pub enum DecryptError {
68 #[error("malformed input")]
69 Malformed,
70 #[error("invalid input")]
71 Invalid,
72}
73
74pub fn decrypt(secret_key: &[u8; 32], message: &[u8]) -> Result<Vec<u8>, DecryptError> {
75 if message.len() < 48 {
76 return Err(DecryptError::Malformed);
77 }
78
79 let ephemeral_public_key = (&message[0..32]).try_into().unwrap();
80 let tag = &message[32..48];
81 let ciphertext = &message[48..];
82
83 let mut plaintext = vec![0; ciphertext.len()];
84 let symmetric_key = x25519(*secret_key, ephemeral_public_key);
85
86 let mut decrypter = ChaCha20Poly1305::new_from_slice(&symmetric_key).unwrap();
87 return decrypter
93 .decrypt(&Nonce::from_slice(&tag[..12]), ciphertext)
94 .map_err(|e| DecryptError::Invalid);
95}