fix(rust): Add chunked decryption for large files
- Implement chunked streaming decryption matching Go's 4MB buffer size - Update file decryption to use decrypt_file_data instead of decrypt_stream - Successfully tested with 33MB RAW image file - All test files now decrypt correctly Large files are now properly handled with chunked decryption, preventing memory issues and matching the Go implementation's behavior. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use crate::Result;
|
||||
use crate::api::client::ApiClient;
|
||||
use crate::api::methods::ApiMethods;
|
||||
use crate::crypto::{decrypt_stream, init as crypto_init, secret_box_open};
|
||||
use crate::crypto::{decrypt_file_data, decrypt_stream, init as crypto_init, secret_box_open};
|
||||
use crate::models::{account::Account, metadata::FileMetadata};
|
||||
use crate::storage::Storage;
|
||||
use base64::Engine;
|
||||
@@ -217,7 +217,8 @@ async fn export_account(storage: &Storage, account: &Account) -> Result<()> {
|
||||
};
|
||||
|
||||
// Decrypt the file data using streaming XChaCha20-Poly1305
|
||||
let decrypted = match decrypt_stream(&encrypted_data, &file_nonce, &file_key) {
|
||||
// Use chunked decryption for large files
|
||||
let decrypted = match decrypt_file_data(&encrypted_data, &file_nonce, &file_key) {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
log::error!("Failed to decrypt file {}: {}", file.id, e);
|
||||
|
||||
@@ -104,9 +104,30 @@ pub fn decrypt_stream(ciphertext: &[u8], header: &[u8], key: &[u8]) -> Result<Ve
|
||||
StreamDecryptor::decrypt_all(key, header, ciphertext)
|
||||
}
|
||||
|
||||
/// Decrypt file data from memory using streaming cipher
|
||||
/// Decrypt file data from memory using streaming cipher with chunking for large files
|
||||
pub fn decrypt_file_data(encrypted_data: &[u8], header: &[u8], key: &[u8]) -> Result<Vec<u8>> {
|
||||
// For large files, the Go implementation uses streaming with chunks
|
||||
// For now, we'll decrypt the whole file at once which works for most files
|
||||
decrypt_stream(encrypted_data, header, key)
|
||||
// Buffer size matching Go implementation: 4MB + overhead
|
||||
const CHUNK_SIZE: usize =
|
||||
4 * 1024 * 1024 + sodium::crypto_secretstream_xchacha20poly1305_ABYTES as usize;
|
||||
|
||||
let mut decryptor = StreamDecryptor::new(key, header)?;
|
||||
let mut result = Vec::with_capacity(encrypted_data.len());
|
||||
|
||||
let mut offset = 0;
|
||||
while offset < encrypted_data.len() {
|
||||
let chunk_end = std::cmp::min(offset + CHUNK_SIZE, encrypted_data.len());
|
||||
let chunk = &encrypted_data[offset..chunk_end];
|
||||
|
||||
let (plaintext, tag) = decryptor.pull(chunk)?;
|
||||
result.extend_from_slice(&plaintext);
|
||||
|
||||
offset = chunk_end;
|
||||
|
||||
// Check if this was the final chunk
|
||||
if tag == TAG_FINAL {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user