Skip to content

Commit 298bcf0

Browse files
committed
move crypto to sdk
1 parent a2fb4cd commit 298bcf0

File tree

10 files changed

+211
-195
lines changed

10 files changed

+211
-195
lines changed

cli/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,4 @@ url = { workspace = true }
2222
tracing-subscriber = { workspace = true }
2323
base64 = { workspace = true }
2424
cuid2 = { workspace = true }
25-
chacha20poly1305 = { workspace = true }
2625
indicatif = { workspace = true }

cli/src/args.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
use clap::{Parser, Subcommand, ValueEnum};
2-
use sdk::dto::FileUrlPath;
2+
use sdk::{dto::FileUrlPath, util::crypto::KeyNonce};
33

44
use std::path::PathBuf;
55

6-
use crate::{
7-
parse::{
8-
parse_auth, parse_destination, parse_expire_time, parse_file_url_path, parse_key_nonce,
9-
parse_source_file,
10-
},
11-
util::crypto::KeyNonce,
6+
use crate::parse::{
7+
parse_auth, parse_destination, parse_expire_time, parse_file_url_path, parse_key_nonce,
8+
parse_source_file,
129
};
1310

1411
const HELP_ENCRYPT :&str = "The encrypt format should be `key:nonce`, with the key being 32 characters in length and the nonce being 19 characters.";

cli/src/command.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use sdk::{
44
response::{ApiResponseResult, BodyResponseError, MessageResponse, UploadResponse},
55
FileUrlPath,
66
},
7-
util::file::{add_extension, rm_extra_extension},
7+
util::{crypto::KeyNonce, file::{add_extension, rm_extra_extension}},
88
};
99
use std::path::{Path, PathBuf};
1010
use url::Url;
1111

12-
use crate::{args::UploadOutput, client::CommandLineClient, util::crypto::KeyNonce};
12+
use crate::{args::UploadOutput, client::CommandLineClient};
1313

1414
#[derive(Debug)]
1515
pub struct UploadArguments {
@@ -180,7 +180,7 @@ pub async fn encrypt_file(key_nonce: &KeyNonce, source_file: &Path, mut destinat
180180
"bin",
181181
));
182182
}
183-
crate::util::crypto::encrypt_file(key_nonce, source_file, destination)
183+
sdk::util::crypto::encrypt_file(key_nonce, source_file, destination)
184184
.await
185185
.unwrap();
186186
}
@@ -193,7 +193,7 @@ pub async fn decrypt_file(key_nonce: &KeyNonce, source_file: &Path, mut destinat
193193
if source_file == destination {
194194
panic!("Please specify the valid destination file path.")
195195
}
196-
crate::util::crypto::decrypt_file(key_nonce, source_file, destination)
196+
sdk::util::crypto::decrypt_file(key_nonce, source_file, destination)
197197
.await
198198
.unwrap();
199199
}

cli/src/parse.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{path::PathBuf, str::FromStr};
33
use anyhow::anyhow;
44
use sdk::dto::FileUrlPath;
55

6-
use crate::util::crypto::{KeyNonce, KeyType, NonceType};
6+
use sdk::util::crypto::{KeyNonce, KeyType, NonceType};
77

88
pub fn parse_key_nonce(input: &str) -> anyhow::Result<KeyNonce> {
99
let pos = input

cli/src/util/crypto.rs

Lines changed: 5 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,9 @@
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-
};
111
use sdk::util::{
2+
crypto::{decrypt_file, encrypt_file, KeyNonce},
123
file::{add_extension, add_parent_dir, rm_extra_extension},
134
random::generate_random_string_with_prefix,
145
};
156
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-
}
707

718
pub async fn encrypt_upload_file(
729
key_nonce: &KeyNonce,
@@ -100,106 +37,16 @@ pub async fn decrypt_download_file(
10037
Ok(())
10138
}
10239

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-
19640
#[cfg(test)]
19741
mod tests {
19842

19943
use fake::{Fake, Faker};
20044
use test_context::test_context;
20145

202-
use crate::util::test::FileTestContext;
46+
use sdk::util::{
47+
crypto::{KeyType, NonceType},
48+
test::FileTestContext,
49+
};
20350

20451
use super::*;
20552

@@ -227,27 +74,4 @@ mod tests {
22774
let actual_contents = tokio::fs::read_to_string(plaintext_file).await.unwrap();
22875
assert_eq!(contents, actual_contents)
22976
}
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-
}
25377
}

cli/src/util/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
pub mod crypto;
22
pub mod progress;
3-
pub mod test;

sdk/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,5 @@ mime_guess = { workspace = true }
2424
url = { workspace = true }
2525
qrcode = { workspace = true }
2626
image = { workspace = true }
27+
test-context = { workspace = true }
28+
chacha20poly1305 = { workspace = true }

0 commit comments

Comments
 (0)