Skip to content

Commit 27f4112

Browse files
committed
file_decryptor into a seperate module
1 parent 669df5e commit 27f4112

File tree

7 files changed

+244
-218
lines changed

7 files changed

+244
-218
lines changed

parquet/src/arrow/arrow_reader/mod.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ use crate::arrow::array_reader::{build_array_reader, ArrayReader};
3232
use crate::arrow::schema::{parquet_to_arrow_schema_and_fields, ParquetField};
3333
use crate::arrow::{parquet_to_arrow_field_levels, FieldLevels, ProjectionMask};
3434
use crate::column::page::{PageIterator, PageReader};
35+
#[cfg(feature = "encryption")]
36+
use crate::encryption::{ciphers::CryptoContext, decryption::FileDecryptionProperties};
3537
use crate::errors::{ParquetError, Result};
3638
use crate::file::metadata::{ParquetMetaData, ParquetMetaDataReader};
3739
use crate::file::reader::{ChunkReader, SerializedPageReader};
@@ -41,9 +43,6 @@ mod filter;
4143
mod selection;
4244
pub mod statistics;
4345

44-
#[cfg(feature = "encryption")]
45-
use crate::encryption::ciphers::{CryptoContext, FileDecryptionProperties};
46-
4746
/// Builder for constructing parquet readers into arrow.
4847
///
4948
/// Most users should use one of the following specializations:
@@ -1047,7 +1046,7 @@ mod tests {
10471046
FloatType, Int32Type, Int64Type, Int96Type,
10481047
};
10491048
#[cfg(feature = "encryption")]
1050-
use crate::encryption::ciphers;
1049+
use crate::encryption::decryption::FileDecryptionProperties;
10511050
use crate::errors::Result;
10521051
use crate::file::properties::{EnabledStatistics, WriterProperties, WriterVersion};
10531052
use crate::file::writer::SerializedFileWriter;
@@ -1891,7 +1890,7 @@ mod tests {
18911890
let column_1_key = "1234567890123450".as_bytes();
18921891
let column_2_key = "1234567890123451".as_bytes();
18931892

1894-
let decryption_properties = ciphers::FileDecryptionProperties::builder()
1893+
let decryption_properties = FileDecryptionProperties::builder()
18951894
.with_column_key("double_field".as_bytes().to_vec(), column_1_key.to_vec())
18961895
.with_column_key("float_field".as_bytes().to_vec(), column_2_key.to_vec())
18971896
.build();
@@ -1910,7 +1909,7 @@ mod tests {
19101909
let column_1_key = "1234567890123450".as_bytes();
19111910
let column_2_key = "1234567890123451".as_bytes();
19121911

1913-
let decryption_properties = ciphers::FileDecryptionProperties::builder()
1912+
let decryption_properties = FileDecryptionProperties::builder()
19141913
.with_footer_key(footer_key.to_vec())
19151914
.with_column_key("double_field".as_bytes().to_vec(), column_1_key.to_vec())
19161915
.with_column_key("float_field".as_bytes().to_vec(), column_2_key.to_vec())
@@ -1927,7 +1926,7 @@ mod tests {
19271926
let file = File::open(path).unwrap();
19281927

19291928
let key_code: &[u8] = "0123456789012345".as_bytes();
1930-
let decryption_properties = ciphers::FileDecryptionProperties::builder()
1929+
let decryption_properties = FileDecryptionProperties::builder()
19311930
.with_footer_key(key_code.to_vec())
19321931
.build();
19331932

@@ -1937,7 +1936,7 @@ mod tests {
19371936
#[cfg(feature = "encryption")]
19381937
fn verify_encryption_test_file_read(
19391938
file: File,
1940-
decryption_properties: ciphers::FileDecryptionProperties,
1939+
decryption_properties: FileDecryptionProperties,
19411940
) {
19421941
let decryption_properties = Some(decryption_properties);
19431942

parquet/src/encryption/ciphers.rs

Lines changed: 1 addition & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -18,53 +18,9 @@
1818
//! Encryption implementation specific to Parquet, as described
1919
//! in the [spec](https://github.com/apache/parquet-format/blob/master/Encryption.md).
2020
21-
use ring::aead::{Aad, LessSafeKey, UnboundKey, AES_128_GCM};
22-
use std::collections::HashMap;
2321
use std::sync::Arc;
2422
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;
6824

6925
#[derive(PartialEq)]
7026
pub(crate) enum ModuleType {
@@ -158,167 +114,6 @@ fn create_module_aad(
158114
Ok(aad)
159115
}
160116

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-
322117
#[derive(Debug, Clone)]
323118
pub struct CryptoContext {
324119
pub(crate) row_group_ordinal: usize,

0 commit comments

Comments
 (0)