1use std::fmt;
22
23use aes_gcm::aead::OsRng;
24use aes_gcm::aead::rand_core::RngCore;
25
26use super::{AesKeySize, SecureKey};
27use crate::{Error, ErrorKind, Result};
28
29#[derive(Clone, PartialEq, Eq)]
37pub struct StandardKeyMetadata {
38 encryption_key: SecureKey,
39 aad_prefix: Option<Box<[u8]>>,
40 file_length: Option<u64>,
41}
42
43impl fmt::Debug for StandardKeyMetadata {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 f.debug_struct("StandardKeyMetadata")
46 .field("encryption_key", &self.encryption_key)
47 .field(
48 "aad_prefix",
49 &self
50 .aad_prefix
51 .as_ref()
52 .map(|b| format!("[{} bytes]", b.len())),
53 )
54 .field("file_length", &self.file_length)
55 .finish()
56 }
57}
58
59impl StandardKeyMetadata {
60 pub fn try_new(encryption_key: &[u8]) -> Result<Self> {
62 Ok(Self::from(SecureKey::new(encryption_key)?))
63 }
64
65 pub(crate) fn generate(key_size: AesKeySize) -> Self {
68 Self::from(SecureKey::generate(key_size)).with_aad_prefix(&generate_aad_prefix())
69 }
70
71 pub fn with_aad_prefix(mut self, aad_prefix: &[u8]) -> Self {
73 self.aad_prefix = Some(aad_prefix.into());
74 self
75 }
76
77 pub fn with_file_length(mut self, length: u64) -> Self {
79 self.file_length = Some(length);
80 self
81 }
82
83 pub fn encryption_key(&self) -> &SecureKey {
85 &self.encryption_key
86 }
87
88 pub fn aad_prefix(&self) -> Option<&[u8]> {
90 self.aad_prefix.as_deref()
91 }
92
93 pub fn file_length(&self) -> Option<u64> {
95 self.file_length
96 }
97
98 pub fn encode(&self) -> Result<Box<[u8]>> {
100 _serde::StandardKeyMetadataV1::from(self).encode()
101 }
102
103 pub fn decode(bytes: &[u8]) -> Result<Self> {
105 _serde::StandardKeyMetadataV1::decode(bytes).and_then(Self::try_from)
106 }
107}
108
109impl From<SecureKey> for StandardKeyMetadata {
110 fn from(encryption_key: SecureKey) -> Self {
112 Self {
113 encryption_key,
114 aad_prefix: None,
115 file_length: None,
116 }
117 }
118}
119
120const AAD_PREFIX_LENGTH: usize = 16;
122
123fn generate_aad_prefix() -> Box<[u8]> {
124 let mut prefix = vec![0u8; AAD_PREFIX_LENGTH];
125 OsRng.fill_bytes(&mut prefix);
126 prefix.into_boxed_slice()
127}
128
129mod _serde {
130 use std::io::Cursor;
131 use std::sync::{Arc, LazyLock};
132
133 use apache_avro::{Schema as AvroSchema, from_avro_datum, from_value, to_avro_datum, to_value};
134 use serde::{Deserialize, Serialize};
135
136 use super::*;
137 use crate::avro::schema_to_avro_schema;
138 use crate::spec::{NestedField, PrimitiveType, Schema, Type};
139
140 pub(super) const V1: u8 = 1;
141
142 pub(super) static AVRO_SCHEMA_V1: LazyLock<AvroSchema> = LazyLock::new(|| {
144 let schema = Schema::builder()
145 .with_fields(vec![
146 Arc::new(NestedField::required(
147 0,
148 "encryption_key",
149 Type::Primitive(PrimitiveType::Binary),
150 )),
151 Arc::new(NestedField::optional(
152 1,
153 "aad_prefix",
154 Type::Primitive(PrimitiveType::Binary),
155 )),
156 Arc::new(NestedField::optional(
157 2,
158 "file_length",
159 Type::Primitive(PrimitiveType::Long),
160 )),
161 ])
162 .build()
163 .expect("Failed to build StandardKeyMetadata Iceberg schema");
164
165 schema_to_avro_schema("StandardKeyMetadata", &schema)
166 .expect("Failed to convert StandardKeyMetadata to Avro schema")
167 });
168
169 #[derive(Serialize, Deserialize)]
172 pub(super) struct StandardKeyMetadataV1 {
173 pub encryption_key: serde_bytes::ByteBuf,
174 pub aad_prefix: Option<serde_bytes::ByteBuf>,
175 pub file_length: Option<u64>,
176 }
177
178 impl StandardKeyMetadataV1 {
179 pub(super) fn encode(&self) -> Result<Box<[u8]>> {
180 let value = to_value(self)
181 .and_then(|v| v.resolve(&AVRO_SCHEMA_V1))
182 .map_err(|e| {
183 Error::new(ErrorKind::Unexpected, "Failed to encode key metadata")
184 .with_source(e)
185 })?;
186
187 let datum = to_avro_datum(&AVRO_SCHEMA_V1, value).map_err(|e| {
188 Error::new(ErrorKind::Unexpected, "Failed to encode key metadata").with_source(e)
189 })?;
190
191 let mut result = Vec::with_capacity(1 + datum.len());
192 result.push(V1);
193 result.extend_from_slice(&datum);
194 Ok(result.into_boxed_slice())
195 }
196
197 pub(super) fn decode(bytes: &[u8]) -> Result<Self> {
198 if bytes.is_empty() {
199 return Err(Error::new(
200 ErrorKind::DataInvalid,
201 "Empty key metadata buffer",
202 ));
203 }
204
205 let version = bytes[0];
206 if version != V1 {
207 return Err(Error::new(
208 ErrorKind::FeatureUnsupported,
209 format!("Cannot resolve schema for version: {version}"),
210 ));
211 }
212
213 let mut reader = Cursor::new(&bytes[1..]);
214 let value = from_avro_datum(&AVRO_SCHEMA_V1, &mut reader, None).map_err(|e| {
215 Error::new(ErrorKind::DataInvalid, "Failed to decode key metadata").with_source(e)
216 })?;
217
218 from_value(&value).map_err(|e| {
219 Error::new(
220 ErrorKind::DataInvalid,
221 "Failed to decode key metadata fields",
222 )
223 .with_source(e)
224 })
225 }
226 }
227
228 impl From<&StandardKeyMetadata> for StandardKeyMetadataV1 {
229 fn from(metadata: &StandardKeyMetadata) -> Self {
230 Self {
231 encryption_key: serde_bytes::ByteBuf::from(metadata.encryption_key.as_bytes()),
232 aad_prefix: metadata
233 .aad_prefix
234 .as_ref()
235 .map(|b| serde_bytes::ByteBuf::from(b.as_ref())),
236 file_length: metadata.file_length,
237 }
238 }
239 }
240
241 impl TryFrom<StandardKeyMetadataV1> for StandardKeyMetadata {
242 type Error = Error;
243
244 fn try_from(v1: StandardKeyMetadataV1) -> Result<Self> {
245 let encryption_key = SecureKey::new(&v1.encryption_key).map_err(|e| {
246 Error::new(
247 ErrorKind::DataInvalid,
248 "Invalid encryption key in key metadata",
249 )
250 .with_source(e)
251 })?;
252 Ok(Self {
253 encryption_key,
254 aad_prefix: v1.aad_prefix.map(|b| b.into_vec().into_boxed_slice()),
255 file_length: v1.file_length,
256 })
257 }
258 }
259}
260
261#[cfg(test)]
262mod tests {
263 use super::*;
264
265 #[test]
266 fn test_roundtrip() {
267 let key = b"0123456789012345";
268 let aad = b"1234567890123456";
269
270 let metadata = StandardKeyMetadata::try_new(key)
271 .unwrap()
272 .with_aad_prefix(aad);
273 let serialized = metadata.encode().unwrap();
274 let parsed = StandardKeyMetadata::decode(&serialized).unwrap();
275
276 assert_eq!(parsed.encryption_key().as_bytes(), key);
277 assert_eq!(parsed.aad_prefix(), Some(aad.as_slice()));
278 assert_eq!(parsed.file_length(), None);
279 }
280
281 #[test]
282 fn test_roundtrip_with_length() {
283 let key = b"0123456789012345";
284 let aad = b"1234567890123456";
285
286 let file_length = 100_000;
287 let metadata = StandardKeyMetadata::try_new(key)
288 .unwrap()
289 .with_aad_prefix(aad)
290 .with_file_length(file_length);
291 let serialized = metadata.encode().unwrap();
292 let parsed = StandardKeyMetadata::decode(&serialized).unwrap();
293
294 assert_eq!(parsed.encryption_key().as_bytes(), key);
295 assert_eq!(parsed.aad_prefix(), Some(aad.as_slice()));
296 assert_eq!(parsed.file_length(), Some(file_length));
297 }
298
299 #[test]
300 fn test_unsupported_version() {
301 let result = StandardKeyMetadata::decode(&[0x02]);
302 assert!(result.is_err());
303 let err = result.unwrap_err();
304 assert_eq!(err.kind(), ErrorKind::FeatureUnsupported);
305 }
306
307 #[test]
308 fn test_empty_buffer() {
309 let result = StandardKeyMetadata::decode(&[]);
310 assert!(result.is_err());
311 assert_eq!(result.unwrap_err().kind(), ErrorKind::DataInvalid);
312 }
313
314 #[test]
315 fn test_roundtrip_without_aad() {
316 let key = b"0123456789012345";
317 let metadata = StandardKeyMetadata::try_new(key).unwrap();
318 let serialized = metadata.encode().unwrap();
319 let parsed = StandardKeyMetadata::decode(&serialized).unwrap();
320
321 assert_eq!(parsed.encryption_key().as_bytes(), key);
322 assert_eq!(parsed.aad_prefix(), None);
323 }
324
325 #[test]
326 fn test_new_rejects_invalid_key_length() {
327 for len in [16usize, 24, 32] {
329 assert!(StandardKeyMetadata::try_new(&vec![0u8; len]).is_ok());
330 }
331
332 for len in [0usize, 4, 15, 20, 33] {
335 assert!(StandardKeyMetadata::try_new(&vec![0u8; len]).is_err());
336 }
337 }
338
339 #[test]
340 fn test_decode_rejects_invalid_key_length() {
341 for len in [0usize, 4, 15, 20, 33] {
345 let serialized = _serde::StandardKeyMetadataV1 {
346 encryption_key: serde_bytes::ByteBuf::from(vec![0u8; len]),
347 aad_prefix: None,
348 file_length: None,
349 }
350 .encode()
351 .unwrap();
352
353 let err = StandardKeyMetadata::decode(&serialized).unwrap_err();
354 assert_eq!(err.kind(), ErrorKind::DataInvalid);
355 assert!(
356 err.to_string()
357 .contains("Invalid encryption key in key metadata")
358 );
359 }
360 }
361}