Open a segment with optional at-rest decryption. - `kek = None` → requires a plaintext (`NDAS`) segment; returns `Err(MissingKek)` if the blob starts with `SEGA`. - `kek = Some(key)` → requires an encrypted (`SEGA`) segment; decrypts the blob, then parses the inner plaintext. Returns `Err(KekRequired)` if the blob starts with `NDAS`.
(
blob: &[u8],
kek: Option<&nodedb_wal::crypto::WalEncryptionKey>,
)
| 313 | /// the blob, then parses the inner plaintext. Returns `Err(KekRequired)` |
| 314 | /// if the blob starts with `NDAS`. |
| 315 | pub fn open_with_kek( |
| 316 | blob: &[u8], |
| 317 | kek: Option<&nodedb_wal::crypto::WalEncryptionKey>, |
| 318 | ) -> ArrayResult<Self> { |
| 319 | use super::encrypt::{decrypt_segment, detect_encryption}; |
| 320 | let is_encrypted = detect_encryption(blob)?; |
| 321 | let plaintext = match (is_encrypted, kek) { |
| 322 | (true, Some(key)) => decrypt_segment(key, blob)?, |
| 323 | (true, None) => return Err(ArrayError::MissingKek), |
| 324 | (false, Some(_)) => return Err(ArrayError::KekRequired), |
| 325 | (false, None) => blob.to_vec(), |
| 326 | }; |
| 327 | let header = SegmentHeader::decode(&plaintext[..HEADER_SIZE.min(plaintext.len())])?; |
| 328 | let footer = SegmentFooter::decode(&plaintext)?; |
| 329 | if header.schema_hash != footer.schema_hash { |
| 330 | return Err(ArrayError::SegmentCorruption { |
| 331 | detail: format!( |
| 332 | "header/footer schema_hash mismatch: header={:x} footer={:x}", |
| 333 | header.schema_hash, footer.schema_hash |
| 334 | ), |
| 335 | }); |
| 336 | } |
| 337 | Ok(Self { |
| 338 | plaintext, |
| 339 | header, |
| 340 | footer, |
| 341 | }) |
| 342 | } |
| 343 | |
| 344 | /// Borrow a `SegmentReader` over the owned plaintext bytes. |
| 345 | pub fn reader(&self) -> SegmentReader<'_> { |
nothing calls this directly
no test coverage detected