use super::super::bounded::BufferLengthError;
pub struct ExposedSecret<'a> {
bytes: &'a [u8],
}
impl<'a> ExposedSecret<'a> {
pub(super) const fn new(bytes: &'a [u8]) -> Self {
Self { bytes }
}
#[must_use]
pub const fn as_bytes(&self) -> &[u8] {
self.bytes
}
#[must_use]
pub const fn len(&self) -> usize {
self.bytes.len()
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
}
impl AsRef<[u8]> for ExposedSecret<'_> {
fn as_ref(&self) -> &[u8] {
self.bytes
}
}
impl core::ops::Deref for ExposedSecret<'_> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.bytes
}
}
redacted_formatting!(ExposedSecret<'_>, "ExposedSecret");
pub struct ExposedSecretMut<'a> {
pub(super) bytes: &'a mut [u8],
}
impl ExposedSecretMut<'_> {
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
self.bytes
}
#[must_use]
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
self.bytes
}
#[must_use]
pub fn len(&self) -> usize {
self.bytes.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
}
impl AsRef<[u8]> for ExposedSecretMut<'_> {
fn as_ref(&self) -> &[u8] {
self.bytes
}
}
impl AsMut<[u8]> for ExposedSecretMut<'_> {
fn as_mut(&mut self) -> &mut [u8] {
self.bytes
}
}
impl core::ops::Deref for ExposedSecretMut<'_> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.bytes
}
}
impl core::ops::DerefMut for ExposedSecretMut<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.bytes
}
}
redacted_formatting!(ExposedSecretMut<'_>, "ExposedSecretMut");
pub struct SecretInput<'a> {
bytes: &'a [u8],
}
impl<'a> SecretInput<'a> {
#[must_use]
pub const fn new(bytes: &'a [u8]) -> Self {
Self { bytes }
}
#[must_use]
pub const fn expose_secret(&self) -> ExposedSecret<'_> {
ExposedSecret::new(self.bytes)
}
#[must_use]
pub const fn len(&self) -> usize {
self.bytes.len()
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
pub(crate) const fn classified_bytes(&self) -> &[u8] {
self.bytes
}
}
redacted_formatting!(SecretInput<'_>, "SecretInput");
pub struct SecretOutput<'a> {
storage: &'a mut [u8],
len: usize,
}
impl<'a> SecretOutput<'a> {
pub fn from_initialized(storage: &'a mut [u8], len: usize) -> Result<Self, BufferLengthError> {
let capacity = storage.len();
if len > capacity {
crate::wipe_bytes(storage);
return Err(BufferLengthError::new(len, capacity));
}
crate::wipe_tail(storage, len);
Ok(Self { storage, len })
}
#[must_use]
pub fn empty(storage: &'a mut [u8]) -> Self {
crate::wipe_bytes(storage);
Self { storage, len: 0 }
}
#[must_use]
pub fn expose_secret(&self) -> ExposedSecret<'_> {
ExposedSecret::new(&self.storage[..self.len])
}
#[must_use]
pub fn expose_secret_mut(&mut self) -> ExposedSecretMut<'_> {
ExposedSecretMut {
bytes: &mut self.storage[..self.len],
}
}
#[must_use = "declassification transfers cleanup responsibility to the caller"]
pub fn declassify(mut self) -> DeclassifiedOutput<'a> {
let storage = core::mem::take(&mut self.storage);
let len = self.len;
self.len = 0;
DeclassifiedOutput { storage, len }
}
#[must_use]
pub const fn len(&self) -> usize {
self.len
}
#[must_use]
pub fn capacity(&self) -> usize {
self.storage.len()
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
pub fn clear(&mut self) {
crate::wipe_bytes(self.storage);
self.len = 0;
}
}
impl Drop for SecretOutput<'_> {
fn drop(&mut self) {
self.clear();
}
}
redacted_formatting!(SecretOutput<'_>, "SecretOutput");
pub struct DeclassifiedOutput<'a> {
storage: &'a mut [u8],
len: usize,
}
impl<'a> DeclassifiedOutput<'a> {
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.storage[..self.len]
}
#[must_use]
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
&mut self.storage[..self.len]
}
#[must_use]
pub const fn len(&self) -> usize {
self.len
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
#[must_use]
pub fn into_parts(self) -> (&'a mut [u8], usize) {
(self.storage, self.len)
}
}
impl AsRef<[u8]> for DeclassifiedOutput<'_> {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsMut<[u8]> for DeclassifiedOutput<'_> {
fn as_mut(&mut self) -> &mut [u8] {
self.as_bytes_mut()
}
}