1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use super::IndCpaCipher;
use tink_core::{utils::wrap_err, TinkError};
pub struct EncryptThenAuthenticate {
ind_cpa_cipher: Box<dyn IndCpaCipher>,
mac: Box<dyn tink_core::Mac>,
tag_size: usize,
}
impl Clone for EncryptThenAuthenticate {
fn clone(&self) -> Self {
Self {
ind_cpa_cipher: self.ind_cpa_cipher.box_clone(),
mac: self.mac.box_clone(),
tag_size: self.tag_size,
}
}
}
const MIN_TAG_SIZE_IN_BYTES: usize = 10;
impl EncryptThenAuthenticate {
pub fn new(
ind_cpa_cipher: Box<dyn IndCpaCipher>,
mac: Box<dyn tink_core::Mac>,
tag_size: usize,
) -> Result<EncryptThenAuthenticate, TinkError> {
if tag_size < MIN_TAG_SIZE_IN_BYTES {
return Err("EncryptThenAuthenticate: tag size too small".into());
}
Ok(EncryptThenAuthenticate {
ind_cpa_cipher,
mac,
tag_size,
})
}
}
impl tink_core::Aead for EncryptThenAuthenticate {
fn encrypt(&self, plaintext: &[u8], additional_data: &[u8]) -> Result<Vec<u8>, TinkError> {
let mut ciphertext = self
.ind_cpa_cipher
.encrypt(plaintext)
.map_err(|e| wrap_err("EncryptThenAuthenticate", e))?;
let mut to_auth_data = Vec::with_capacity(additional_data.len() + ciphertext.len() + 8);
to_auth_data.extend_from_slice(additional_data);
to_auth_data.extend_from_slice(&ciphertext);
let aad_size_in_bits = (additional_data.len() * 8) as u64;
to_auth_data.extend_from_slice(&aad_size_in_bits.to_be_bytes());
let tag = self
.mac
.compute_mac(&to_auth_data)
.map_err(|e| wrap_err("EncryptThenAuthenticate", e))?;
if tag.len() != self.tag_size {
return Err("EncryptThenAuthenticate: invalid tag size".into());
}
ciphertext.extend_from_slice(&tag);
Ok(ciphertext)
}
fn decrypt(&self, ciphertext: &[u8], additional_data: &[u8]) -> Result<Vec<u8>, TinkError> {
if ciphertext.len() < self.tag_size {
return Err("EncryptThenAuthenticate: ciphertext too short".into());
}
let payload = &ciphertext[..(ciphertext.len() - self.tag_size)];
let mut to_auth_data = Vec::with_capacity(additional_data.len() + payload.len() + 8);
to_auth_data.extend_from_slice(additional_data);
to_auth_data.extend_from_slice(payload);
let aad_size_in_bits = (additional_data.len() * 8) as u64;
to_auth_data.extend_from_slice(&aad_size_in_bits.to_be_bytes());
self.mac
.verify_mac(
&ciphertext[(ciphertext.len() - self.tag_size)..],
&to_auth_data,
)
.map_err(|e| wrap_err("EncryptThenAuthenticate", e))?;
let plaintext = self
.ind_cpa_cipher
.decrypt(payload)
.map_err(|e| wrap_err("EncryptThenAuthenticate", e))?;
Ok(plaintext)
}
}