1use crate::{
2 generate,
3 util,
4 lqb,
5 ArxKW,
6 ArxKwError,
7 InvalidLengthError,
8 AuthTag,
9 ConstantTimeEq
10};
11
12pub struct G;
15impl G {
16 #[must_use]
18 #[cfg(not(tarpaulin_include))]
19 pub const fn key_length() -> usize {
20 32
21 }
22
23 #[cfg(not(tarpaulin_include))]
31 #[must_use]
32 pub const fn max_input_length() -> usize {
33 64
34 }
35}
36
37
38impl ArxKW for G {
39 type Key = [u8; Self::key_length()];
40 fn encrypt(key: &Self::Key, plaintext: &[u8]) -> Result<(Vec<u8>, AuthTag), ArxKwError> {
41 if plaintext.len() > Self::max_input_length() {
42 Err(ArxKwError::InvalidLength(InvalidLengthError::UpTo(plaintext.len(), Self::max_input_length())))
43 } else {
44 let (k1,k2) = generate::subkeys(key)?;
45 let authentication_tag = util::sip_array_keyed(&k1, plaintext);
46 let ciphertext = lqb::chacha8_encrypt(&k2, authentication_tag.as_ref(), plaintext)?;
47 Ok((ciphertext, authentication_tag))
48 }
49 }
50
51
52 fn decrypt(key: &Self::Key, ciphertext: &[u8], authentication_tag: &AuthTag) -> Result<Vec<u8>, ArxKwError> {
53 if ciphertext.len() > Self::max_input_length() {
54 Err(ArxKwError::InvalidLength(InvalidLengthError::UpTo(ciphertext.len(), Self::max_input_length())))
55 } else {
56 let (k1,k2) = generate::subkeys(key)?;
57 let p_prime = lqb::chacha8_encrypt(&k2, authentication_tag.as_ref(), ciphertext)?;
58 let t_prime = util::sip_array_keyed(&k1, &p_prime);
59 if bool::from(t_prime.ct_eq(authentication_tag)) {
60 return Ok(p_prime);
61 }
62 Err(ArxKwError::BadTags(t_prime, *authentication_tag))
63 }
64 }
65}
66
67
68#[cfg(test)]
69mod tests {
70 use hex::FromHex;
71 use anyhow::Result;
72 use super::{G,ArxKW};
73 use crate::{AuthTag,assert_ct_eq,ConstantTimeEq};
74
75 #[test]
76 fn test_encrypt() -> Result<()> {
77
78 let k = <[u8;32]>::from_hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")?;
79 let p = <[u8;32]>::from_hex("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")?;
80 let p_bad = [0xaf; 69];
81 let res = G::encrypt(&k, &p_bad);
82 assert!(res.is_err());
83 let t_expected = AuthTag(<[u8;16]>::from_hex("016325cf6a3c4b2e3b039675e1ccbc65")?);
84 let c_expected = <[u8;32]>::from_hex("f63830f5148a039b6aacc4b9b6bc281d7704d906e4b5d91e045a62cdfc25eb10")?;
85 let (c,t) = G::encrypt(&k,&p)?;
86 assert_ct_eq!(c, &c_expected);
87 assert_ct_eq!(t, &t_expected);
88 Ok(())
89 }
90
91 #[test]
92 fn test_encrypt_blob() -> Result<()> {
93 let k = <[u8;32]>::from_hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")?;
94 let p = <[u8;32]>::from_hex("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")?;
95 let blob_expected = <[u8;48]>::from_hex("016325cf6a3c4b2e3b039675e1ccbc65f63830f5148a039b6aacc4b9b6bc281d7704d906e4b5d91e045a62cdfc25eb10")?;
96 let blob = G::encrypt_blob(&k, &p)?;
97 assert_ct_eq!(blob_expected, &blob);
98 Ok(())
99 }
100
101 #[test]
102 fn test_decrypt_blob() -> Result<()> {
103 let k = <[u8;32]>::from_hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")?;
104 let p_expected = <[u8;32]>::from_hex("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")?;
105 let blob = <[u8;48]>::from_hex("016325cf6a3c4b2e3b039675e1ccbc65f63830f5148a039b6aacc4b9b6bc281d7704d906e4b5d91e045a62cdfc25eb10")?;
106 let p = G::decrypt_blob(&k, &blob)?;
107 assert_ct_eq!(p, &p_expected);
108 Ok(())
109 }
110
111 #[test]
112 fn test_decrypt() -> Result<()> {
113 let k = <[u8;32]>::from_hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")?;
114 let p_expected = <[u8;32]>::from_hex("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")?;
115 let p_bad = [0xaf; 69];
116 let t_expected = AuthTag(<[u8;16]>::from_hex("016325cf6a3c4b2e3b039675e1ccbc65")?);
117 let res = G::decrypt(&k, &p_bad, &t_expected);
118 assert!(res.is_err());
119 let c = <[u8;32]>::from_hex("f63830f5148a039b6aacc4b9b6bc281d7704d906e4b5d91e045a62cdfc25eb10")?;
120 let p = G::decrypt(&k,&c,&t_expected)?;
121 assert_eq!(p, p_expected);
122 Ok(())
123 }
124
125 #[test]
126 fn test_decrypt_bad() -> Result<()> {
127 let k = <[u8;32]>::from_hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")?;
128 let p_expected = <[u8;32]>::from_hex("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")?;
129 let c = <[u8;32]>::from_hex("f63830f5148a039b6aacc4b9b6bc281d7704d906e4b5d91e045a62cdfc25eb10")?;
130 let c_bad = [0xaf; 69];
131 let t_expected = AuthTag(<[u8;16]>::from_hex("016325cf6a3c4b2e3b039675e1ccbc65")?);
132 let res = G::decrypt(&k, &c_bad, &t_expected);
133 assert!(res.is_err());
134 let p = G::decrypt(&k,&c,&t_expected)?;
135 assert_eq!(p, p_expected);
136 let t_bad = AuthTag(<[u8;16]>::from_hex("dab325cf6a3c4b2e3b039675e1ccbc65")?); let res = G::decrypt(&k, &c, &t_bad);
138 assert!(res.is_err());
139 Ok(())
140 }
141}