1#![allow(dead_code)]
6
7use crate::error::Unspecified;
10use crate::rand;
11use zeroize::Zeroize;
12
13#[cfg(feature = "legacy-des")]
15pub(crate) const IV_LEN_64_BIT: usize = 8;
16
17pub const IV_LEN_128_BIT: usize = 16;
19
20pub struct FixedLength<const L: usize>([u8; L]);
23
24impl<const L: usize> FixedLength<L> {
25 #[allow(clippy::must_use_candidate)]
27 pub fn size(&self) -> usize {
28 L
29 }
30
31 pub fn new() -> Result<Self, Unspecified> {
37 let mut iv_bytes = [0u8; L];
38 rand::fill(&mut iv_bytes)?;
39 Ok(Self(iv_bytes))
40 }
41}
42
43impl<const L: usize> Drop for FixedLength<L> {
44 fn drop(&mut self) {
45 self.0.zeroize();
46 }
47}
48
49impl<const L: usize> AsRef<[u8; L]> for FixedLength<L> {
50 #[inline]
51 fn as_ref(&self) -> &[u8; L] {
52 &self.0
53 }
54}
55
56impl<const L: usize> From<&[u8; L]> for FixedLength<L> {
57 #[inline]
58 fn from(bytes: &[u8; L]) -> Self {
59 FixedLength(bytes.to_owned())
60 }
61}
62
63impl<const L: usize> From<[u8; L]> for FixedLength<L> {
64 #[inline]
65 fn from(bytes: [u8; L]) -> Self {
66 FixedLength(bytes)
67 }
68}
69
70impl<const L: usize> TryFrom<&[u8]> for FixedLength<L> {
71 type Error = Unspecified;
72
73 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
74 let value: &[u8; L] = value.try_into()?;
75 Ok(Self::from(*value))
76 }
77}
78
79impl<const L: usize> TryFrom<FixedLength<L>> for [u8; L] {
80 type Error = Unspecified;
81
82 fn try_from(value: FixedLength<L>) -> Result<Self, Self::Error> {
83 Ok(value.0)
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use crate::iv::FixedLength;
90
91 #[test]
92 fn test_size() {
93 let fixed = FixedLength::from([0u8; 16]);
94 assert_eq!(16, fixed.size());
95
96 let array = [0u8; 12];
97 let fixed = FixedLength::<12>::try_from(array.as_slice()).unwrap();
98 assert_eq!(12, fixed.size());
99
100 assert!(FixedLength::<16>::try_from(array.as_slice()).is_err());
101
102 assert!(TryInto::<[u8; 12]>::try_into(fixed).is_ok());
103 }
104}