1use super::CtrFlavor;
3use cipher::{
4 array::{Array, ArraySize},
5 typenum::{PartialDiv, PartialQuot, U4, Unsigned},
6};
7use core::fmt;
8
9type ChunkSize = U4;
10type Chunks<B> = PartialQuot<B, ChunkSize>;
11const CS: usize = ChunkSize::USIZE;
12
13#[derive(Clone)]
14pub struct CtrNonce32<N: ArraySize> {
15 ctr: u32,
16 nonce: Array<u32, N>,
17}
18
19impl<N: ArraySize> fmt::Debug for CtrNonce32<N> {
20 #[inline]
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 f.write_str("CtrNonce32 { ... }")
23 }
24}
25
26impl<N: ArraySize> Drop for CtrNonce32<N> {
27 fn drop(&mut self) {
28 #[cfg(feature = "zeroize")]
29 {
30 use cipher::zeroize::Zeroize;
31 self.ctr.zeroize();
32 self.nonce.zeroize();
33 }
34 }
35}
36
37#[cfg(feature = "zeroize")]
38impl<N: ArraySize> cipher::zeroize::ZeroizeOnDrop for CtrNonce32<N> {}
39
40#[derive(Clone, Copy, Debug)]
42pub enum Ctr32BE {}
43
44impl<B> CtrFlavor<B> for Ctr32BE
45where
46 B: ArraySize + PartialDiv<ChunkSize>,
47 Chunks<B>: ArraySize,
48{
49 type CtrNonce = CtrNonce32<Chunks<B>>;
50 type Backend = u32;
51 const NAME: &'static str = "32BE";
52
53 #[inline]
54 fn remaining(cn: &Self::CtrNonce) -> Option<usize> {
55 (u32::MAX - cn.ctr).try_into().ok()
56 }
57
58 #[inline(always)]
59 fn current_block(cn: &Self::CtrNonce) -> Array<u8, B> {
60 let mut block = Array::<u8, B>::default();
61 for i in 0..Chunks::<B>::USIZE {
62 let t = if i == Chunks::<B>::USIZE - 1 {
63 cn.ctr.wrapping_add(cn.nonce[i]).to_be_bytes()
64 } else {
65 cn.nonce[i].to_ne_bytes()
66 };
67 block[CS * i..][..CS].copy_from_slice(&t);
68 }
69 block
70 }
71
72 #[inline]
73 fn next_block(cn: &mut Self::CtrNonce) -> Array<u8, B> {
74 let block = Self::current_block(cn);
75 cn.ctr = cn.ctr.wrapping_add(1);
76 block
77 }
78
79 #[inline]
80 fn from_nonce(block: &Array<u8, B>) -> Self::CtrNonce {
81 let mut nonce = Array::<u32, Chunks<B>>::default();
82 for i in 0..Chunks::<B>::USIZE {
83 let chunk = block[CS * i..][..CS]
84 .try_into()
85 .expect("should be the correct size");
86 nonce[i] = if i == Chunks::<B>::USIZE - 1 {
87 u32::from_be_bytes(chunk)
88 } else {
89 u32::from_ne_bytes(chunk)
90 }
91 }
92 let ctr = 0;
93 Self::CtrNonce { ctr, nonce }
94 }
95
96 #[inline]
97 fn as_backend(cn: &Self::CtrNonce) -> Self::Backend {
98 cn.ctr
99 }
100
101 #[inline]
102 fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) {
103 cn.ctr = v;
104 }
105}
106
107#[derive(Clone, Copy, Debug)]
109pub enum Ctr32LE {}
110
111impl<B> CtrFlavor<B> for Ctr32LE
112where
113 B: ArraySize + PartialDiv<ChunkSize>,
114 Chunks<B>: ArraySize,
115{
116 type CtrNonce = CtrNonce32<Chunks<B>>;
117 type Backend = u32;
118 const NAME: &'static str = "32LE";
119
120 #[inline]
121 fn remaining(cn: &Self::CtrNonce) -> Option<usize> {
122 (u32::MAX - cn.ctr).try_into().ok()
123 }
124
125 #[inline(always)]
126 fn current_block(cn: &Self::CtrNonce) -> Array<u8, B> {
127 let mut block = Array::<u8, B>::default();
128 for i in 0..Chunks::<B>::USIZE {
129 let t = if i == 0 {
130 cn.ctr.wrapping_add(cn.nonce[i]).to_le_bytes()
131 } else {
132 cn.nonce[i].to_ne_bytes()
133 };
134 block[CS * i..][..CS].copy_from_slice(&t);
135 }
136 block
137 }
138
139 #[inline]
140 fn next_block(cn: &mut Self::CtrNonce) -> Array<u8, B> {
141 let block = Self::current_block(cn);
142 cn.ctr = cn.ctr.wrapping_add(1);
143 block
144 }
145
146 #[inline]
147 fn from_nonce(block: &Array<u8, B>) -> Self::CtrNonce {
148 let mut nonce = Array::<u32, Chunks<B>>::default();
149 for i in 0..Chunks::<B>::USIZE {
150 let chunk = block[CS * i..][..CS]
151 .try_into()
152 .expect("should be the correct size");
153 nonce[i] = if i == 0 {
154 u32::from_le_bytes(chunk)
155 } else {
156 u32::from_ne_bytes(chunk)
157 }
158 }
159 let ctr = 0;
160 Self::CtrNonce { ctr, nonce }
161 }
162
163 #[inline]
164 fn as_backend(cn: &Self::CtrNonce) -> Self::Backend {
165 cn.ctr
166 }
167
168 #[inline]
169 fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) {
170 cn.ctr = v;
171 }
172}