#[must_use] pubfn hex<A: AsRef<[u8]>>(buf: A) -> String { letmut ret = String::with_capacity(buf.as_ref().len() * 2); for b in buf.as_ref() {
write!(&mut ret, "{b:02x}").expect("write OK");
}
ret
}
/// Rotate keys. This causes any previous key that is being held to be replaced by the current /// key. /// /// # Errors /// /// Failure to generate a new HKDF key using NSS results in an error. pubfn rotate(&mutself) -> Res<()> { let new_key = hkdf::generate_key(self.version, self.cipher)?; self.old_key = Some(mem::replace(&mutself.key, new_key)); let (kid, _) = self.key_id.overflowing_add(1); self.key_id = kid;
info!("[SelfEncrypt] Rotated keys to {}", self.key_id);
Ok(())
}
/// Seal an item using the underlying key. This produces a single buffer that contains /// the encrypted `plaintext`, plus a version number and salt. /// `aad` is only used as input to the AEAD, it is not included in the output; the /// caller is responsible for carrying the AAD as appropriate. /// /// # Errors /// /// Failure to protect using NSS AEAD APIs produces an error. pubfn seal(&self, aad: &[u8], plaintext: &[u8]) -> Res<Vec<u8>> { // Format is: // struct { // uint8 version; // uint8 key_id; // uint8 salt[16]; // opaque aead_encrypted(plaintext)[length as expanded]; // }; // AAD covers the entire header, plus the value of the AAD parameter that is provided. let salt = random::<{ Self::SALT_LENGTH }>(); let cipher = self.make_aead(&self.key, &salt, Mode::Encrypt)?; let encoded_len = 2 + salt.len() + plaintext.len() + cipher.expansion();
letmut enc = Vec::<u8>::with_capacity(encoded_len);
enc.write_all(&[Self::VERSION])
.unwrap_or_else(|_| unreachable!("Buffer has enough capacity."));
enc.write_all(&[self.key_id])
.unwrap_or_else(|_| unreachable!("Buffer has enough capacity."));
enc.write_all(&salt)
.unwrap_or_else(|_| unreachable!("Buffer has enough capacity."));
/// Open the protected `ciphertext`. /// /// # Errors /// /// Returns an error when the self-encrypted object is invalid; /// when the keys have been rotated; or when NSS fails. #[expect(clippy::similar_names, reason = "aad is similar to aead.")] pubfn open(&self, aad: &[u8], ciphertext: &[u8]) -> Res<Vec<u8>> { const OFFSET: usize = 2 + SelfEncrypt::SALT_LENGTH; if *ciphertext.first().ok_or(Error::SelfEncrypt)? != Self::VERSION { return Err(Error::SelfEncrypt);
} let Some(key) = self.select_key(*ciphertext.get(1).ok_or(Error::SelfEncrypt)?) else { return Err(Error::SelfEncrypt);
}; let salt = ciphertext.get(2..OFFSET).ok_or(Error::SelfEncrypt)?;
letmut extended_aad = Vec::<u8>::with_capacity(OFFSET + aad.len());
extended_aad
.write_all(&ciphertext[..OFFSET])
.unwrap_or_else(|_| unreachable!("Buffer has enough capacity."));
extended_aad
.write_all(aad)
.unwrap_or_else(|_| unreachable!("Buffer has enough capacity."));
let aead = self.make_aead(key, salt, Mode::Decrypt)?; // NSS insists on having extra space available for decryption. let padded_len = ciphertext.len() - OFFSET; letmut output = vec![0; padded_len]; let decrypted =
aead.decrypt(0, extended_aad.as_ref(), &ciphertext[OFFSET..], &mut output)?; let final_len = decrypted.len();
output.truncate(final_len);
trace!( "[SelfEncrypt] open {} {} -> {}",
hex(aad),
hex(ciphertext),
hex(&output)
);
Ok(output)
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.