|
1 |
| -use anyhow::anyhow; |
2 |
| -use chacha20poly1305::{ |
3 |
| - aead::{ |
4 |
| - generic_array::GenericArray, |
5 |
| - stream::{DecryptorBE32, EncryptorBE32}, |
6 |
| - KeyInit, |
7 |
| - }, |
8 |
| - consts::U32, |
9 |
| - XChaCha20Poly1305, |
10 |
| -}; |
11 | 1 | use sdk::util::{
|
| 2 | + crypto::{decrypt_file, encrypt_file, KeyNonce}, |
12 | 3 | file::{add_extension, add_parent_dir, rm_extra_extension},
|
13 | 4 | random::generate_random_string_with_prefix,
|
14 | 5 | };
|
15 | 6 | use std::path::{Path, PathBuf};
|
16 |
| -use tokio::{ |
17 |
| - fs::File, |
18 |
| - io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, |
19 |
| -}; |
20 |
| - |
21 |
| -#[derive(Debug, Clone, Copy)] |
22 |
| -pub struct KeyType(GenericArray<u8, U32>); |
23 |
| - |
24 |
| -impl KeyType { |
25 |
| - pub fn new(key: &str) -> anyhow::Result<Self> { |
26 |
| - let key: [u8; 32] = key |
27 |
| - .as_bytes() |
28 |
| - .try_into() |
29 |
| - .map_err(|_e| anyhow::anyhow!("The key length should be 32 characters."))?; |
30 |
| - |
31 |
| - Ok(Self(GenericArray::from_iter(key))) |
32 |
| - } |
33 |
| -} |
34 |
| - |
35 |
| -impl std::ops::Deref for KeyType { |
36 |
| - type Target = GenericArray<u8, U32>; |
37 |
| - |
38 |
| - fn deref(&self) -> &Self::Target { |
39 |
| - &self.0 |
40 |
| - } |
41 |
| -} |
42 |
| - |
43 |
| -#[derive(Debug, Clone, Copy)] |
44 |
| -pub struct NonceType([u8; 19]); |
45 |
| - |
46 |
| -impl NonceType { |
47 |
| - pub fn new(nonce: &str) -> anyhow::Result<Self> { |
48 |
| - let nonce: [u8; 19] = nonce |
49 |
| - .as_bytes() |
50 |
| - .try_into() |
51 |
| - .map_err(|_e| anyhow::anyhow!("The nonce length should be 19 characters."))?; |
52 |
| - |
53 |
| - Ok(Self(nonce)) |
54 |
| - } |
55 |
| -} |
56 |
| - |
57 |
| -impl std::ops::Deref for NonceType { |
58 |
| - type Target = [u8; 19]; |
59 |
| - |
60 |
| - fn deref(&self) -> &Self::Target { |
61 |
| - &self.0 |
62 |
| - } |
63 |
| -} |
64 |
| - |
65 |
| -#[derive(Debug, Clone, Copy)] |
66 |
| -pub struct KeyNonce { |
67 |
| - pub key: KeyType, |
68 |
| - pub nonce: NonceType, |
69 |
| -} |
70 | 7 |
|
71 | 8 | pub async fn encrypt_upload_file(
|
72 | 9 | key_nonce: &KeyNonce,
|
@@ -100,106 +37,16 @@ pub async fn decrypt_download_file(
|
100 | 37 | Ok(())
|
101 | 38 | }
|
102 | 39 |
|
103 |
| -pub async fn encrypt_file( |
104 |
| - key_nonce: &KeyNonce, |
105 |
| - plaintext_file: impl AsRef<Path>, |
106 |
| - destination_file: impl AsRef<Path>, |
107 |
| -) -> anyhow::Result<()> { |
108 |
| - let reader = File::open(plaintext_file).await?; |
109 |
| - let writer = File::create(destination_file).await?; |
110 |
| - encrypt(key_nonce, reader, writer).await?; |
111 |
| - Ok(()) |
112 |
| -} |
113 |
| - |
114 |
| -pub async fn decrypt_file( |
115 |
| - key_nonce: &KeyNonce, |
116 |
| - encrypted_file: impl AsRef<Path>, |
117 |
| - destination_file: impl AsRef<Path>, |
118 |
| -) -> anyhow::Result<()> { |
119 |
| - let reader = File::open(encrypted_file).await?; |
120 |
| - let writer = File::create(destination_file).await?; |
121 |
| - decrypt(key_nonce, reader, writer).await?; |
122 |
| - Ok(()) |
123 |
| -} |
124 |
| - |
125 |
| -pub async fn encrypt<R, W>( |
126 |
| - KeyNonce { key, nonce }: &KeyNonce, |
127 |
| - mut reader: R, |
128 |
| - mut writer: W, |
129 |
| -) -> anyhow::Result<()> |
130 |
| -where |
131 |
| - R: AsyncRead + Unpin, |
132 |
| - W: AsyncWrite + Unpin, |
133 |
| -{ |
134 |
| - const BUFFER_LEN: usize = 500; |
135 |
| - let mut buffer = [0u8; BUFFER_LEN]; |
136 |
| - let mut stream_encryptor = |
137 |
| - EncryptorBE32::from_aead(XChaCha20Poly1305::new(key), (*nonce).as_ref().into()); |
138 |
| - loop { |
139 |
| - let read_count = reader.read(&mut buffer).await?; |
140 |
| - if read_count == BUFFER_LEN { |
141 |
| - let ciphertext = stream_encryptor |
142 |
| - .encrypt_next(buffer.as_slice()) |
143 |
| - .map_err(|err| anyhow!("Encrypting file failed, Error: {err}"))?; |
144 |
| - writer.write_all(&ciphertext).await?; |
145 |
| - } else if read_count == 0 { |
146 |
| - break; |
147 |
| - } else { |
148 |
| - let ciphertext = stream_encryptor |
149 |
| - .encrypt_last(&buffer[..read_count]) |
150 |
| - .map_err(|err| anyhow!("Encrypting file failed, Error: {err}"))?; |
151 |
| - writer.write_all(&ciphertext).await?; |
152 |
| - break; |
153 |
| - } |
154 |
| - } |
155 |
| - writer.flush().await?; |
156 |
| - |
157 |
| - Ok(()) |
158 |
| -} |
159 |
| - |
160 |
| -pub async fn decrypt<R, W>( |
161 |
| - KeyNonce { key, nonce }: &KeyNonce, |
162 |
| - mut reader: R, |
163 |
| - mut writer: W, |
164 |
| -) -> anyhow::Result<()> |
165 |
| -where |
166 |
| - R: AsyncRead + Unpin, |
167 |
| - W: AsyncWrite + Unpin, |
168 |
| -{ |
169 |
| - const BUFFER_LEN: usize = 500 + 16; |
170 |
| - let mut buffer = [0u8; BUFFER_LEN]; |
171 |
| - let mut stream_decryptor = |
172 |
| - DecryptorBE32::from_aead(XChaCha20Poly1305::new(key), nonce.as_ref().into()); |
173 |
| - |
174 |
| - loop { |
175 |
| - let read_count = reader.read(&mut buffer).await?; |
176 |
| - if read_count == BUFFER_LEN { |
177 |
| - let plaintext = stream_decryptor |
178 |
| - .decrypt_next(buffer.as_slice()) |
179 |
| - .map_err(|err| anyhow!("Decrypting file failed, Error: {err}"))?; |
180 |
| - writer.write_all(&plaintext).await?; |
181 |
| - } else if read_count == 0 { |
182 |
| - break; |
183 |
| - } else { |
184 |
| - let plaintext = stream_decryptor |
185 |
| - .decrypt_last(&buffer[..read_count]) |
186 |
| - .map_err(|err| anyhow!("Decrypting file failed, Error: {err}"))?; |
187 |
| - writer.write_all(&plaintext).await?; |
188 |
| - break; |
189 |
| - } |
190 |
| - } |
191 |
| - writer.flush().await?; |
192 |
| - |
193 |
| - Ok(()) |
194 |
| -} |
195 |
| - |
196 | 40 | #[cfg(test)]
|
197 | 41 | mod tests {
|
198 | 42 |
|
199 | 43 | use fake::{Fake, Faker};
|
200 | 44 | use test_context::test_context;
|
201 | 45 |
|
202 |
| - use crate::util::test::FileTestContext; |
| 46 | + use sdk::util::{ |
| 47 | + crypto::{KeyType, NonceType}, |
| 48 | + test::FileTestContext, |
| 49 | + }; |
203 | 50 |
|
204 | 51 | use super::*;
|
205 | 52 |
|
@@ -227,27 +74,4 @@ mod tests {
|
227 | 74 | let actual_contents = tokio::fs::read_to_string(plaintext_file).await.unwrap();
|
228 | 75 | assert_eq!(contents, actual_contents)
|
229 | 76 | }
|
230 |
| - |
231 |
| - #[test_context(FileTestContext)] |
232 |
| - #[tokio::test] |
233 |
| - pub async fn test_encrypt_file_and_decrypt_file(ctx: &mut FileTestContext) { |
234 |
| - let key_nonce = KeyNonce { |
235 |
| - key: KeyType::new("01234567890123456789012345678912").unwrap(), |
236 |
| - nonce: NonceType::new("1234567891213141516").unwrap(), |
237 |
| - }; |
238 |
| - let contents = Faker.fake::<String>(); |
239 |
| - |
240 |
| - let plaintext_file = ctx.temp_path.join("file.txt"); |
241 |
| - tokio::fs::write(&plaintext_file, &contents).await.unwrap(); |
242 |
| - let ciphertext_file = ctx.temp_path.join("file.bin"); |
243 |
| - encrypt_file(&key_nonce, &plaintext_file, &ciphertext_file) |
244 |
| - .await |
245 |
| - .unwrap(); |
246 |
| - let result_file = ctx.temp_path.join("result_file.txt"); |
247 |
| - decrypt_file(&key_nonce, &ciphertext_file, &result_file) |
248 |
| - .await |
249 |
| - .unwrap(); |
250 |
| - let actual_contents = tokio::fs::read_to_string(result_file).await.unwrap(); |
251 |
| - assert_eq!(contents, actual_contents) |
252 |
| - } |
253 | 77 | }
|
0 commit comments