|
18 | 18 | //! Encryption implementation specific to Parquet, as described
|
19 | 19 | //! in the [spec](https://github.com/apache/parquet-format/blob/master/Encryption.md).
|
20 | 20 |
|
21 |
| -use ring::aead::{Aad, LessSafeKey, UnboundKey, AES_128_GCM}; |
22 |
| -use std::collections::HashMap; |
23 | 21 | use std::sync::Arc;
|
24 | 22 | use crate::errors::{ParquetError, Result};
|
25 |
| - |
26 |
| -pub trait BlockDecryptor { |
27 |
| - fn decrypt(&self, length_and_ciphertext: &[u8], aad: &[u8]) -> Result<Vec<u8>>; |
28 |
| -} |
29 |
| - |
30 |
| -const NONCE_LEN: usize = 12; |
31 |
| -const TAG_LEN: usize = 16; |
32 |
| -const SIZE_LEN: usize = 4; |
33 |
| - |
34 |
| - |
35 |
| -#[derive(Debug, Clone)] |
36 |
| -pub(crate) struct RingGcmBlockDecryptor { |
37 |
| - key: LessSafeKey, |
38 |
| -} |
39 |
| - |
40 |
| -impl RingGcmBlockDecryptor { |
41 |
| - pub(crate) fn new(key_bytes: &[u8]) -> Self { |
42 |
| - // todo support other key sizes |
43 |
| - let key = UnboundKey::new(&AES_128_GCM, key_bytes).unwrap(); |
44 |
| - |
45 |
| - Self { |
46 |
| - key: LessSafeKey::new(key), |
47 |
| - } |
48 |
| - } |
49 |
| -} |
50 |
| - |
51 |
| -impl BlockDecryptor for RingGcmBlockDecryptor { |
52 |
| - fn decrypt(&self, length_and_ciphertext: &[u8], aad: &[u8]) -> Result<Vec<u8>> { |
53 |
| - let mut result = |
54 |
| - Vec::with_capacity(length_and_ciphertext.len() - SIZE_LEN - NONCE_LEN - TAG_LEN); |
55 |
| - result.extend_from_slice(&length_and_ciphertext[SIZE_LEN + NONCE_LEN..]); |
56 |
| - |
57 |
| - let nonce = ring::aead::Nonce::try_assume_unique_for_key( |
58 |
| - &length_and_ciphertext[SIZE_LEN..SIZE_LEN + NONCE_LEN], |
59 |
| - )?; |
60 |
| - |
61 |
| - self.key.open_in_place(nonce, Aad::from(aad), &mut result)?; |
62 |
| - |
63 |
| - // Truncate result to remove the tag |
64 |
| - result.resize(result.len() - TAG_LEN, 0u8); |
65 |
| - Ok(result) |
66 |
| - } |
67 |
| -} |
| 23 | +use crate::encryption::decryption::FileDecryptor; |
68 | 24 |
|
69 | 25 | #[derive(PartialEq)]
|
70 | 26 | pub(crate) enum ModuleType {
|
@@ -158,167 +114,6 @@ fn create_module_aad(
|
158 | 114 | Ok(aad)
|
159 | 115 | }
|
160 | 116 |
|
161 |
| -#[derive(Debug, Clone, PartialEq)] |
162 |
| -pub struct FileDecryptionProperties { |
163 |
| - footer_key: Option<Vec<u8>>, |
164 |
| - column_keys: Option<HashMap<Vec<u8>, Vec<u8>>>, |
165 |
| - aad_prefix: Option<Vec<u8>>, |
166 |
| -} |
167 |
| - |
168 |
| -impl FileDecryptionProperties { |
169 |
| - pub fn builder() -> DecryptionPropertiesBuilder { |
170 |
| - DecryptionPropertiesBuilder::with_defaults() |
171 |
| - } |
172 |
| - pub fn has_footer_key(&self) -> bool { |
173 |
| - self.footer_key.is_some() |
174 |
| - } |
175 |
| - |
176 |
| - pub fn has_column_keys(&self) -> bool { |
177 |
| - self.column_keys.is_some() |
178 |
| - } |
179 |
| - |
180 |
| - pub fn aad_prefix(&self) -> Option<Vec<u8>> { |
181 |
| - self.aad_prefix.clone() |
182 |
| - } |
183 |
| -} |
184 |
| - |
185 |
| -pub struct DecryptionPropertiesBuilder { |
186 |
| - footer_key: Option<Vec<u8>>, |
187 |
| - column_keys: Option<HashMap<Vec<u8>, Vec<u8>>>, |
188 |
| - aad_prefix: Option<Vec<u8>>, |
189 |
| -} |
190 |
| - |
191 |
| -impl DecryptionPropertiesBuilder { |
192 |
| - pub fn with_defaults() -> Self { |
193 |
| - Self { |
194 |
| - footer_key: None, |
195 |
| - column_keys: None, |
196 |
| - aad_prefix: None, |
197 |
| - } |
198 |
| - } |
199 |
| - |
200 |
| - pub fn build(self) -> FileDecryptionProperties { |
201 |
| - FileDecryptionProperties { |
202 |
| - footer_key: self.footer_key, |
203 |
| - column_keys: self.column_keys, |
204 |
| - aad_prefix: self.aad_prefix, |
205 |
| - } |
206 |
| - } |
207 |
| - |
208 |
| - // todo decr: doc comment |
209 |
| - pub fn with_footer_key(mut self, value: Vec<u8>) -> Self { |
210 |
| - self.footer_key = Some(value); |
211 |
| - self |
212 |
| - } |
213 |
| - |
214 |
| - pub fn with_aad_prefix(mut self, value: Vec<u8>) -> Self { |
215 |
| - self.aad_prefix = Some(value); |
216 |
| - self |
217 |
| - } |
218 |
| - |
219 |
| - pub fn with_column_key(mut self, key: Vec<u8>, value: Vec<u8>) -> Self { |
220 |
| - let mut column_keys = self.column_keys.unwrap_or_default(); |
221 |
| - column_keys.insert(key, value); |
222 |
| - self.column_keys = Some(column_keys); |
223 |
| - self |
224 |
| - } |
225 |
| -} |
226 |
| - |
227 |
| -#[derive(Debug, Clone)] |
228 |
| -pub struct FileDecryptor { |
229 |
| - decryption_properties: FileDecryptionProperties, |
230 |
| - // todo decr: change to BlockDecryptor |
231 |
| - footer_decryptor: Option<RingGcmBlockDecryptor>, |
232 |
| - aad_file_unique: Vec<u8>, |
233 |
| - aad_prefix: Vec<u8>, |
234 |
| -} |
235 |
| - |
236 |
| -impl PartialEq for FileDecryptor { |
237 |
| - fn eq(&self, other: &Self) -> bool { |
238 |
| - self.decryption_properties == other.decryption_properties |
239 |
| - } |
240 |
| -} |
241 |
| - |
242 |
| -impl FileDecryptor { |
243 |
| - pub(crate) fn new( |
244 |
| - decryption_properties: &FileDecryptionProperties, |
245 |
| - aad_file_unique: Vec<u8>, |
246 |
| - aad_prefix: Vec<u8>, |
247 |
| - ) -> Self { |
248 |
| - let footer_decryptor = decryption_properties |
249 |
| - .footer_key |
250 |
| - .clone() |
251 |
| - .map(|footer_key| RingGcmBlockDecryptor::new(footer_key.as_ref())); |
252 |
| - |
253 |
| - Self { |
254 |
| - // todo decr: if no key available yet (not set in properties, will be retrieved from metadata) |
255 |
| - footer_decryptor, |
256 |
| - decryption_properties: decryption_properties.clone(), |
257 |
| - aad_file_unique, |
258 |
| - aad_prefix, |
259 |
| - } |
260 |
| - } |
261 |
| - |
262 |
| - // todo decr: change to BlockDecryptor |
263 |
| - pub(crate) fn get_footer_decryptor(self) -> RingGcmBlockDecryptor { |
264 |
| - self.footer_decryptor.unwrap() |
265 |
| - } |
266 |
| - |
267 |
| - pub(crate) fn has_column_key(&self, column_name: &[u8]) -> bool { |
268 |
| - self.decryption_properties |
269 |
| - .column_keys |
270 |
| - .clone() |
271 |
| - .unwrap() |
272 |
| - .contains_key(column_name) |
273 |
| - } |
274 |
| - |
275 |
| - pub(crate) fn get_column_decryptor(&self, column_name: &[u8]) -> FileDecryptor { |
276 |
| - if self.decryption_properties.column_keys.is_none() || !self.has_column_key(column_name) { |
277 |
| - return self.clone(); |
278 |
| - } |
279 |
| - let column_keys = &self.decryption_properties.column_keys.clone().unwrap(); |
280 |
| - let decryption_properties = if let Some(column_key) = column_keys.get(column_name) { |
281 |
| - DecryptionPropertiesBuilder::with_defaults() |
282 |
| - .with_footer_key(column_key.clone()) |
283 |
| - .with_aad_prefix(self.aad_prefix.clone()) |
284 |
| - .build() |
285 |
| - } else { |
286 |
| - self.decryption_properties.clone() |
287 |
| - }; |
288 |
| - |
289 |
| - FileDecryptor::new( |
290 |
| - &decryption_properties, |
291 |
| - self.aad_file_unique.clone(), |
292 |
| - self.aad_prefix.clone(), |
293 |
| - ) |
294 |
| - } |
295 |
| - |
296 |
| - pub(crate) fn decryption_properties(&self) -> &FileDecryptionProperties { |
297 |
| - &self.decryption_properties |
298 |
| - } |
299 |
| - |
300 |
| - pub(crate) fn footer_decryptor(&self) -> Option<RingGcmBlockDecryptor> { |
301 |
| - self.footer_decryptor.clone() |
302 |
| - } |
303 |
| - |
304 |
| - pub(crate) fn aad_file_unique(&self) -> &Vec<u8> { |
305 |
| - &self.aad_file_unique |
306 |
| - } |
307 |
| - |
308 |
| - pub(crate) fn aad_prefix(&self) -> &Vec<u8> { |
309 |
| - &self.aad_prefix |
310 |
| - } |
311 |
| - |
312 |
| - pub(crate) fn has_footer_key(&self) -> bool { |
313 |
| - self.decryption_properties.has_footer_key() |
314 |
| - } |
315 |
| - |
316 |
| - pub(crate) fn is_column_encrypted(&self, column_name: &[u8]) -> bool { |
317 |
| - // Column is encrypted if either uniform encryption is used or an encryption key is set for the column |
318 |
| - self.decryption_properties.column_keys.is_none() || self.has_column_key(column_name) |
319 |
| - } |
320 |
| -} |
321 |
| - |
322 | 117 | #[derive(Debug, Clone)]
|
323 | 118 | pub struct CryptoContext {
|
324 | 119 | pub(crate) row_group_ordinal: usize,
|
|
0 commit comments