Skip to content

Commit 92abd75

Browse files
authored
Using blake3 hmac for protected chunk support (#35)
* Using blake3 hmac for protected chunk support * clippy * change return to DataHash
1 parent dc6679b commit 92abd75

File tree

3 files changed

+29
-33
lines changed

3 files changed

+29
-33
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cas_object/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ tracing = "0.1.40"
1616
lz4_flex = "0.11.3"
1717
bytes = "1.7.2"
1818
rand = "0.8.5"
19+
blake3 = "1.5.4"
1920

2021
[dev-dependencies]
2122
tempfile = "3.12.0"

cas_object/src/cas_object_format.rs

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
use anyhow::anyhow;
77
use bytes::Buf;
88
use merkledb::{prelude::MerkleDBHighLevelMethodsV1, Chunk, MerkleMemDB};
9-
use merklehash::MerkleHash;
9+
use merklehash::{DataHash, MerkleHash};
1010
use std::{
1111
cmp::min,
1212
io::{Cursor, Error, Read, Seek, Write},
@@ -378,8 +378,8 @@ impl CasObject {
378378
&self,
379379
chunk_start_index: u32,
380380
chunk_end_index: u32,
381-
key: &[u8],
382-
) -> Result<MerkleHash, CasObjectError> {
381+
key: &[u8; 32],
382+
) -> Result<DataHash, CasObjectError> {
383383
self.validate_cas_object_info()?;
384384

385385
if chunk_end_index <= chunk_start_index || chunk_end_index > self.info.num_chunks {
@@ -388,18 +388,14 @@ impl CasObject {
388388

389389
// Collect relevant hashes
390390
let range_hashes = self.info.chunk_hashes[chunk_start_index as usize..chunk_end_index as usize].as_ref();
391-
392-
// TODO: Make this more robust, currently appends range hashes together, adds key to end
393-
let mut combined: Vec<u8> = range_hashes
391+
let combined: Vec<u8> = range_hashes
394392
.iter()
395393
.flat_map(|hash| hash.as_bytes().to_vec())
396394
.collect();
397-
combined.extend_from_slice(key);
398-
399-
// now hash the hashes + key and return
400-
let range_hash = merklehash::compute_data_hash(&combined);
401395

402-
Ok(range_hash)
396+
// now apply hmac to hashes and return
397+
let range_hash = blake3::keyed_hash(key, combined.as_slice());
398+
Ok(DataHash::from(range_hash.as_bytes()))
403399
}
404400

405401
/// Return end offset of all physical chunk contents (byte index at the beginning of footer)
@@ -689,56 +685,54 @@ mod tests {
689685
// Arrange
690686
let (c, _cas_data, _raw_data, _raw_chunk_boundaries) =
691687
build_cas_object(3, ChunkSize::Fixed(100), CompressionScheme::None);
692-
let key = [b'K', b'E', b'Y'];
688+
let key: &[u8; 32] = c.info.cashash.as_bytes().try_into().map_err(|_| "The slice is not 32 bytes long").unwrap();
693689

694-
let mut hashes: Vec<u8> = c
690+
let hashes: Vec<u8> = c
695691
.info
696692
.chunk_hashes
697693
.iter()
698694
.flat_map(|hash| hash.as_bytes().to_vec())
699695
.collect();
700-
hashes.extend_from_slice(&key);
701-
let expected_hash = merklehash::compute_data_hash(&hashes);
696+
697+
let expected_hash = blake3::keyed_hash(key, hashes.as_slice());
702698

703699
// Act & Assert
704-
let range_hash = c.generate_chunk_range_hash(0, 3, &key).unwrap();
705-
assert_eq!(range_hash, expected_hash);
700+
let range_hash = c.generate_chunk_range_hash(0, 3, key).unwrap();
701+
assert_eq!(range_hash, DataHash::from(expected_hash.as_bytes()));
706702
}
707703

708704
#[test]
709705
fn test_generate_range_hash_partial() {
710706
// Arrange
711707
let (c, _cas_data, _raw_data, _raw_chunk_boundaries) =
712708
build_cas_object(5, ChunkSize::Fixed(100), CompressionScheme::None);
713-
let key = [b'K', b'E', b'Y', b'B', b'A', b'B', b'Y'];
709+
let key: &[u8; 32] = c.info.cashash.as_bytes().try_into().map_err(|_| "The slice is not 32 bytes long").unwrap();
714710

715-
let mut hashes : Vec<u8> = c.info.chunk_hashes.as_slice()[1..=3].to_vec().iter().flat_map(|hash| hash.as_bytes().to_vec()).collect();
716-
hashes.extend_from_slice(&key);
717-
let expected_hash = merklehash::compute_data_hash(&hashes);
711+
let hashes : Vec<u8> = c.info.chunk_hashes.as_slice()[1..=3].to_vec().iter().flat_map(|hash| hash.as_bytes().to_vec()).collect();
712+
let expected_hash = blake3::keyed_hash(key, hashes.as_slice());
718713

719714
// Act & Assert
720-
let range_hash = c.generate_chunk_range_hash(1, 4, &key).unwrap();
721-
assert_eq!(range_hash, expected_hash);
715+
let range_hash = c.generate_chunk_range_hash(1, 4, key).unwrap();
716+
assert_eq!(range_hash, DataHash::from(expected_hash.as_bytes()));
722717

723-
let mut hashes : Vec<u8> = c.info.chunk_hashes.as_slice()[0..1].to_vec().iter().flat_map(|hash| hash.as_bytes().to_vec()).collect();
724-
hashes.extend_from_slice(&key);
725-
let expected_hash = merklehash::compute_data_hash(&hashes);
718+
let hashes : Vec<u8> = c.info.chunk_hashes.as_slice()[0..1].to_vec().iter().flat_map(|hash| hash.as_bytes().to_vec()).collect();
719+
let expected_hash = blake3::keyed_hash(key, hashes.as_slice());
726720

727-
let range_hash = c.generate_chunk_range_hash(0, 1, &key).unwrap();
728-
assert_eq!(range_hash, expected_hash);
721+
let range_hash = c.generate_chunk_range_hash(0, 1, key).unwrap();
722+
assert_eq!(range_hash, DataHash::from(expected_hash.as_bytes()));
729723
}
730724

731725
#[test]
732726
fn test_generate_range_hash_invalid_range() {
733727
// Arrange
734728
let (c, _cas_data, _raw_data, _raw_chunk_boundaries) =
735729
build_cas_object(5, ChunkSize::Fixed(100), CompressionScheme::None);
736-
let key = [b'K', b'E', b'Y', b'B', b'A', b'B', b'Y'];
737-
730+
let key: &[u8; 32] = c.info.cashash.as_bytes().try_into().map_err(|_| "The slice is not 32 bytes long").unwrap();
731+
738732
// Act & Assert
739-
assert_eq!(c.generate_chunk_range_hash(1, 6, &key), Err(CasObjectError::InvalidArguments));
740-
assert_eq!(c.generate_chunk_range_hash(100, 10, &key), Err(CasObjectError::InvalidArguments));
741-
assert_eq!(c.generate_chunk_range_hash(0, 0, &key), Err(CasObjectError::InvalidArguments));
733+
assert_eq!(c.generate_chunk_range_hash(1, 6, key), Err(CasObjectError::InvalidArguments));
734+
assert_eq!(c.generate_chunk_range_hash(100, 10, key), Err(CasObjectError::InvalidArguments));
735+
assert_eq!(c.generate_chunk_range_hash(0, 0, key), Err(CasObjectError::InvalidArguments));
742736
}
743737

744738
#[test]

0 commit comments

Comments
 (0)