1use futures_core::Stream;
2use bytes::{Bytes, BytesMut, BufMut};
3use rand_core::TryCryptoRng;
4use ctr::cipher::{KeyIvInit, StreamCipher};
5use hmac::{Mac, KeyInit};
6use core::pin::Pin;
7use core::task::{Context, Poll, ready};
8use crate::util::{HmacSha3_256, new_arr, kdf, compute_verification_hash};
9use crate::{BYTES_PER_POLL, Aes256Ctr};
10
11enum EncryptState {
12 PreHeader,
13 PostHeader,
14 Finalizing,
15 Finished
16}
17
18pin_project_lite::pin_project! {
19 pub struct Encrypt<R> {
20 #[pin]
21 read: R,
22 aes: Aes256Ctr,
23 password_salt: Box<[u8; 32]>,
24 password_verification_hash: Box<[u8; 64]>,
25 integrity_code: Option<HmacSha3_256>,
26 state: EncryptState,
27 block_buffer: BytesMut,
28 iv: [u8; 16]
29 }
30}
31
32impl<R> Encrypt<R> {
33 pub fn new_uncompressed<RNG: TryCryptoRng>(read: R, password: &[u8], rng: &mut RNG) -> Result<Self, RNG::Error> {
38 let mut password_salt = new_arr::<32>();
39 rng.try_fill_bytes(password_salt.as_mut())?;
40
41 let aes_key = kdf(password, password_salt.as_ref());
42 let password_verification_hash = compute_verification_hash(&aes_key);
43
44 let mut iv = [0; 16];
45 rng.try_fill_bytes(&mut iv)?;
46
47 let aes = Aes256Ctr::new(aes_key.as_ref().get_ref().into(), (&iv).into());
48
49 Ok(Self {
50 read,
51 aes,
52 password_salt,
53 password_verification_hash,
54 integrity_code: Some(HmacSha3_256::new_from_slice(aes_key.as_ref().get_ref()).unwrap()),
55 state: EncryptState::PreHeader,
56 block_buffer: BytesMut::new(),
57 iv
58 })
59 }
60}
61
62impl<E, R: Stream<Item = Result<Bytes, E>>> Stream for Encrypt<R> {
63 type Item = Result<Bytes, E>;
64
65 fn poll_next(
66 self: Pin<&mut Self>,
67 cx: &mut Context<'_>
68 ) -> Poll<Option<Self::Item>> {
69 let mut this = self.project();
70
71 loop {
72 match this.state {
73 EncryptState::PreHeader => {
74 let mut buf = Vec::with_capacity(
75 4 + 1 + 1 + 32 + 64 + 16 );
82
83 buf.extend_from_slice(b"SSEC");
84 buf.push(0x01);
85 buf.push(0x6e);
86 buf.extend_from_slice(this.password_salt.as_ref());
87 buf.extend_from_slice(this.password_verification_hash.as_ref());
88 buf.extend_from_slice(this.iv.as_ref());
89
90 let integrity_code = this.integrity_code.as_mut().unwrap();
92 integrity_code.update(&[0x01, 0x6e]);
93 integrity_code.update(this.iv.as_ref());
94
95 match this.read.poll_next(cx) {
96 Poll::Pending => *this.state = EncryptState::PostHeader,
97 Poll::Ready(None) => *this.state = EncryptState::Finalizing,
98 Poll::Ready(Some(Err(e))) => {
99 *this.state = EncryptState::Finished;
100 return Poll::Ready(Some(Err(e)));
101 },
102 Poll::Ready(Some(Ok(bytes))) => {
103 *this.state = EncryptState::PostHeader;
104 this.block_buffer.put(bytes);
105 }
106 }
107
108 return Poll::Ready(Some(Ok(Bytes::from_owner(buf))));
109 },
110 EncryptState::PostHeader => {
111 if this.block_buffer.len() >= BYTES_PER_POLL {
112 let mut data = this.block_buffer.split_to(BYTES_PER_POLL);
113 this.aes.apply_keystream(&mut data);
114 this.integrity_code.as_mut().unwrap().update(&data);
115
116 return Poll::Ready(Some(Ok(data.freeze())));
117 } else {
118 match ready!(this.read.as_mut().poll_next(cx)) {
119 Some(Ok(bytes)) => {
120 this.block_buffer.put(bytes);
121 continue;
122 },
123 Some(Err(e)) => {
124 *this.state = EncryptState::Finished;
125 return Poll::Ready(Some(Err(e)));
126 },
127 None => {
128 *this.state = EncryptState::Finalizing;
129 continue;
130 }
131 }
132 }
133 },
134 EncryptState::Finalizing => {
135 debug_assert!(this.block_buffer.len() < BYTES_PER_POLL);
136
137 let mut final_data = this.block_buffer.split();
138
139 let mut hmac = this.integrity_code.take()
140 .expect("integrity_code only taken here");
141
142 this.aes.apply_keystream(&mut final_data);
143
144 hmac.update(&final_data);
145 final_data.put(Bytes::from_owner(hmac.finalize().into_bytes()));
146
147 *this.state = EncryptState::Finished;
148
149 return Poll::Ready(Some(Ok(final_data.freeze())));
150 },
151 EncryptState::Finished => return Poll::Ready(None)
152 }
153 }
154 }
155}