oasis_core_runtime/common/crypto/mrae/
deoxysii.rs1use anyhow::Result;
3use hmac::{Hmac, KeyInit, Mac};
4use rand::{rand_core::UnwrapErr, rngs::SysRng};
5use sha2::Sha512_256;
6use x25519_dalek::{PublicKey, StaticSecret};
7
8pub use deoxysii::{DeoxysII, KEY_SIZE, NONCE_SIZE, TAG_SIZE};
9
10type Kdf = Hmac<Sha512_256>;
11
12pub trait Opener: Send + Sync {
14 fn box_open(
16 &self,
17 nonce: &[u8; NONCE_SIZE],
18 ciphertext: Vec<u8>,
19 additional_data: Vec<u8>,
20 peers_public_key: &PublicKey,
21 ) -> Result<Vec<u8>>;
22}
23
24fn derive_symmetric_key(public: &PublicKey, private: &StaticSecret) -> [u8; KEY_SIZE] {
27 let pmk = private.diffie_hellman(public);
28
29 let mut kdf = Kdf::new_from_slice(b"MRAE_Box_Deoxys-II-256-128").expect("Hmac::new_from_slice");
30 kdf.update(pmk.as_bytes());
31 drop(pmk);
32
33 let mut derived_key = [0u8; KEY_SIZE];
34 let digest = kdf.finalize();
35 derived_key.copy_from_slice(&digest.into_bytes()[..KEY_SIZE]);
36
37 derived_key
38}
39
40pub fn generate_key_pair() -> (PublicKey, StaticSecret) {
43 let mut rng = UnwrapErr(SysRng);
44 let sk = StaticSecret::random_from_rng(&mut rng);
45 let pk = PublicKey::from(&sk);
46
47 (pk, sk)
48}
49
50pub fn box_seal(
56 nonce: &[u8; NONCE_SIZE],
57 plaintext: Vec<u8>,
58 additional_data: Vec<u8>,
59 peers_public_key: &PublicKey,
60 private_key: &StaticSecret,
61) -> Result<Vec<u8>> {
62 let key = derive_symmetric_key(peers_public_key, private_key);
63
64 let d2 = DeoxysII::new(&key);
65
66 Ok(d2.seal(nonce, plaintext, additional_data))
67}
68
69pub fn box_open(
75 nonce: &[u8; NONCE_SIZE],
76 ciphertext: Vec<u8>,
77 additional_data: Vec<u8>,
78 peers_public_key: &PublicKey,
79 private_key: &StaticSecret,
80) -> Result<Vec<u8>> {
81 let key = derive_symmetric_key(peers_public_key, private_key);
82
83 let d2 = DeoxysII::new(&key);
84
85 d2.open(nonce, ciphertext, additional_data)
86 .map_err(|err| err.into())
87}
88
89#[cfg(test)]
90mod tests {
91 extern crate test;
92
93 use self::test::{black_box, Bencher};
94 use super::*;
95 use rand::Rng;
96
97 #[test]
98 fn test_mrae_asymmetric() {
99 let (a_pub, a_priv) = generate_key_pair(); let (b_pub, b_priv) = generate_key_pair(); assert_ne!(a_pub.to_bytes(), b_pub.to_bytes());
104 assert_ne!(a_priv.to_bytes(), b_priv.to_bytes());
105 assert_ne!(a_pub.to_bytes(), a_priv.to_bytes());
106 assert_ne!(b_pub.to_bytes(), b_priv.to_bytes());
107
108 let nonce = [1u8; NONCE_SIZE];
110 let text = String::from("This is a test!").as_bytes().to_vec();
111 let aad = vec![42u8; 10];
112
113 let sealed = box_seal(&nonce, text.clone(), aad.clone(), &b_pub, &a_priv);
114 assert!(sealed.is_ok());
115
116 let opened = box_open(&nonce, sealed.unwrap(), aad, &a_pub, &b_priv);
118 assert!(opened.is_ok());
119
120 let deciphered = opened.unwrap();
122 assert_eq!(deciphered, text);
123 }
124
125 #[bench]
126 fn bench_mrae_box_seal_4096(b: &mut Bencher) {
127 let mut rng = rand::rng();
128
129 let (_a_pub, a_priv) = generate_key_pair(); let (b_pub, _b_priv) = generate_key_pair(); let mut nonce = [0u8; NONCE_SIZE];
135 rng.fill_bytes(&mut nonce);
136 let mut text = [0u8; 4096];
137 rng.fill_bytes(&mut text);
138 let mut aad = [0u8; 64];
139 rng.fill_bytes(&mut aad);
140
141 b.iter(|| {
143 let _sealed = black_box(box_seal(
144 &nonce,
145 text.to_vec(),
146 aad.to_vec(),
147 &b_pub,
148 &a_priv,
149 ));
150 });
151 }
152
153 #[bench]
154 fn bench_mrae_box_open_4096(b: &mut Bencher) {
155 let mut rng = rand::rng();
156
157 let (a_pub, a_priv) = generate_key_pair(); let (b_pub, b_priv) = generate_key_pair(); let mut nonce = [0u8; NONCE_SIZE];
163 rng.fill_bytes(&mut nonce);
164 let mut text = [0u8; 4096];
165 rng.fill_bytes(&mut text);
166 let mut aad = [0u8; 64];
167 rng.fill_bytes(&mut aad);
168
169 let sealed = box_seal(&nonce, text.to_vec(), aad.to_vec(), &b_pub, &a_priv);
171 let ciphertext = sealed.unwrap();
172
173 b.iter(|| {
175 let _opened = black_box(box_open(
176 &nonce,
177 ciphertext.clone(),
178 aad.to_vec(),
179 &a_pub,
180 &b_priv,
181 ));
182 });
183 }
184}