Skip to content

Commit df845a4

Browse files
committed
Add key retrieval methods to FileDecryptionProperties
1 parent 1314cd1 commit df845a4

File tree

3 files changed

+71
-28
lines changed

3 files changed

+71
-28
lines changed

parquet/src/encryption/decrypt.rs

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::encryption::ciphers::{BlockDecryptor, RingGcmBlockDecryptor};
1919
use crate::encryption::modules::{create_module_aad, ModuleType};
2020
use crate::errors::{ParquetError, Result};
2121
use crate::file::column_crypto_metadata::ColumnCryptoMetaData;
22+
use std::borrow::Cow;
2223
use std::collections::HashMap;
2324
use std::fmt::Formatter;
2425
use std::io::Read;
@@ -204,6 +205,39 @@ impl FileDecryptionProperties {
204205
pub fn with_key_retriever(key_retriever: Arc<dyn KeyRetriever>) -> DecryptionPropertiesBuilder {
205206
DecryptionPropertiesBuilder::new_with_key_retriever(key_retriever)
206207
}
208+
209+
/// Get the encryption key for decrypting a file's footer,
210+
/// and also column data if uniform encryption is used.
211+
pub(crate) fn footer_key(&self, key_metadata: Option<&[u8]>) -> Result<Cow<Vec<u8>>> {
212+
match &self.keys {
213+
DecryptionKeys::Explicit(keys) => Ok(Cow::Borrowed(&keys.footer_key)),
214+
DecryptionKeys::ViaRetriever(retriever) => {
215+
let key = retriever.retrieve_key(key_metadata.unwrap_or_default())?;
216+
Ok(Cow::Owned(key))
217+
}
218+
}
219+
}
220+
221+
/// Get the column-specific encryption key for decrypting column data and metadata within a file
222+
pub(crate) fn column_key(
223+
&self,
224+
column_name: &str,
225+
key_metadata: Option<&[u8]>,
226+
) -> Result<Cow<Vec<u8>>> {
227+
match &self.keys {
228+
DecryptionKeys::Explicit(keys) => match keys.column_keys.get(column_name) {
229+
None => Err(general_err!(
230+
"No column decryption key set for column '{}'",
231+
column_name
232+
)),
233+
Some(key) => Ok(Cow::Borrowed(key)),
234+
},
235+
DecryptionKeys::ViaRetriever(retriever) => {
236+
let key = retriever.retrieve_key(key_metadata.unwrap_or_default())?;
237+
Ok(Cow::Owned(key))
238+
}
239+
}
240+
}
207241
}
208242

209243
impl std::fmt::Debug for FileDecryptionProperties {
@@ -307,14 +341,8 @@ impl FileDecryptor {
307341
aad_prefix: Vec<u8>,
308342
) -> Result<Self> {
309343
let file_aad = [aad_prefix.as_slice(), aad_file_unique.as_slice()].concat();
310-
let footer_decryptor = match &decryption_properties.keys {
311-
DecryptionKeys::Explicit(keys) => RingGcmBlockDecryptor::new(&keys.footer_key),
312-
DecryptionKeys::ViaRetriever(retriever) => {
313-
let footer_key = retriever.retrieve_key(footer_key_metadata.unwrap_or_default())?;
314-
RingGcmBlockDecryptor::new(&footer_key)
315-
}
316-
};
317-
let footer_decryptor = footer_decryptor.map_err(|e| {
344+
let footer_key = decryption_properties.footer_key(footer_key_metadata)?;
345+
let footer_decryptor = RingGcmBlockDecryptor::new(&footer_key).map_err(|e| {
318346
general_err!(
319347
"Invalid footer key. {}",
320348
e.to_string().replace("Parquet error: ", "")
@@ -337,16 +365,10 @@ impl FileDecryptor {
337365
column_name: &str,
338366
key_metadata: Option<&[u8]>,
339367
) -> Result<Arc<dyn BlockDecryptor>> {
340-
match &self.decryption_properties.keys {
341-
DecryptionKeys::Explicit(keys) => match keys.column_keys.get(column_name) {
342-
Some(column_key) => Ok(Arc::new(RingGcmBlockDecryptor::new(column_key)?)),
343-
None => self.get_footer_decryptor(),
344-
},
345-
DecryptionKeys::ViaRetriever(retriever) => {
346-
let key = retriever.retrieve_key(key_metadata.unwrap_or_default())?;
347-
Ok(Arc::new(RingGcmBlockDecryptor::new(&key)?))
348-
}
349-
}
368+
let column_key = self
369+
.decryption_properties
370+
.column_key(column_name, key_metadata)?;
371+
Ok(Arc::new(RingGcmBlockDecryptor::new(&column_key)?))
350372
}
351373

352374
pub(crate) fn get_column_metadata_decryptor(

parquet/src/file/metadata/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -680,10 +680,13 @@ impl RowGroupMetaData {
680680
)?;
681681

682682
let buf = c.encrypted_column_metadata.clone().unwrap();
683-
let decrypted_cc_buf =
684-
column_decryptor.decrypt(buf.as_slice(), column_aad.as_ref()).map_err(|_| {
685-
general_err!("Unable to decrypt column '{}', perhaps the column key is wrong or missing?",
686-
d.path().string())
683+
let decrypted_cc_buf = column_decryptor
684+
.decrypt(buf.as_slice(), column_aad.as_ref())
685+
.map_err(|_| {
686+
general_err!(
687+
"Unable to decrypt column '{}', perhaps the column key is wrong?",
688+
d.path().string()
689+
)
687690
})?;
688691

689692
let mut prot = TCompactSliceInputProtocol::new(decrypted_cc_buf.as_slice());

parquet/tests/arrow_reader/encryption_async.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,14 @@ async fn test_misspecified_encryption_keys() {
115115
.await;
116116

117117
// Missing column key
118-
check_for_error("Parquet error: Unable to decrypt column 'double_field', perhaps the column key is wrong or missing?",
119-
&path, footer_key, "".as_bytes(), column_2_key).await;
118+
check_for_error(
119+
"Parquet error: No column decryption key set for column 'double_field'",
120+
&path,
121+
footer_key,
122+
"".as_bytes(),
123+
column_2_key,
124+
)
125+
.await;
120126

121127
// Too short column key
122128
check_for_error(
@@ -129,12 +135,24 @@ async fn test_misspecified_encryption_keys() {
129135
.await;
130136

131137
// Wrong column key
132-
check_for_error("Parquet error: Unable to decrypt column 'double_field', perhaps the column key is wrong or missing?",
133-
&path, footer_key, "1123456789012345".as_bytes(), column_2_key).await;
138+
check_for_error(
139+
"Parquet error: Unable to decrypt column 'double_field', perhaps the column key is wrong?",
140+
&path,
141+
footer_key,
142+
"1123456789012345".as_bytes(),
143+
column_2_key,
144+
)
145+
.await;
134146

135147
// Mixed up keys
136-
check_for_error("Parquet error: Unable to decrypt column 'float_field', perhaps the column key is wrong or missing?",
137-
&path, footer_key, column_2_key, column_1_key).await;
148+
check_for_error(
149+
"Parquet error: Unable to decrypt column 'float_field', perhaps the column key is wrong?",
150+
&path,
151+
footer_key,
152+
column_2_key,
153+
column_1_key,
154+
)
155+
.await;
138156
}
139157

140158
#[tokio::test]

0 commit comments

Comments
 (0)