Skip to content

Commit 3d4dff8

Browse files
committed
fix: sync fuzz targets with actual API
Fuzz targets were written against a different API and never compiled. Issues fixed: - ZeroKnowledgeEncryptor::new() returns Result, not Self - unwrap properly - ByteStorageError is an enum - use matches!() not .contains() - StorageEnvelope.checksum is [u8; 8] (xxHash3-64), not [u8; 32] - ByteStorage methods return u64/usize, not f64 for ratios All 16 fuzz targets now compile and match the actual crate API.
1 parent 15ee9be commit 3d4dff8

10 files changed

+82
-52
lines changed

fuzz/fuzz_targets/byte_storage_checksum_collision.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![no_main]
22

33
use libfuzzer_sys::fuzz_target;
4-
use cachekit_core::byte_storage::StorageEnvelope;
4+
use cachekit_core::byte_storage::{StorageEnvelope, ByteStorageError};
55
use arbitrary::Arbitrary;
66

77
#[derive(Arbitrary, Debug)]
@@ -55,34 +55,34 @@ fuzz_target!(|test_case: ChecksumTestCase| {
5555
// If it succeeded, data must be unchanged (flip reverted or no-op)
5656
// This is only acceptable if flip_mask was 0 or flipped back to original
5757
}
58-
Err(err_msg) => {
59-
// Expected: Checksum validation should fail
58+
Err(err) => {
59+
// Expected: Checksum validation or decompression should fail
6060
assert!(
61-
err_msg.contains("Checksum validation failed") || err_msg.contains("decompression failed"),
62-
"Error should indicate checksum or decompression failure: {}",
63-
err_msg
61+
matches!(err, ByteStorageError::ChecksumMismatch | ByteStorageError::DecompressionFailed),
62+
"Error should be checksum or decompression failure: {:?}",
63+
err
6464
);
6565
}
6666
}
6767

68-
// Test with completely wrong checksum
68+
// Test with completely wrong checksum (xxHash3-64 = 8 bytes)
6969
let wrong_checksum_envelope = StorageEnvelope {
7070
compressed_data: envelope.compressed_data.clone(),
71-
checksum: [0xFF; 32], // Wrong checksum
71+
checksum: [0xFF; 8], // Wrong checksum
7272
original_size: envelope.original_size,
7373
format: envelope.format.clone(),
7474
};
7575

7676
// Should be rejected unless original checksum happened to be all 0xFF
7777
match wrong_checksum_envelope.extract() {
7878
Ok(_) => {
79-
// Only acceptable if original checksum was [0xFF; 32]
79+
// Only acceptable if original checksum was [0xFF; 8]
8080
}
81-
Err(err_msg) => {
81+
Err(err) => {
8282
assert!(
83-
err_msg.contains("Checksum") || err_msg.contains("failed"),
84-
"Wrong checksum should be detected: {}",
85-
err_msg
83+
matches!(err, ByteStorageError::ChecksumMismatch | ByteStorageError::DecompressionFailed),
84+
"Wrong checksum should be detected: {:?}",
85+
err
8686
);
8787
}
8888
}

fuzz/fuzz_targets/byte_storage_empty_data.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ struct EmptyDataTestCase {
1010
original_size: u32,
1111
/// Compressed data length (can be 0)
1212
compressed_len: u8, // 0-255
13-
/// Checksum
14-
checksum: [u8; 32],
13+
/// Checksum (xxHash3-64 = 8 bytes)
14+
checksum: [u8; 8],
1515
}
1616

1717
fuzz_target!(|test_case: EmptyDataTestCase| {

fuzz/fuzz_targets/byte_storage_integer_overflow.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![no_main]
22

33
use libfuzzer_sys::fuzz_target;
4-
use cachekit_core::byte_storage::StorageEnvelope;
4+
use cachekit_core::byte_storage::{StorageEnvelope, ByteStorageError};
55
use arbitrary::Arbitrary;
66

77
#[derive(Arbitrary, Debug)]
@@ -10,8 +10,8 @@ struct OverflowTestCase {
1010
original_size: u32,
1111
/// Compressed data size (small to create suspicious ratios)
1212
compressed_data_len: u8, // 0-255 bytes
13-
/// Checksum bytes
14-
checksum: [u8; 32],
13+
/// Checksum bytes (xxHash3-64 = 8 bytes)
14+
checksum: [u8; 8],
1515
/// Format string
1616
format_len: u8, // 0-255 for format string length
1717
}
@@ -40,13 +40,20 @@ fuzz_target!(|test_case: OverflowTestCase| {
4040
// Decompression succeeded - envelope passed all validation checks
4141
// This should only happen for valid sizes within limits
4242
}
43-
Err(err_msg) => {
43+
Err(err) => {
4444
// Expected for oversized allocations (u32::MAX, beyond 512MB, etc.)
45-
// Verify error message is descriptive
45+
// Valid error types for size/validation failures
4646
assert!(
47-
err_msg.contains("Security violation") || err_msg.contains("failed"),
48-
"Error message should be descriptive: {}",
49-
err_msg
47+
matches!(
48+
err,
49+
ByteStorageError::InputTooLarge
50+
| ByteStorageError::DecompressionBomb
51+
| ByteStorageError::DecompressionFailed
52+
| ByteStorageError::ChecksumMismatch
53+
| ByteStorageError::SizeValidationFailed
54+
),
55+
"Expected size/validation error, got: {:?}",
56+
err
5057
);
5158
}
5259
}

fuzz/fuzz_targets/compression_bomb.rs

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![no_main]
22

33
use libfuzzer_sys::fuzz_target;
4-
use cachekit_core::byte_storage::{ByteStorage, StorageEnvelope};
4+
use cachekit_core::byte_storage::{ByteStorage, ByteStorageError, StorageEnvelope};
55
use arbitrary::Arbitrary;
66

77
#[derive(Arbitrary, Debug)]
@@ -10,8 +10,8 @@ struct CompressionBombTestCase {
1010
compressed_size: u16, // 0-65535 bytes
1111
/// Original size claim (potentially massive for bomb attacks)
1212
original_size: u32,
13-
/// Checksum
14-
checksum: [u8; 32],
13+
/// Checksum (xxHash3-64 = 8 bytes)
14+
checksum: [u8; 8],
1515
/// Format string length
1616
format_len: u8,
1717
/// Actual compressed data pattern (for LZ4 valid/invalid inputs)
@@ -57,37 +57,44 @@ fuzz_target!(|test_case: CompressionBombTestCase| {
5757
);
5858
}
5959
Err(err) => {
60-
// Expected for malicious inputs - verify error is descriptive
60+
// Expected for malicious inputs - verify error type
6161
if test_case.original_size as usize > storage.max_uncompressed_size() {
6262
assert!(
63-
err.contains("Security violation") || err.contains("too large"),
64-
"Expected size limit error, got: {}",
63+
matches!(
64+
err,
65+
ByteStorageError::InputTooLarge
66+
| ByteStorageError::DecompressionBomb
67+
| ByteStorageError::DecompressionFailed
68+
),
69+
"Expected size limit error, got: {:?}",
6570
err
6671
);
6772
}
6873
}
6974
}
7075

71-
// Property 3: Compression ratio limits enforced (500x max expansion)
76+
// Property 3: Compression ratio limits enforced (1000x max expansion)
7277
if !compressed_data.is_empty() && test_case.original_size > 0 {
73-
let claimed_ratio = test_case.original_size as f64 / compressed_data.len() as f64;
78+
let claimed_ratio = test_case.original_size as u64 / compressed_data.len() as u64;
7479

7580
if claimed_ratio > storage.max_compression_ratio() {
7681
// Must reject suspicious ratios (or size limits caught it first)
7782
assert!(
7883
extract_result.is_err(),
79-
"Decompression bomb bypassed ratio limit: {:.1}x expansion (1KB -> {}MB)",
80-
claimed_ratio,
81-
test_case.original_size / (1024 * 1024)
84+
"Decompression bomb bypassed ratio limit: {}x expansion",
85+
claimed_ratio
8286
);
8387

8488
if let Err(err) = &extract_result {
8589
// Security checks may fail in different order (size limit or ratio limit)
8690
assert!(
87-
err.contains("Suspicious compression ratio")
88-
|| err.contains("decompression bomb")
89-
|| err.contains("too large"), // Size limit caught it first
90-
"Expected security violation error, got: {}",
91+
matches!(
92+
err,
93+
ByteStorageError::DecompressionBomb
94+
| ByteStorageError::InputTooLarge
95+
| ByteStorageError::DecompressionFailed
96+
),
97+
"Expected security violation error, got: {:?}",
9198
err
9299
);
93100
}
@@ -110,10 +117,10 @@ fuzz_target!(|test_case: CompressionBombTestCase| {
110117

111118
// Ratio must be within limits (for non-empty compressed data)
112119
if !compressed_data.is_empty() {
113-
let actual_ratio = decompressed.len() as f64 / compressed_data.len() as f64;
120+
let actual_ratio = decompressed.len() as u64 / compressed_data.len() as u64;
114121
assert!(
115122
actual_ratio <= storage.max_compression_ratio(),
116-
"retrieve() bypassed ratio limit: {:.1}x",
123+
"retrieve() bypassed ratio limit: {}x",
117124
actual_ratio
118125
);
119126
}
@@ -130,7 +137,7 @@ fuzz_target!(|test_case: CompressionBombTestCase| {
130137
// Defense-in-depth: Size limits prevent 1KB -> 10GB attacks
131138

132139
// SUCCESS: All compression bomb attack vectors blocked
133-
// - Extreme ratios rejected (500x limit)
140+
// - Extreme ratios rejected (1000x limit)
134141
// - Oversized outputs rejected (512MB limit)
135142
// - Malformed LZ4 data handled gracefully
136143
// - No panics, crashes, or memory exhaustion

fuzz/fuzz_targets/encryption_aad_injection.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ fuzz_target!(|data: &[u8]| {
1919

2020
let (plaintext, aad) = rest.split_at(rest.len() / 2);
2121

22-
let encryptor = ZeroKnowledgeEncryptor::new();
22+
let encryptor = match ZeroKnowledgeEncryptor::new() {
23+
Ok(e) => e,
24+
Err(_) => return, // Skip if encryptor creation fails
25+
};
2326

2427
// Encrypt with potentially malicious AAD
2528
// AAD can contain: nulls, control chars, Unicode, empty, long strings

fuzz/fuzz_targets/encryption_large_payload.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ fuzz_target!(|data: &[u8]| {
2020
let (key, plaintext) = data.split_at(32);
2121
let aad = b"large_payload_test";
2222

23-
let encryptor = ZeroKnowledgeEncryptor::new();
23+
let encryptor = match ZeroKnowledgeEncryptor::new() {
24+
Ok(e) => e,
25+
Err(_) => return, // Skip if encryptor creation fails
26+
};
2427

2528
// Test encryption → decryption roundtrip
2629
let start = std::time::Instant::now();

fuzz/fuzz_targets/encryption_nonce_reuse.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ fuzz_target!(|data: &[u8]| {
2121
let (key, plaintext) = data.split_at(32);
2222
let aad = b"fuzz_test_aad";
2323

24-
let encryptor = ZeroKnowledgeEncryptor::new();
24+
let encryptor = match ZeroKnowledgeEncryptor::new() {
25+
Ok(e) => e,
26+
Err(_) => return, // Skip if encryptor creation fails
27+
};
2528

2629
// Encrypt same plaintext multiple times
2730
let mut ciphertexts = HashSet::new();

fuzz/fuzz_targets/encryption_roundtrip.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,25 @@ fuzz_target!(|data: &[u8]| {
1010
}
1111

1212
// Create encryptor
13-
let encryptor = ZeroKnowledgeEncryptor::new();
13+
let encryptor = match ZeroKnowledgeEncryptor::new() {
14+
Ok(e) => e,
15+
Err(_) => return, // Skip if encryptor creation fails
16+
};
1417

1518
// Generate deterministic key and AAD from input
1619
// (In real usage, keys come from key derivation)
17-
let key = if data.len() >= 32 {
20+
let key: &[u8] = if data.len() >= 32 {
1821
&data[0..32]
1922
} else {
2023
// Pad with zeros if input too short
21-
let mut padded = [0u8; 32];
22-
padded[..data.len()].copy_from_slice(data);
23-
return; // Skip fuzzing with padded keys - focus on real data
24+
return; // Skip fuzzing with short keys - focus on real data
2425
};
2526

2627
let aad = b"fuzz_test_aad";
2728
let plaintext = if data.len() > 32 {
2829
&data[32..]
2930
} else {
30-
b"test_plaintext"
31+
b"test_plaintext" as &[u8]
3132
};
3233

3334
// Test encryption (should not panic on any input)

fuzz/fuzz_targets/encryption_truncated_ciphertext.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ fuzz_target!(|data: &[u8]| {
1515
let (key, plaintext) = data.split_at(32);
1616
let aad = b"test_aad";
1717

18-
let encryptor = ZeroKnowledgeEncryptor::new();
18+
let encryptor = match ZeroKnowledgeEncryptor::new() {
19+
Ok(e) => e,
20+
Err(_) => return, // Skip if encryptor creation fails
21+
};
1922

2023
// Create valid ciphertext
2124
let ciphertext = match encryptor.encrypt_aes_gcm(plaintext, key, aad) {

fuzz/fuzz_targets/integration_layered_security.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ fuzz_target!(|data: &[u8]| {
2121
}
2222

2323
let aad = b"layered_test";
24-
let encryptor = ZeroKnowledgeEncryptor::new();
24+
let encryptor = match ZeroKnowledgeEncryptor::new() {
25+
Ok(e) => e,
26+
Err(_) => return, // Skip if encryptor creation fails
27+
};
2528

2629
// Step 1: Create ByteStorage envelope (compression + checksum)
2730
let envelope = match StorageEnvelope::new(plaintext.to_vec(), "msgpack".to_string()) {

0 commit comments

Comments
 (0)