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> {
39 let mut password_salt = new_arr::<32>();
40 rng.try_fill_bytes(password_salt.as_mut())?;
41
42 let aes_key = kdf(password, password_salt.as_ref());
43 let password_verification_hash = compute_verification_hash(&aes_key);
44
45 let mut iv = [0; 16];
46 rng.try_fill_bytes(&mut iv)?;
47
48 let aes = Aes256Ctr::new(aes_key.as_ref().get_ref().into(), (&iv).into());
49
50 Ok(Self {
51 read,
52 aes,
53 password_salt,
54 password_verification_hash,
55 integrity_code: Some(HmacSha3_256::new_from_slice(aes_key.as_ref().get_ref()).unwrap()),
56 state: EncryptState::PreHeader,
57 block_buffer: BytesMut::new(),
58 iv
59 })
60 }
61}
62
63impl<E, R: Stream<Item = Result<Bytes, E>>> Stream for Encrypt<R> {
64 type Item = Result<Bytes, E>;
65
66 fn poll_next(
67 self: Pin<&mut Self>,
68 cx: &mut Context<'_>
69 ) -> Poll<Option<Self::Item>> {
70 let mut this = self.project();
71
72 loop {
73 match this.state {
74 EncryptState::PreHeader => {
75 let mut buf = Vec::with_capacity(
76 4 + 1 + 1 + 32 + 64 + 16 );
83
84 buf.extend_from_slice(b"SSEC");
85 buf.push(0x01);
86 buf.push(0x6e);
87 buf.extend_from_slice(this.password_salt.as_ref());
88 buf.extend_from_slice(this.password_verification_hash.as_ref());
89 buf.extend_from_slice(this.iv.as_ref());
90
91 let integrity_code = this.integrity_code.as_mut().unwrap();
93 integrity_code.update(&[0x01, 0x6e]);
94 integrity_code.update(this.iv.as_ref());
95
96 match this.read.poll_next(cx) {
97 Poll::Pending => *this.state = EncryptState::PostHeader,
98 Poll::Ready(None) => *this.state = EncryptState::Finalizing,
99 Poll::Ready(Some(Err(e))) => {
100 *this.state = EncryptState::Finished;
101 return Poll::Ready(Some(Err(e)));
102 },
103 Poll::Ready(Some(Ok(bytes))) => {
104 *this.state = EncryptState::PostHeader;
105 this.block_buffer.put(bytes);
106 }
107 }
108
109 return Poll::Ready(Some(Ok(Bytes::from_owner(buf))));
110 },
111 EncryptState::PostHeader => {
112 if this.block_buffer.len() >= BYTES_PER_POLL {
113 let mut data = this.block_buffer.split_to(BYTES_PER_POLL);
114 this.aes.apply_keystream(&mut data);
115 this.integrity_code.as_mut().unwrap().update(&data);
116
117 return Poll::Ready(Some(Ok(data.freeze())));
118 } else {
119 match ready!(this.read.as_mut().poll_next(cx)) {
120 Some(Ok(bytes)) => {
121 this.block_buffer.put(bytes);
122 continue;
123 },
124 Some(Err(e)) => {
125 *this.state = EncryptState::Finished;
126 return Poll::Ready(Some(Err(e)));
127 },
128 None => {
129 *this.state = EncryptState::Finalizing;
130 continue;
131 }
132 }
133 }
134 },
135 EncryptState::Finalizing => {
136 debug_assert!(this.block_buffer.len() < BYTES_PER_POLL);
137
138 let mut final_data = this.block_buffer.split();
139
140 let mut hmac = this.integrity_code.take()
141 .expect("integrity_code only taken here");
142
143 this.aes.apply_keystream(&mut final_data);
144
145 hmac.update(&final_data);
146 final_data.put(Bytes::from_owner(hmac.finalize().into_bytes()));
147
148 *this.state = EncryptState::Finished;
149
150 return Poll::Ready(Some(Ok(final_data.freeze())));
151 },
152 EncryptState::Finished => return Poll::Ready(None)
153 }
154 }
155 }
156}