| // 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()); |
| } |
| } |