blob: b4f5684f7db0e81f5f947cd7a478f64dd99d660d [file] [log] [blame] [edit]
// Copyright 2018 Brian Smith.
// SPDX-License-Identifier: ISC
// Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#![allow(dead_code)]
//! Initialization Vector (IV) cryptographic primitives
use crate::error::Unspecified;
use crate::rand;
use zeroize::Zeroize;
/// Length of a 128-bit IV in bytes.
pub const IV_LEN_128_BIT: usize = 16;
/// An initialization vector that must be unique for the lifetime of the associated key
/// it is used with.
pub struct FixedLength<const L: usize>([u8; L]);
impl<const L: usize> FixedLength<L> {
/// Returns the size of the iv in bytes.
#[allow(clippy::must_use_candidate)]
pub fn size(&self) -> usize {
L
}
/// Constructs a new [`FixedLength`] from pseudo-random bytes.
///
/// # Errors
///
/// * [`Unspecified`]: Returned if there is a failure generating `L` bytes.
pub fn new() -> Result<Self, Unspecified> {
let mut iv_bytes = [0u8; L];
rand::fill(&mut iv_bytes)?;
Ok(Self(iv_bytes))
}
}
impl<const L: usize> Drop for FixedLength<L> {
fn drop(&mut self) {
self.0.zeroize();
}
}
impl<const L: usize> AsRef<[u8; L]> for FixedLength<L> {
#[inline]
fn as_ref(&self) -> &[u8; L] {
&self.0
}
}
impl<const L: usize> From<&[u8; L]> for FixedLength<L> {
#[inline]
fn from(bytes: &[u8; L]) -> Self {
FixedLength(bytes.to_owned())
}
}
impl<const L: usize> From<[u8; L]> for FixedLength<L> {
#[inline]
fn from(bytes: [u8; L]) -> Self {
FixedLength(bytes)
}
}
impl<const L: usize> TryFrom<&[u8]> for FixedLength<L> {
type Error = Unspecified;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
let value: &[u8; L] = value.try_into()?;
Ok(Self::from(*value))
}
}
impl<const L: usize> TryFrom<FixedLength<L>> for [u8; L] {
type Error = Unspecified;
fn try_from(value: FixedLength<L>) -> Result<Self, Self::Error> {
Ok(value.0)
}
}
#[cfg(test)]
mod tests {
use crate::iv::FixedLength;
#[test]
fn test_size() {
let fixed = FixedLength::from([0u8; 16]);
assert_eq!(16, fixed.size());
let array = [0u8; 12];
let fixed = FixedLength::<12>::try_from(array.as_slice()).unwrap();
assert_eq!(12, fixed.size());
assert!(FixedLength::<16>::try_from(array.as_slice()).is_err());
assert!(TryInto::<[u8; 12]>::try_into(fixed).is_ok());
}
}