parquet/encryption/
ciphers.rs1use crate::errors::ParquetError;
19use crate::errors::ParquetError::General;
20use crate::errors::Result;
21use ring::aead::{Aad, LessSafeKey, NonceSequence, UnboundKey, AES_128_GCM};
22use ring::rand::{SecureRandom, SystemRandom};
23use std::fmt::Debug;
24
25const RIGHT_TWELVE: u128 = 0x0000_0000_ffff_ffff_ffff_ffff_ffff_ffff;
26const NONCE_LEN: usize = 12;
27const TAG_LEN: usize = 16;
28const SIZE_LEN: usize = 4;
29
30pub(crate) trait BlockDecryptor: Debug + Send + Sync {
31 fn decrypt(&self, length_and_ciphertext: &[u8], aad: &[u8]) -> Result<Vec<u8>>;
32}
33
34#[derive(Debug, Clone)]
35pub(crate) struct RingGcmBlockDecryptor {
36 key: LessSafeKey,
37}
38
39impl RingGcmBlockDecryptor {
40 pub(crate) fn new(key_bytes: &[u8]) -> Result<Self> {
41 let key = UnboundKey::new(&AES_128_GCM, key_bytes)
43 .map_err(|_| General("Failed to create AES key".to_string()))?;
44
45 Ok(Self {
46 key: LessSafeKey::new(key),
47 })
48 }
49}
50
51impl BlockDecryptor for RingGcmBlockDecryptor {
52 fn decrypt(&self, length_and_ciphertext: &[u8], aad: &[u8]) -> Result<Vec<u8>> {
53 let mut result = Vec::with_capacity(length_and_ciphertext.len() - SIZE_LEN - NONCE_LEN);
54 result.extend_from_slice(&length_and_ciphertext[SIZE_LEN + NONCE_LEN..]);
55
56 let nonce = ring::aead::Nonce::try_assume_unique_for_key(
57 &length_and_ciphertext[SIZE_LEN..SIZE_LEN + NONCE_LEN],
58 )?;
59
60 self.key.open_in_place(nonce, Aad::from(aad), &mut result)?;
61
62 result.resize(result.len() - TAG_LEN, 0u8);
64 Ok(result)
65 }
66}
67
68pub(crate) trait BlockEncryptor: Debug + Send + Sync {
69 fn encrypt(&mut self, plaintext: &[u8], aad: &[u8]) -> Result<Vec<u8>>;
70}
71
72#[derive(Debug, Clone)]
73struct CounterNonce {
74 start: u128,
75 counter: u128,
76}
77
78impl CounterNonce {
79 pub fn new(rng: &SystemRandom) -> Result<Self> {
80 let mut buf = [0; 16];
81 rng.fill(&mut buf)?;
82
83 let start = u128::from_ne_bytes(buf) & RIGHT_TWELVE;
86 let counter = start.wrapping_add(1);
87
88 Ok(Self { start, counter })
89 }
90
91 #[inline]
93 pub fn get_bytes(&self) -> [u8; NONCE_LEN] {
94 self.counter.to_le_bytes()[0..NONCE_LEN].try_into().unwrap()
95 }
96}
97
98impl NonceSequence for CounterNonce {
99 fn advance(&mut self) -> Result<ring::aead::Nonce, ring::error::Unspecified> {
100 if (self.counter & RIGHT_TWELVE) == (self.start & RIGHT_TWELVE) {
102 Err(ring::error::Unspecified)
103 } else {
104 let buf: [u8; NONCE_LEN] = self.get_bytes();
106 self.counter = self.counter.wrapping_add(1);
107 Ok(ring::aead::Nonce::assume_unique_for_key(buf))
108 }
109 }
110}
111
112#[derive(Debug, Clone)]
113pub(crate) struct RingGcmBlockEncryptor {
114 key: LessSafeKey,
115 nonce_sequence: CounterNonce,
116}
117
118impl RingGcmBlockEncryptor {
119 pub(crate) fn new(key_bytes: &[u8]) -> Result<Self> {
123 let rng = SystemRandom::new();
124
125 let key = UnboundKey::new(&AES_128_GCM, key_bytes)
127 .map_err(|e| general_err!("Error creating AES key: {}", e))?;
128 let nonce = CounterNonce::new(&rng)?;
129
130 Ok(Self {
131 key: LessSafeKey::new(key),
132 nonce_sequence: nonce,
133 })
134 }
135}
136
137impl BlockEncryptor for RingGcmBlockEncryptor {
138 fn encrypt(&mut self, plaintext: &[u8], aad: &[u8]) -> Result<Vec<u8>> {
139 let ciphertext_length: u32 = (NONCE_LEN + plaintext.len() + TAG_LEN)
142 .try_into()
143 .map_err(|err| General(format!("Plaintext data too long. {:?}", err)))?;
144 let mut ciphertext = Vec::with_capacity(SIZE_LEN + ciphertext_length as usize);
146 ciphertext.extend((ciphertext_length).to_le_bytes());
147
148 let nonce = self.nonce_sequence.advance()?;
149 ciphertext.extend(nonce.as_ref());
150 ciphertext.extend(plaintext);
151
152 let tag = self.key.seal_in_place_separate_tag(
153 nonce,
154 Aad::from(aad),
155 &mut ciphertext[SIZE_LEN + NONCE_LEN..],
156 )?;
157
158 ciphertext.extend(tag.as_ref());
159
160 debug_assert_eq!(SIZE_LEN + ciphertext_length as usize, ciphertext.len());
161
162 Ok(ciphertext)
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn test_round_trip() {
172 let key = [0u8; 16];
173 let mut encryptor = RingGcmBlockEncryptor::new(&key).unwrap();
174 let decryptor = RingGcmBlockDecryptor::new(&key).unwrap();
175
176 let plaintext = b"hello, world!";
177 let aad = b"some aad";
178
179 let ciphertext = encryptor.encrypt(plaintext, aad).unwrap();
180 let decrypted = decryptor.decrypt(&ciphertext, aad).unwrap();
181
182 assert_eq!(plaintext, decrypted.as_slice());
183 }
184}