• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Abstractions and related types for accessing cryptographic primitives
2 //! and related functionality.
3 
4 use crate::{km_err, vec_try, vec_try_with_capacity, Error, FallibleAllocExt};
5 use alloc::{
6     format,
7     string::{String, ToString},
8     vec::Vec,
9 };
10 use core::convert::{From, TryInto};
11 use enumn::N;
12 use kmr_derive::AsCborValue;
13 use kmr_wire::keymint::{Algorithm, Digest, EcCurve};
14 use kmr_wire::{cbor, cbor_type_error, AsCborValue, CborError, KeySizeInBits, RsaExponent};
15 use log::error;
16 use spki::SubjectPublicKeyInfo;
17 use zeroize::ZeroizeOnDrop;
18 
19 pub mod aes;
20 pub mod des;
21 pub mod ec;
22 pub mod hmac;
23 pub mod rsa;
24 mod traits;
25 pub use traits::*;
26 
27 /// Size of SHA-256 output in bytes.
28 pub const SHA256_DIGEST_LEN: usize = 32;
29 
30 /// Function that mimics `slice.to_vec()` but which detects allocation failures.  This version emits
31 /// `CborError` (instead of the `Error` that `crate::try_to_vec` emits).
32 #[inline]
try_to_vec<T: Clone>(s: &[T]) -> Result<Vec<T>, CborError>33 pub fn try_to_vec<T: Clone>(s: &[T]) -> Result<Vec<T>, CborError> {
34     let mut v = vec_try_with_capacity!(s.len()).map_err(|_e| CborError::AllocationFailed)?;
35     v.extend_from_slice(s);
36     Ok(v)
37 }
38 
39 /// Milliseconds since an arbitrary epoch.
40 #[repr(transparent)]
41 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
42 pub struct MillisecondsSinceEpoch(pub i64);
43 
44 impl From<MillisecondsSinceEpoch> for kmr_wire::secureclock::Timestamp {
from(value: MillisecondsSinceEpoch) -> Self45     fn from(value: MillisecondsSinceEpoch) -> Self {
46         kmr_wire::secureclock::Timestamp { milliseconds: value.0 }
47     }
48 }
49 
50 /// Information for key generation.
51 #[derive(Clone)]
52 pub enum KeyGenInfo {
53     Aes(aes::Variant),
54     TripleDes,
55     Hmac(KeySizeInBits),
56     Rsa(KeySizeInBits, RsaExponent),
57     NistEc(ec::NistCurve),
58     Ed25519,
59     X25519,
60 }
61 
62 /// Type of elliptic curve.
63 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, AsCborValue, N)]
64 #[repr(i32)]
65 pub enum CurveType {
66     Nist = 0,
67     EdDsa = 1,
68     Xdh = 2,
69 }
70 
71 /// Raw key material used for deriving other keys.
72 #[derive(PartialEq, Eq, ZeroizeOnDrop)]
73 pub struct RawKeyMaterial(pub Vec<u8>);
74 
75 /// Opaque key material whose structure is only known/accessible to the crypto implementation.
76 /// The contents of this are assumed to be encrypted (and so are not `ZeroizeOnDrop`).
77 #[derive(Clone, PartialEq, Eq)]
78 pub struct OpaqueKeyMaterial(pub Vec<u8>);
79 
80 /// Wrapper that holds either a key of explicit type `T`, or an opaque blob of key material.
81 #[derive(Clone, PartialEq, Eq)]
82 pub enum OpaqueOr<T> {
83     Explicit(T),
84     Opaque(OpaqueKeyMaterial),
85 }
86 
87 /// Macro to provide `impl From<SomeKey> for OpaqueOr<SomeKey>`, so that explicit key material
88 /// automatically converts into the equivalent `OpaqueOr` variant.
89 macro_rules! opaque_from_key {
90     { $t:ty } => {
91         impl From<$t> for OpaqueOr<$t> {
92             fn from(k: $t) -> Self {
93                 Self::Explicit(k)
94             }
95         }
96     }
97 }
98 
99 opaque_from_key!(aes::Key);
100 opaque_from_key!(des::Key);
101 opaque_from_key!(hmac::Key);
102 opaque_from_key!(rsa::Key);
103 opaque_from_key!(ec::Key);
104 
105 impl<T> From<OpaqueKeyMaterial> for OpaqueOr<T> {
from(k: OpaqueKeyMaterial) -> Self106     fn from(k: OpaqueKeyMaterial) -> Self {
107         Self::Opaque(k)
108     }
109 }
110 
111 /// Key material that is held in plaintext (or is alternatively an opaque blob that is only
112 /// known/accessible to the crypto implementation, indicated by the `OpaqueOr::Opaque` variant).
113 #[derive(Clone, PartialEq, Eq)]
114 pub enum KeyMaterial {
115     Aes(OpaqueOr<aes::Key>),
116     TripleDes(OpaqueOr<des::Key>),
117     Hmac(OpaqueOr<hmac::Key>),
118     Rsa(OpaqueOr<rsa::Key>),
119     Ec(EcCurve, CurveType, OpaqueOr<ec::Key>),
120 }
121 
122 /// Macro that extracts the explicit key from an [`OpaqueOr`] wrapper.
123 #[macro_export]
124 macro_rules! explicit {
125     { $key:expr } => {
126         if let $crate::crypto::OpaqueOr::Explicit(k) = $key {
127             Ok(k)
128         } else {
129             Err($crate::km_err!(UnknownError, "Expected explicit key but found opaque key!"))
130         }
131     }
132 }
133 
134 impl KeyMaterial {
135     /// Indicate whether the key material is for an asymmetric key.
is_asymmetric(&self) -> bool136     pub fn is_asymmetric(&self) -> bool {
137         match self {
138             Self::Aes(_) | Self::TripleDes(_) | Self::Hmac(_) => false,
139             Self::Ec(_, _, _) | Self::Rsa(_) => true,
140         }
141     }
142 
143     /// Indicate whether the key material is for a symmetric key.
is_symmetric(&self) -> bool144     pub fn is_symmetric(&self) -> bool {
145         !self.is_asymmetric()
146     }
147 
148     /// Return the public key information as an ASN.1 DER encodable `SubjectPublicKeyInfo`, as
149     /// described in RFC 5280 section 4.1.
150     ///
151     /// ```asn1
152     /// SubjectPublicKeyInfo  ::=  SEQUENCE  {
153     ///    algorithm            AlgorithmIdentifier,
154     ///    subjectPublicKey     BIT STRING  }
155     ///
156     /// AlgorithmIdentifier  ::=  SEQUENCE  {
157     ///    algorithm               OBJECT IDENTIFIER,
158     ///    parameters              ANY DEFINED BY algorithm OPTIONAL  }
159     /// ```
160     ///
161     /// Returns `None` for a symmetric key.
subject_public_key_info<'a>( &'a self, buf: &'a mut Vec<u8>, ec: &dyn Ec, rsa: &dyn Rsa, ) -> Result<Option<SubjectPublicKeyInfo<'a>>, Error>162     pub fn subject_public_key_info<'a>(
163         &'a self,
164         buf: &'a mut Vec<u8>,
165         ec: &dyn Ec,
166         rsa: &dyn Rsa,
167     ) -> Result<Option<SubjectPublicKeyInfo<'a>>, Error> {
168         Ok(match self {
169             Self::Rsa(key) => Some(key.subject_public_key_info(buf, rsa)?),
170             Self::Ec(curve, curve_type, key) => {
171                 Some(key.subject_public_key_info(buf, ec, curve, curve_type)?)
172             }
173             _ => None,
174         })
175     }
176 }
177 
178 /// Manual implementation of [`Debug`] that skips emitting plaintext key material.
179 impl core::fmt::Debug for KeyMaterial {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result180     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
181         match self {
182             Self::Aes(k) => match k {
183                 OpaqueOr::Explicit(aes::Key::Aes128(_)) => f.write_str("Aes128(...)"),
184                 OpaqueOr::Explicit(aes::Key::Aes192(_)) => f.write_str("Aes192(...)"),
185                 OpaqueOr::Explicit(aes::Key::Aes256(_)) => f.write_str("Aes256(...)"),
186                 OpaqueOr::Opaque(_) => f.write_str("Aes(opaque)"),
187             },
188             Self::TripleDes(_) => f.write_str("TripleDes(...)"),
189             Self::Hmac(_) => f.write_str("Hmac(...)"),
190             Self::Rsa(_) => f.write_str("Rsa(...)"),
191             Self::Ec(c, _, _) => f.write_fmt(format_args!("Ec({:?}, ...)", c)),
192         }
193     }
194 }
195 
196 impl AsCborValue for KeyMaterial {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>197     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
198         let mut a = match value {
199             cbor::value::Value::Array(a) if a.len() == 3 => a,
200             _ => return cbor_type_error(&value, "arr len 3"),
201         };
202         let raw_key_value = a.remove(2);
203         let opaque = match a.remove(1) {
204             cbor::value::Value::Bool(b) => b,
205             v => return cbor_type_error(&v, "bool"),
206         };
207         let algo: i32 = match a.remove(0) {
208             cbor::value::Value::Integer(i) => i.try_into()?,
209             v => return cbor_type_error(&v, "uint"),
210         };
211 
212         match algo {
213             x if x == Algorithm::Aes as i32 => {
214                 let raw_key = <Vec<u8>>::from_cbor_value(raw_key_value)?;
215                 if opaque {
216                     Ok(Self::Aes(OpaqueKeyMaterial(raw_key).into()))
217                 } else {
218                     match aes::Key::new(raw_key) {
219                         Ok(k) => Ok(Self::Aes(k.into())),
220                         Err(_e) => Err(CborError::UnexpectedItem("bstr", "bstr len 16/24/32")),
221                     }
222                 }
223             }
224             x if x == Algorithm::TripleDes as i32 => {
225                 let raw_key = <Vec<u8>>::from_cbor_value(raw_key_value)?;
226                 if opaque {
227                     Ok(Self::TripleDes(OpaqueKeyMaterial(raw_key).into()))
228                 } else {
229                     Ok(Self::TripleDes(
230                         des::Key(
231                             raw_key
232                                 .try_into()
233                                 .map_err(|_e| CborError::UnexpectedItem("bstr", "bstr len 24"))?,
234                         )
235                         .into(),
236                     ))
237                 }
238             }
239             x if x == Algorithm::Hmac as i32 => {
240                 let raw_key = <Vec<u8>>::from_cbor_value(raw_key_value)?;
241                 if opaque {
242                     Ok(Self::Hmac(OpaqueKeyMaterial(raw_key).into()))
243                 } else {
244                     Ok(Self::Hmac(hmac::Key(raw_key).into()))
245                 }
246             }
247             x if x == Algorithm::Rsa as i32 => {
248                 let raw_key = <Vec<u8>>::from_cbor_value(raw_key_value)?;
249                 if opaque {
250                     Ok(Self::Rsa(OpaqueKeyMaterial(raw_key).into()))
251                 } else {
252                     Ok(Self::Rsa(rsa::Key(raw_key).into()))
253                 }
254             }
255             x if x == Algorithm::Ec as i32 => {
256                 let mut a = match raw_key_value {
257                     cbor::value::Value::Array(a) if a.len() == 3 => a,
258                     _ => return cbor_type_error(&raw_key_value, "arr len 2"),
259                 };
260                 let raw_key_value = a.remove(2);
261                 let raw_key = <Vec<u8>>::from_cbor_value(raw_key_value)?;
262                 let curve_type = CurveType::from_cbor_value(a.remove(1))?;
263                 let curve = <EcCurve>::from_cbor_value(a.remove(0))?;
264                 if opaque {
265                     Ok(Self::Ec(curve, curve_type, OpaqueKeyMaterial(raw_key).into()))
266                 } else {
267                     let key = match (curve, curve_type) {
268                         (EcCurve::P224, CurveType::Nist) => ec::Key::P224(ec::NistKey(raw_key)),
269                         (EcCurve::P256, CurveType::Nist) => ec::Key::P256(ec::NistKey(raw_key)),
270                         (EcCurve::P384, CurveType::Nist) => ec::Key::P384(ec::NistKey(raw_key)),
271                         (EcCurve::P521, CurveType::Nist) => ec::Key::P521(ec::NistKey(raw_key)),
272                         (EcCurve::Curve25519, CurveType::EdDsa) => {
273                             let key = raw_key.try_into().map_err(|_e| {
274                                 error!("decoding Ed25519 key of incorrect len");
275                                 CborError::OutOfRangeIntegerValue
276                             })?;
277                             ec::Key::Ed25519(ec::Ed25519Key(key))
278                         }
279                         (EcCurve::Curve25519, CurveType::Xdh) => {
280                             let key = raw_key.try_into().map_err(|_e| {
281                                 error!("decoding X25519 key of incorrect len");
282                                 CborError::OutOfRangeIntegerValue
283                             })?;
284                             ec::Key::X25519(ec::X25519Key(key))
285                         }
286                         (_, _) => {
287                             error!("Unexpected EC combination ({:?}, {:?})", curve, curve_type);
288                             return Err(CborError::NonEnumValue);
289                         }
290                     };
291                     Ok(Self::Ec(curve, curve_type, key.into()))
292                 }
293             }
294             _ => Err(CborError::UnexpectedItem("unknown enum", "algo enum")),
295         }
296     }
297 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>298     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
299         let cbor_alloc_err = |_e| CborError::AllocationFailed;
300         Ok(cbor::value::Value::Array(match self {
301             Self::Aes(OpaqueOr::Opaque(OpaqueKeyMaterial(k))) => vec_try![
302                 cbor::value::Value::Integer((Algorithm::Aes as i32).into()),
303                 cbor::value::Value::Bool(true),
304                 cbor::value::Value::Bytes(try_to_vec(&k)?),
305             ]
306             .map_err(cbor_alloc_err)?,
307             Self::TripleDes(OpaqueOr::Opaque(OpaqueKeyMaterial(k))) => vec_try![
308                 cbor::value::Value::Integer((Algorithm::TripleDes as i32).into()),
309                 cbor::value::Value::Bool(true),
310                 cbor::value::Value::Bytes(try_to_vec(&k)?),
311             ]
312             .map_err(cbor_alloc_err)?,
313             Self::Hmac(OpaqueOr::Opaque(OpaqueKeyMaterial(k))) => vec_try![
314                 cbor::value::Value::Integer((Algorithm::Hmac as i32).into()),
315                 cbor::value::Value::Bool(true),
316                 cbor::value::Value::Bytes(try_to_vec(&k)?),
317             ]
318             .map_err(cbor_alloc_err)?,
319             Self::Rsa(OpaqueOr::Opaque(OpaqueKeyMaterial(k))) => vec_try![
320                 cbor::value::Value::Integer((Algorithm::Rsa as i32).into()),
321                 cbor::value::Value::Bool(true),
322                 cbor::value::Value::Bytes(try_to_vec(&k)?),
323             ]
324             .map_err(cbor_alloc_err)?,
325             Self::Ec(curve, curve_type, OpaqueOr::Opaque(OpaqueKeyMaterial(k))) => vec_try![
326                 cbor::value::Value::Integer((Algorithm::Ec as i32).into()),
327                 cbor::value::Value::Bool(true),
328                 cbor::value::Value::Array(
329                     vec_try![
330                         cbor::value::Value::Integer((curve as i32).into()),
331                         cbor::value::Value::Integer((curve_type as i32).into()),
332                         cbor::value::Value::Bytes(try_to_vec(&k)?),
333                     ]
334                     .map_err(cbor_alloc_err)?
335                 ),
336             ]
337             .map_err(cbor_alloc_err)?,
338 
339             Self::Aes(OpaqueOr::Explicit(k)) => vec_try![
340                 cbor::value::Value::Integer((Algorithm::Aes as i32).into()),
341                 cbor::value::Value::Bool(false),
342                 match k {
343                     aes::Key::Aes128(k) => cbor::value::Value::Bytes(try_to_vec(&k)?),
344                     aes::Key::Aes192(k) => cbor::value::Value::Bytes(try_to_vec(&k)?),
345                     aes::Key::Aes256(k) => cbor::value::Value::Bytes(try_to_vec(&k)?),
346                 },
347             ]
348             .map_err(cbor_alloc_err)?,
349 
350             Self::TripleDes(OpaqueOr::Explicit(k)) => vec_try![
351                 cbor::value::Value::Integer((Algorithm::TripleDes as i32).into()),
352                 cbor::value::Value::Bool(false),
353                 cbor::value::Value::Bytes(k.0.to_vec()),
354             ]
355             .map_err(cbor_alloc_err)?,
356             Self::Hmac(OpaqueOr::Explicit(k)) => vec_try![
357                 cbor::value::Value::Integer((Algorithm::Hmac as i32).into()),
358                 cbor::value::Value::Bool(false),
359                 cbor::value::Value::Bytes(k.0.clone()),
360             ]
361             .map_err(cbor_alloc_err)?,
362             Self::Rsa(OpaqueOr::Explicit(k)) => vec_try![
363                 cbor::value::Value::Integer((Algorithm::Rsa as i32).into()),
364                 cbor::value::Value::Bool(false),
365                 cbor::value::Value::Bytes(k.0.clone()),
366             ]
367             .map_err(cbor_alloc_err)?,
368             Self::Ec(curve, curve_type, OpaqueOr::Explicit(k)) => vec_try![
369                 cbor::value::Value::Integer((Algorithm::Ec as i32).into()),
370                 cbor::value::Value::Bool(false),
371                 cbor::value::Value::Array(
372                     vec_try![
373                         cbor::value::Value::Integer((curve as i32).into()),
374                         cbor::value::Value::Integer((curve_type as i32).into()),
375                         cbor::value::Value::Bytes(k.private_key_bytes().to_vec()),
376                     ]
377                     .map_err(cbor_alloc_err)?,
378                 ),
379             ]
380             .map_err(cbor_alloc_err)?,
381         }))
382     }
383 
cddl_typename() -> Option<String>384     fn cddl_typename() -> Option<String> {
385         Some("KeyMaterial".to_string())
386     }
387 
cddl_schema() -> Option<String>388     fn cddl_schema() -> Option<String> {
389         Some(format!(
390             "&(
391   ; For each variant the `bool` second entry indicates whether the bstr for the key material
392   ; is opaque (true), or explicit (false).
393   [{}, bool, bstr], ; {}
394   [{}, bool, bstr], ; {}
395   [{}, bool, bstr], ; {}
396   ; An explicit RSA key is in the form of an ASN.1 DER encoding of a PKCS#1 `RSAPrivateKey`
397   ; structure, as specified by RFC 3447 sections A.1.2 and 3.2.
398   [{}, bool, bstr], ; {}
399   ; An explicit EC key for a NIST curve is in the form of an ASN.1 DER encoding of a
400   ; `ECPrivateKey` structure, as specified by RFC 5915 section 3.
401   ; An explicit EC key for curve 25519 is the raw key bytes.
402   [{}, bool, [EcCurve, CurveType, bstr]], ; {}
403 )",
404             Algorithm::Aes as i32,
405             "Algorithm_Aes",
406             Algorithm::TripleDes as i32,
407             "Algorithm_TripleDes",
408             Algorithm::Hmac as i32,
409             "Algorithm_Hmac",
410             Algorithm::Rsa as i32,
411             "Algorithm_Rsa",
412             Algorithm::Ec as i32,
413             "Algorithm_Ec",
414         ))
415     }
416 }
417 
418 /// Direction of cipher operation.
419 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
420 pub enum SymmetricOperation {
421     Encrypt,
422     Decrypt,
423 }
424 
425 /// Extract or generate a nonce of the given size.
nonce( size: usize, caller_nonce: Option<&Vec<u8>>, rng: &mut dyn Rng, ) -> Result<Vec<u8>, Error>426 pub fn nonce(
427     size: usize,
428     caller_nonce: Option<&Vec<u8>>,
429     rng: &mut dyn Rng,
430 ) -> Result<Vec<u8>, Error> {
431     match caller_nonce {
432         Some(n) => match n.len() {
433             l if l == size => Ok(n.clone()),
434             _ => Err(km_err!(InvalidNonce, "want {} byte nonce", size)),
435         },
436         None => {
437             let mut n = vec_try![0; size]?;
438             rng.fill_bytes(&mut n);
439             Ok(n)
440         }
441     }
442 }
443 
444 /// Salt value used in HKDF if none provided.
445 const HKDF_EMPTY_SALT: [u8; SHA256_DIGEST_LEN] = [0; SHA256_DIGEST_LEN];
446 
447 /// Convenience wrapper to perform one-shot HMAC-SHA256.
hmac_sha256(hmac: &dyn Hmac, key: &[u8], data: &[u8]) -> Result<Vec<u8>, Error>448 pub fn hmac_sha256(hmac: &dyn Hmac, key: &[u8], data: &[u8]) -> Result<Vec<u8>, Error> {
449     let mut op = hmac.begin(hmac::Key(crate::try_to_vec(key)?).into(), Digest::Sha256)?;
450     op.update(data)?;
451     op.finish()
452 }
453 
454 /// Default implementation of [`Hkdf`] for any type implementing [`Hmac`].
455 impl<T: Hmac> Hkdf for T {
extract(&self, mut salt: &[u8], ikm: &[u8]) -> Result<OpaqueOr<hmac::Key>, Error>456     fn extract(&self, mut salt: &[u8], ikm: &[u8]) -> Result<OpaqueOr<hmac::Key>, Error> {
457         if salt.is_empty() {
458             salt = &HKDF_EMPTY_SALT[..];
459         }
460         let prk = hmac_sha256(self, salt, ikm)?;
461         Ok(OpaqueOr::Explicit(hmac::Key::new(prk)))
462     }
463 
expand( &self, prk: &OpaqueOr<hmac::Key>, info: &[u8], out_len: usize, ) -> Result<Vec<u8>, Error>464     fn expand(
465         &self,
466         prk: &OpaqueOr<hmac::Key>,
467         info: &[u8],
468         out_len: usize,
469     ) -> Result<Vec<u8>, Error> {
470         let prk = &explicit!(prk)?.0;
471         let n = (out_len + SHA256_DIGEST_LEN - 1) / SHA256_DIGEST_LEN;
472         if n > 256 {
473             return Err(km_err!(UnknownError, "overflow in hkdf"));
474         }
475         let mut t = vec_try_with_capacity!(SHA256_DIGEST_LEN)?;
476         let mut okm = vec_try_with_capacity!(n * SHA256_DIGEST_LEN)?;
477         let n = n as u8;
478         for idx in 0..n {
479             let mut input = vec_try_with_capacity!(t.len() + info.len() + 1)?;
480             input.extend_from_slice(&t);
481             input.extend_from_slice(info);
482             input.push(idx + 1);
483 
484             t = hmac_sha256(self, prk, &input)?;
485             okm.try_extend_from_slice(&t)?;
486         }
487         okm.truncate(out_len);
488         Ok(okm)
489     }
490 }
491 
492 /// Default implementation of [`Ckdf`] for any type implementing [`AesCmac`].
493 impl<T: AesCmac> Ckdf for T {
ckdf( &self, key: &OpaqueOr<aes::Key>, label: &[u8], chunks: &[&[u8]], out_len: usize, ) -> Result<Vec<u8>, Error>494     fn ckdf(
495         &self,
496         key: &OpaqueOr<aes::Key>,
497         label: &[u8],
498         chunks: &[&[u8]],
499         out_len: usize,
500     ) -> Result<Vec<u8>, Error> {
501         let key = explicit!(key)?;
502         // Note: the variables i and l correspond to i and L in the standard.  See page 12 of
503         // http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-108.pdf.
504 
505         let blocks: u32 = ((out_len + aes::BLOCK_SIZE - 1) / aes::BLOCK_SIZE) as u32;
506         let l = (out_len * 8) as u32; // in bits
507         let net_order_l = l.to_be_bytes();
508         let zero_byte: [u8; 1] = [0];
509         let mut output = vec_try![0; out_len]?;
510         let mut output_pos = 0;
511 
512         for i in 1u32..=blocks {
513             // Data to mac is (i:u32 || label || 0x00:u8 || context || L:u32), with integers in
514             // network order.
515             let mut op = self.begin(key.clone().into())?;
516             let net_order_i = i.to_be_bytes();
517             op.update(&net_order_i[..])?;
518             op.update(label)?;
519             op.update(&zero_byte[..])?;
520             for chunk in chunks {
521                 op.update(chunk)?;
522             }
523             op.update(&net_order_l[..])?;
524 
525             let data = op.finish()?;
526             let copy_len = core::cmp::min(data.len(), output.len() - output_pos);
527             output[output_pos..output_pos + copy_len].clone_from_slice(&data[..copy_len]);
528             output_pos += copy_len;
529         }
530         if output_pos != output.len() {
531             return Err(km_err!(
532                 UnknownError,
533                 "finished at {} before end of output at {}",
534                 output_pos,
535                 output.len()
536             ));
537         }
538         Ok(output)
539     }
540 }
541