1use chacha::KeyStream;
2use crate::{util,ArxKW,ArxKwError,AuthTag,ConstantTimeEq};
3
4pub struct EX {}
8impl EX {
9 #[cfg(not(tarpaulin_include))]
11 #[must_use] pub const fn key_length() -> usize {
12 48
13 }
14}
15
16impl ArxKW for EX {
17 type Key = [u8; Self::key_length()];
18 fn encrypt(key: &Self::Key, plaintext: &[u8]) -> Result<(Vec<u8>, AuthTag), ArxKwError> {
19 let (k1, k2) = array_refs![key,16,32];
20 let authentication_tag = util::sip_array_keyed(k1, plaintext);
21 let nonce = construct_nonce(&authentication_tag);
22 let mut stream = util::xchacha8::new(k2,&nonce);
23 let mut ciphertext = plaintext.to_vec();
24 stream.xor_read(&mut ciphertext).map_err(|e| ArxKwError::ChaChaError(format!("Reached end of stream: {:?} X",e)))?;
25 Ok((ciphertext,authentication_tag))
26 }
27
28 fn decrypt(key: &Self::Key, ciphertext: &[u8], authentication_tag: &AuthTag) -> Result<Vec<u8>, ArxKwError> {
29 let (k1,k2) = array_refs![key,16,32];
30 let nonce = construct_nonce(authentication_tag);
31 let mut p_prime = ciphertext.to_vec();
32 let mut stream = util::xchacha8::new(k2,&nonce);
33 stream.xor_read(&mut p_prime).map_err(|e| ArxKwError::ChaChaError(format!("Reached end of stream: {:?} X",e)))?;
34 let t_prime = util::sip_array_keyed(k1, &p_prime);
35 if bool::from(t_prime.ct_eq(authentication_tag)) {
36 return Ok(p_prime);
37 }
38 Err(ArxKwError::BadTags(t_prime, *authentication_tag))
39 }
40}
41
42const NONCE_INIT_EX: [u8;24] = [0x61, 0x72, 0x62, 0x69, 0x74, 0x72, 0x45, 0x58,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
44
45#[must_use]
99#[inline]
100#[cfg(not(tarpaulin_include))]
101pub fn construct_nonce(authentication_tag: &AuthTag) -> [u8;24] {
102 let mut nonce = NONCE_INIT_EX;
104 nonce[8..24].clone_from_slice(authentication_tag.as_ref());
106 nonce
107}
108
109
110#[cfg(test)]
111mod tests {
112 extern crate hex;
113 use super::*;
114 use anyhow::Result;
115 use hex::FromHex;
116 use crate::{assert_ct_eq,ConstantTimeEq};
117
118 #[test]
119 fn test_encrypt() -> Result<()> {
120 let k = <[u8; 48]>::from_hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f")?;
121 let p = <[u8; 32]>::from_hex("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")?;
122 let t_expected = AuthTag(<[u8; 16]>::from_hex("c4f21d3b4dbcc566c3a73bbc59790f2f")?);
123 let c_expected = <[u8; 32]>::from_hex("02a55ab1d7f549db160e8ecb33e1c6d65a05d0ebaba54dc0712285787c8a62db")?;
124 let (c,t) = EX::encrypt(array_ref![k,0,48], &p)?;
125 assert_eq!(&c.to_vec(), &c_expected);
126 assert_ct_eq!(&t, &t_expected);
127 Ok(())
128 }
129
130 #[test]
131 fn test_encrypt_blob() -> Result<()> {
132 let k = <[u8; 48]>::from_hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f")?;
133 let p = <[u8; 32]>::from_hex("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")?;
134 let blob_expected = <[u8;48]>::from_hex("c4f21d3b4dbcc566c3a73bbc59790f2f02a55ab1d7f549db160e8ecb33e1c6d65a05d0ebaba54dc0712285787c8a62db")?;
135 let blob = EX::encrypt_blob(&k, &p)?;
136 assert_ct_eq!(blob, &blob_expected);
137 Ok(())
138 }
139
140 #[test]
141 fn test_decrypt_blob() -> Result<()> {
142 let blob = <[u8;48]>::from_hex("c4f21d3b4dbcc566c3a73bbc59790f2f02a55ab1d7f549db160e8ecb33e1c6d65a05d0ebaba54dc0712285787c8a62db")?;
143 let k = <[u8; 48]>::from_hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f")?;
144 let p_expected = <[u8; 32]>::from_hex("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")?;
145 let p = EX::decrypt_blob(&k, &blob)?;
146 assert_ct_eq!(p, &p_expected);
147 Ok(())
148 }
149
150 #[test]
151 fn test_decrypt() -> Result<()> {
152 let k = <[u8; 48]>::from_hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f")?;
153 let p_expected = <[u8; 32]>::from_hex("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")?;
154 let t = AuthTag(<[u8; 16]>::from_hex("c4f21d3b4dbcc566c3a73bbc59790f2f")?);
155 let c = <[u8; 32]>::from_hex("02a55ab1d7f549db160e8ecb33e1c6d65a05d0ebaba54dc0712285787c8a62db")?;
156 let p = EX::decrypt(&k, &c, &t)?;
157 assert_eq!(p, p_expected);
158 Ok(())
159 }
160
161 #[test]
162 fn test_bad_decrypt() -> Result<()> {
164 let k = <[u8; 48]>::from_hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f")?;
165 let t_bad = AuthTag(<[u8; 16]>::from_hex("aaf21d3b4dbcc566c3a73bbc59790f2f")?); let c = <[u8; 32]>::from_hex("02a55ab1d7f549db160e8ecb33e1c6d65a05d0ebaba54dc0712285787c8a62db")?;
167 let res = EX::decrypt(&k, &c, &t_bad);
168 assert!(res.is_err());
169 Ok(())
170 }
171}