ironcore_documents/
lib.rs1pub mod aes;
2mod signing;
3pub mod v3;
4pub mod v4;
5pub mod v5;
6
7use hmac::{Hmac, KeyInit, Mac};
8use sha2::Sha256;
9use std::{
10 fmt::{Display, Formatter, Result as DisplayResult},
11 sync::{Mutex, MutexGuard},
12};
13use thiserror::Error;
14use v5::key_id_header::KEY_ID_HEADER_LEN;
15
16pub(crate) type Result<T> = core::result::Result<T, Error>;
17
18type HmacSha256 = Hmac<Sha256>;
20
21const CRATE_DEBUG_KEY: &str = match option_env!("MY_CRATE_DEBUG_KEY") {
23 Some(val) => val,
24 None => "2025-10-28T17:23:36",
26};
27
28pub fn redacted_hash(data: &[u8]) -> String {
30 let mut mac = HmacSha256::new_from_slice(CRATE_DEBUG_KEY.as_ref())
31 .expect("HMAC can take key of any size");
32 mac.update(data);
33 hex::encode(mac.finalize().into_bytes())[..8].to_string()
35}
36
37include!(concat!(env!("OUT_DIR"), "/mod.rs"));
38
39#[derive(Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
40pub enum Error {
41 EdocTooShort(usize),
43 HeaderParseErr(String),
45 InvalidVersion(u8),
47 NoIronCoreMagic,
49 SpecifiedLengthTooLong(u32),
51 ProtoSerializationErr(String),
53 HeaderLengthOverflow(u64),
55 EncryptError(String),
57 DecryptError(String),
59 EdekTypeError(String),
62 PayloadTypeError(String),
64 KeyIdHeaderTooShort(usize),
66 KeyIdHeaderMalformed(String),
68}
69
70impl Display for Error {
71 fn fmt(&self, f: &mut Formatter) -> DisplayResult {
72 match self {
73 Error::EdocTooShort(x) => write!(f, "EDOC too short. Found {x} bytes."),
74 Error::HeaderParseErr(x) => write!(f, "Header parse error: '{x}'"),
75 Error::InvalidVersion(x) => write!(f, "Invalid EDOC version: {x}"),
76 Error::NoIronCoreMagic => write!(f, "Missing IronCore Magic bytes in header."),
77 Error::SpecifiedLengthTooLong(x) => {
78 write!(f, "Header too short for specified length: {x} bytes")
79 }
80 Error::ProtoSerializationErr(x) => write!(f, "Protobuf serialization error: '{x}'"),
81 Error::HeaderLengthOverflow(x) => write!(f, "Header length too long: {x} bytes"),
82 Error::EncryptError(x) => write!(f, "{x}"),
83 Error::DecryptError(x) => write!(f, "{x}"),
84 Error::KeyIdHeaderTooShort(x) => write!(
85 f,
86 "Key ID header too short. Found: {x} bytes. Required: {KEY_ID_HEADER_LEN} bytes."
87 ),
88 Error::EdekTypeError(x) => write!(f, "EDEK type error: '{x}'"),
89 Error::PayloadTypeError(x) => write!(f, "Payload type error: '{x}'"),
90 Error::KeyIdHeaderMalformed(x) => write!(f, "Malformed key ID header: '{x}'"),
91 }
92 }
93}
94
95pub fn take_lock<T>(m: &Mutex<T>) -> MutexGuard<'_, T> {
114 m.lock().unwrap_or_else(|e| {
115 let error = format!("Error when acquiring lock: {e}");
116 panic!("{error}");
117 })
118}
119
120#[macro_export]
126macro_rules! impl_secret_debug {
127 ($t:ty) => {
128 impl std::fmt::Debug for $t {
129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130 write!(
131 f,
132 "{}(<redacted:{}...>)",
133 stringify!($t),
134 $crate::redacted_hash(self.0.as_ref())
135 )
136 }
137 }
138 };
139}
140
141#[macro_export]
147macro_rules! impl_secret_debug_named {
148 ($t:ty, $field:ident) => {
149 impl std::fmt::Debug for $t {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 write!(
152 f,
153 "{}{{<redacted:{}...>}}",
154 stringify!($t),
155 $crate::redacted_hash(self.$field.as_ref())
156 )
157 }
158 }
159 };
160}
161
162#[cfg(test)]
163mod test {
164 #[test]
165 fn impl_secret_debug_works() {
166 struct FooSecret([u8; 32]);
167 impl_secret_debug!(FooSecret);
168 let debug_str = format!("{:?}", FooSecret([1; 32]));
169 assert_eq!(debug_str, "FooSecret(<redacted:633f9067...>)");
170 }
171
172 #[test]
173 fn impl_secret_debug_named_works() {
174 struct FooSecret {
175 secret: String,
176 }
177 impl_secret_debug_named!(FooSecret, secret);
178 let debug_str = format!(
179 "{:?}",
180 FooSecret {
181 secret: "yes".to_string()
182 }
183 );
184 assert_eq!(debug_str, "FooSecret{<redacted:bda33dd3...>}");
185 }
186}