1use core::fmt::Debug;
21
22use crate::error::{Error, ErrorCode};
23use crate::tlv::{FromTLV, TLVElement, TLVTag, TLVWrite, ToTLV, TLV};
24use crate::utils::init::{init, zeroed, Init, IntoFallibleInit};
25
26pub const HASH_LEN: usize = 32;
30
31pub const SHA1_HASH_LEN: usize = 20;
33
34pub const HMAC_HASH_LEN: usize = HASH_LEN;
38
39pub const EC_CANON_SCALAR_LEN: usize = 32;
43
44pub const EC_CANON_POINT_LEN: usize = EC_CANON_SCALAR_LEN * 2 + 1;
48
49pub const PKC_CANON_PUBLIC_KEY_LEN: usize = EC_CANON_POINT_LEN;
56
57pub const PKC_CANON_SECRET_KEY_LEN: usize = EC_CANON_SCALAR_LEN;
64
65pub const PKC_SIGNATURE_LEN: usize = PKC_CANON_SECRET_KEY_LEN * 2;
73
74pub const PKC_SHARED_SECRET_LEN: usize = 32;
81
82pub const UINT320_CANON_LEN: usize = 40;
86
87pub const AEAD_CANON_KEY_LEN: usize = 16;
91
92pub const AEAD_NONCE_LEN: usize = 13;
96
97pub const AEAD_TAG_LEN: usize = 16;
101
102macro_rules! canon {
103 ($len:expr, $zero: ident, $name:ident, $name_ref:ident) => {
104 #[allow(unused)]
106 pub type $name = $crate::crypto::CryptoSensitive<$len>;
107
108 #[allow(unused)]
110 pub type $name_ref<'a> = $crate::crypto::CryptoSensitiveRef<'a, $len>;
111
112 #[allow(unused)]
114 pub const $zero: $name = $name::new();
115 };
116}
117
118pub(crate) use canon;
119
120canon!(HASH_LEN, HASH_ZEROED, Hash, HashRef);
121canon!(HMAC_HASH_LEN, HMAC_HASH_ZEROED, HmacHash, HmacHashRef);
122
123canon!(
124 UINT320_CANON_LEN,
125 UINT320_ZEROED,
126 CanonUint320,
127 CanonUint320Ref
128);
129
130canon!(
131 AEAD_CANON_KEY_LEN,
132 AEAD_KEY_ZEROED,
133 CanonAeadKey,
134 CanonAeadKeyRef
135);
136canon!(AEAD_NONCE_LEN, AEAD_NONCE_ZEROED, AeadNonce, AeadNonceRef);
137canon!(AEAD_TAG_LEN, AEAD_TAG_ZEROED, AeadTag, AeadTagRef);
138
139canon!(
140 PKC_CANON_PUBLIC_KEY_LEN,
141 PKC_PUBLIC_KEY_ZEROED,
142 CanonPkcPublicKey,
143 CanonPkcPublicKeyRef
144);
145canon!(
146 PKC_CANON_SECRET_KEY_LEN,
147 PKC_SECRET_KEY_ZEROED,
148 CanonPkcSecretKey,
149 CanonPkcSecretKeyRef
150);
151canon!(
152 PKC_SIGNATURE_LEN,
153 PKC_SIGNATURE_ZEROED,
154 CanonPkcSignature,
155 CanonPkcSignatureRef
156);
157canon!(
158 PKC_SHARED_SECRET_LEN,
159 PKC_SHARED_SECRET_ZEROED,
160 CanonPkcSharedSecret,
161 CanonPkcSharedSecretRef
162);
163
164canon!(
165 EC_CANON_SCALAR_LEN,
166 EC_SCALAR_ZEROED,
167 CanonEcScalar,
168 CanonEcScalarRef
169);
170canon!(
171 EC_CANON_POINT_LEN,
172 EC_POINT_ZEROED,
173 CanonEcPoint,
174 CanonEcPointRef
175);
176
177#[derive(Clone)]
198pub struct CryptoSensitive<const N: usize> {
199 data: [u8; N],
201}
202
203impl<const N: usize> CryptoSensitive<N> {
204 #[inline(always)]
206 pub const fn new() -> Self {
207 Self { data: [0u8; N] }
208 }
209
210 pub const fn new_from_ref(other: CryptoSensitiveRef<'_, N>) -> Self {
212 let mut this = Self::new();
213
214 this.load(other);
215
216 this
217 }
218
219 #[inline(always)]
221 pub fn init() -> impl Init<Self> {
222 init!(Self {
223 data <- zeroed(),
224 })
225 }
226
227 pub fn zeroize(&mut self) {
229 self.data.fill(0);
232 }
233
234 pub const fn reference(&self) -> CryptoSensitiveRef<'_, N> {
236 CryptoSensitiveRef::new(&self.data)
237 }
238
239 pub const fn load(&mut self, other: CryptoSensitiveRef<'_, N>) {
241 self.load_from_array(other.access());
242 }
243
244 pub const fn load_from_array(&mut self, data: &[u8; N]) {
246 self.data.copy_from_slice(data);
247 }
248
249 pub fn try_load_from_slice(&mut self, data: &[u8]) -> Result<(), Error> {
253 if data.len() != N {
254 return Err(ErrorCode::InvalidData.into());
255 }
256
257 self.data.copy_from_slice(data);
258
259 Ok(())
260 }
261
262 pub const fn access(&self) -> &[u8; N] {
266 &self.data
267 }
268
269 pub const fn access_mut(&mut self) -> &mut [u8; N] {
273 &mut self.data
274 }
275}
276
277impl<const N: usize> Drop for CryptoSensitive<N> {
278 fn drop(&mut self) {
279 self.zeroize();
280 }
281}
282
283impl<const N: usize> Default for CryptoSensitive<N> {
284 fn default() -> Self {
285 Self::new()
286 }
287}
288
289impl<const N: usize> Debug for CryptoSensitive<N> {
290 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
291 write!(f, "CryptoSensitive<{}>(**hidden**)", N)
292 }
293}
294
295#[cfg(feature = "defmt")]
296impl<const N: usize> defmt::Format for CryptoSensitive<N> {
297 fn format(&self, f: defmt::Formatter) {
298 defmt::write!(f, "CryptoSensitive<{}>(**hidden**)", N);
299 }
300}
301
302impl<const N: usize> From<CryptoSensitiveRef<'_, N>> for CryptoSensitive<N> {
303 fn from(other: CryptoSensitiveRef<'_, N>) -> Self {
304 let mut material = CryptoSensitive::new();
305
306 material.load(other);
307
308 material
309 }
310}
311
312impl<const N: usize> From<&[u8; N]> for CryptoSensitive<N> {
313 fn from(data: &[u8; N]) -> Self {
314 let mut material = CryptoSensitive::new();
315
316 material.load_from_array(data);
317
318 material
319 }
320}
321
322impl<const N: usize> From<[u8; N]> for CryptoSensitive<N> {
323 fn from(data: [u8; N]) -> Self {
324 let mut material = CryptoSensitive::new();
325
326 material.load_from_array(&data);
327
328 material
329 }
330}
331
332impl<const N: usize> TryFrom<&[u8]> for CryptoSensitive<N> {
333 type Error = Error;
334
335 fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
336 let mut material = CryptoSensitive::new();
337
338 material.try_load_from_slice(data)?;
339
340 Ok(material)
341 }
342}
343
344impl<'a, const N: usize> FromTLV<'a> for CryptoSensitive<N> {
345 fn from_tlv(element: &TLVElement<'a>) -> Result<Self, crate::error::Error> {
346 Ok(Self {
347 data: element
348 .str()?
349 .try_into()
350 .map_err(|_| ErrorCode::ConstraintError)?,
351 })
352 }
353
354 fn init_from_tlv(element: TLVElement<'a>) -> impl Init<Self, Error> {
355 Init::chain(Self::init().into_fallible(), move |this| {
356 let data = element.str()?;
357 if data.len() != N {
358 Err(ErrorCode::ConstraintError)?;
359 }
360
361 this.access_mut().copy_from_slice(data);
362
363 Ok(())
364 })
365 }
366}
367
368impl<const N: usize> ToTLV for CryptoSensitive<N> {
369 fn to_tlv<W: TLVWrite>(&self, tag: &TLVTag, mut tw: W) -> Result<(), Error> {
370 tw.str(tag, &self.data)
371 }
372
373 fn tlv_iter(&self, tag: TLVTag) -> impl Iterator<Item = Result<TLV<'_>, Error>> {
374 TLV::str(tag, self.data.as_slice()).into_tlv_iter()
375 }
376}
377
378#[derive(Copy, Clone)]
381pub struct CryptoSensitiveRef<'a, const N: usize> {
382 data: &'a [u8; N],
383}
384
385impl<'a, const N: usize> CryptoSensitiveRef<'a, N> {
386 #[inline(always)]
388 pub const fn new(material: &'a [u8; N]) -> Self {
389 Self { data: material }
390 }
391
392 #[inline(always)]
396 pub fn new_from_slice(material: &'a [u8]) -> Self {
397 assert_eq!(material.len(), N);
398
399 Self::new(Self::as_array(material).unwrap()) }
401
402 #[inline(always)]
406 pub fn try_new(material: &'a [u8]) -> Result<Self, Error> {
407 if material.len() != N {
408 Err(ErrorCode::InvalidData)?;
409 }
410
411 Ok(Self::new(Self::as_array(material).unwrap())) }
413
414 pub fn split<const M1: usize, const M2: usize>(
418 &self,
419 ) -> (CryptoSensitiveRef<'a, M1>, CryptoSensitiveRef<'a, M2>) {
420 let (left, right) = self.data.split_at(M1);
421
422 (
423 CryptoSensitiveRef::new_from_slice(left),
424 CryptoSensitiveRef::new_from_slice(right),
425 )
426 }
427
428 pub const fn access(&self) -> &'a [u8; N] {
432 self.data
433 }
434
435 const fn as_array<const L: usize>(slice: &'a [u8]) -> Option<&'a [u8; L]> {
437 if slice.len() == L {
438 let ptr = slice.as_ptr() as *const [u8; L];
439
440 let me = unsafe { &*ptr };
442 Some(me)
443 } else {
444 None
445 }
446 }
447}
448
449impl<const N: usize> Debug for CryptoSensitiveRef<'_, N> {
450 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
451 write!(f, "CryptoSensitiveRef<{}>(**hidden**)", N)
452 }
453}
454
455#[cfg(feature = "defmt")]
456impl<const N: usize> defmt::Format for CryptoSensitiveRef<'_, N> {
457 fn format(&self, f: defmt::Formatter) {
458 defmt::write!(f, "CryptoSensitiveRef<{}>(**hidden**)", N);
459 }
460}
461
462impl<'a, const N: usize> From<&'a CryptoSensitive<N>> for CryptoSensitiveRef<'a, N> {
463 fn from(cs: &'a CryptoSensitive<N>) -> Self {
464 cs.reference()
465 }
466}
467
468impl<'a, const N: usize> From<&'a [u8; N]> for CryptoSensitiveRef<'a, N> {
469 fn from(data: &'a [u8; N]) -> Self {
470 Self::new(data)
471 }
472}
473
474impl<'a, const N: usize> TryFrom<&'a [u8]> for CryptoSensitiveRef<'a, N> {
475 type Error = Error;
476
477 fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
478 Self::try_new(data)
479 }
480}