-
-
Notifications
You must be signed in to change notification settings - Fork 88
feat: adaugat structura de baza pentru ipfs_plugin #324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
6abd836
29c1c5e
cb3572e
f2bd2b5
12db078
b3a0ae8
8f2ac30
bfa24f2
a68daaf
7c130ee
f6f579b
eeb8772
02f0364
387034e
23d95a0
1a0fb47
5ba0476
9fea777
59a632e
aa3a2f7
06580f3
f7e7842
7dfa5b3
a165ef8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| use crate::crypto::write::CryptoWrite; // Resolves the error with .finish() | ||
| use crate::crypto::{self, Cipher}; | ||
| use shush_rs::SecretVec; | ||
| use std::io::{Cursor, Read, Write, Error, ErrorKind, Result}; | ||
| use std::sync::Mutex; // Required for reusable decryption buffer | ||
|
|
||
| pub struct IpfsCipher { | ||
| key: SecretVec<u8>, | ||
| cipher: Cipher, | ||
| dec_buffer: Mutex<Vec<u8>>, // Reusable buffer for decryption | ||
| } | ||
|
|
||
| impl IpfsCipher { | ||
| /// Initializes the plugin with a secure key and the default cipher | ||
| pub fn new(secret_key: Vec<u8>) -> Self { | ||
| // Validate key length to prevent downstream library panics (Point 3 in review) | ||
| assert_eq!( | ||
| secret_key.len(), | ||
| 32, | ||
| "Invalid key length for ChaCha20Poly1305. Expected exactly 32 bytes." | ||
| ); | ||
|
|
||
| Self { | ||
| key: SecretVec::from(secret_key), | ||
| cipher: Cipher::ChaCha20Poly1305, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hardcoding
Generated by Claude Code |
||
| dec_buffer: Mutex::new(Vec::with_capacity(1024 * 64)), // Pre-allocate 64KB | ||
| } | ||
| } | ||
|
|
||
| /// Encrypts a block of data using a Cursor to simulate an in-memory file | ||
| pub fn encrypt(&self, data: &[u8]) -> Result<Vec<u8>> { | ||
| if data.is_empty() { | ||
| return Ok(Vec::new()); | ||
| } | ||
|
|
||
| // Pre-allocate capacity matching data size to satisfy 'static bounds without reallocation churn | ||
| let estimated_capacity = data.len() + 256; | ||
| let memory_file = Cursor::new(Vec::with_capacity(estimated_capacity)); | ||
| let mut writer = crypto::create_write(memory_file, self.cipher, &self.key); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Every Because Cheaper: cache reusable cipher state in Generated by Claude Code |
||
|
|
||
| writer | ||
| .write_all(data) | ||
| .map_err(|e| Error::new(ErrorKind::Other, format!("Error writing IPFS data: {:?}", e)))?; | ||
|
|
||
| // .finish() returns the internal object (the Cursor) on success | ||
| let finished_cursor = writer | ||
| .finish() | ||
| .map_err(|e| Error::new(ErrorKind::Other, format!("Error finalizing IPFS encryption: {:?}", e)))?; | ||
|
|
||
| // Extract the byte vector from the inner cursor | ||
| Ok(finished_cursor.into_inner()) | ||
| } | ||
|
|
||
| /// Decrypts a block of data using the native CryptoRead from rencfs | ||
| pub fn decrypt(&self, encrypted_data: &[u8]) -> Result<Vec<u8>> { | ||
| if encrypted_data.is_empty() { | ||
| return Ok(Vec::new()); | ||
| } | ||
|
|
||
| let mut buffer_guard = self.dec_buffer.lock().map_err(|_| { | ||
| Error::new(ErrorKind::Other, "Failed to lock decryption buffer lock") | ||
| })?; | ||
| buffer_guard.clear(); | ||
|
|
||
| let mut reader = crypto::create_read(encrypted_data, self.cipher, &self.key); | ||
|
|
||
| reader | ||
| .read_to_end(&mut *buffer_guard) | ||
| .map_err(|e| Error::new(ErrorKind::Other, format!("Error decrypting IPFS data: {:?}", e)))?; | ||
|
|
||
| Ok(buffer_guard.to_vec()) | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn test_ipfs_encryption_decryption() { | ||
| // Generate a 32-byte test key (required for ChaCha20Poly1305) | ||
| let test_key = vec![0u8; 32]; | ||
| let cipher = IpfsCipher::new(test_key); | ||
|
|
||
| let original_data = b"Secret data sent via IPFS with a unique CID!"; | ||
|
|
||
| // 1. Encrypt the data | ||
| let encrypted = cipher.encrypt(original_data).expect("Encryption failed"); | ||
| assert_ne!( | ||
| original_data.to_vec(), | ||
| encrypted, | ||
| "Encrypted data must not match the original data" | ||
| ); | ||
|
|
||
| // 2. Decrypt the data back | ||
| let decrypted = cipher.decrypt(&encrypted).expect("Decryption failed"); | ||
| assert_eq!( | ||
| original_data.to_vec(), | ||
| decrypted, | ||
| "Decrypted data does not match the original data" | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
| #[should_panic(expected = "Invalid key length")] | ||
| fn test_invalid_key_length_panics() { | ||
| // Test that an invalid key length triggers the validation assert | ||
| let short_key = vec![0u8; 16]; | ||
| let _cipher = IpfsCipher::new(short_key); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -326,3 +326,6 @@ pub const fn is_debug() -> bool { | |
| } | ||
| false | ||
| } | ||
|
|
||
| #[path = "../ipfs_plugin/src/lib.rs"] | ||
| pub mod ipfs_plugin; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
The repo already has the right pattern for an integration bridge: Generated by Claude Code |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No key-length validation — a wrong-length key panics (and aborts the process in release builds) despite the
Resultsignature.new()accepts anyVec<u8>. The firstencrypt()/decrypt()then reachesUnboundKey::new(algorithm, &key.expose_secret()).expect("unbound key")(src/crypto/write.rs:92, and the.unwrap()at read.rs:93); ring returnsErrfor any key that isn't exactlyCipher::key_len()bytes (32 here), so the.expectfires. With[profile.release] panic = "abort", that's a full process abort — from a safe public API whose methods promiseResult<_, String>. Every existing key path avoids this becausecrypto::derive_keysizes the key tocipher.key_len(); this constructor is the only way to smuggle in a bad length.Validate in
new()(returnResultand checksecret_key.len() == self.cipher.key_len()), or better, acceptSecretVec<u8>from a source that already guarantees the length.Generated by Claude Code