api: switch to crc_fast for checksumming and implement full-object mpu checksums

This commit is contained in:
Alex Auvolat
2025-05-09 16:32:33 +02:00
parent 589a992af8
commit e475c7f802
9 changed files with 235 additions and 149 deletions
+1 -3
View File
@@ -21,9 +21,7 @@ garage_util.workspace = true
base64.workspace = true
bytes.workspace = true
chrono.workspace = true
crc32fast.workspace = true
crc32c.workspace = true
crc64fast-nvme.workspace = true
crc-fast.workspace = true
crypto-common.workspace = true
err-derive.workspace = true
hex.workspace = true
+35 -24
View File
@@ -1,10 +1,7 @@
use std::convert::{TryFrom, TryInto};
use std::hash::Hasher;
use std::convert::TryInto;
use base64::prelude::*;
use crc32c::Crc32cHasher as Crc32c;
use crc32fast::Hasher as Crc32;
use crc64fast_nvme::Digest as Crc64Nvme;
use crc_fast::{CrcAlgorithm, Digest as CrcDigest};
use md5::{Digest, Md5};
use sha1::Sha1;
use sha2::Sha256;
@@ -41,6 +38,21 @@ pub type Md5Checksum = [u8; 16];
pub type Sha1Checksum = [u8; 20];
pub type Sha256Checksum = [u8; 32];
// -- MAP OF CRC ALGORITHMS :
// CRC32 -> CrcAlgorithm::Crc32IsoHdlc
// CRC32C -> CrcAlgorithm::Crc32Iscsi
// CRC64NVME -> CrcAlgorithm::Crc64Nvme
pub fn new_crc32() -> CrcDigest {
CrcDigest::new(CrcAlgorithm::Crc32IsoHdlc)
}
pub fn new_crc32c() -> CrcDigest {
CrcDigest::new(CrcAlgorithm::Crc32Iscsi)
}
pub fn new_crc64nvme() -> CrcDigest {
CrcDigest::new(CrcAlgorithm::Crc64Nvme)
}
#[derive(Debug, Default, Clone)]
pub struct ExpectedChecksums {
// base64-encoded md5 (content-md5 header)
@@ -52,9 +64,9 @@ pub struct ExpectedChecksums {
}
pub struct Checksummer {
pub crc32: Option<Crc32>,
pub crc32c: Option<Crc32c>,
pub crc64nvme: Option<Crc64Nvme>,
pub crc32: Option<CrcDigest>,
pub crc32c: Option<CrcDigest>,
pub crc64nvme: Option<CrcDigest>,
pub md5: Option<Md5>,
pub sha1: Option<Sha1>,
pub sha256: Option<Sha256>,
@@ -103,13 +115,13 @@ impl Checksummer {
self.sha256 = Some(Sha256::new());
}
if matches!(&expected.extra, Some(ChecksumValue::Crc32(_))) {
self.crc32 = Some(Crc32::new());
self.crc32 = Some(new_crc32());
}
if matches!(&expected.extra, Some(ChecksumValue::Crc32c(_))) {
self.crc32c = Some(Crc32c::default());
self.crc32c = Some(new_crc32c());
}
if matches!(&expected.extra, Some(ChecksumValue::Crc64Nvme(_))) {
self.crc64nvme = Some(Crc64Nvme::default());
self.crc64nvme = Some(new_crc64nvme());
}
if matches!(&expected.extra, Some(ChecksumValue::Sha1(_))) {
self.sha1 = Some(Sha1::new());
@@ -119,13 +131,13 @@ impl Checksummer {
pub fn add(mut self, algo: Option<ChecksumAlgorithm>) -> Self {
match algo {
Some(ChecksumAlgorithm::Crc32) => {
self.crc32 = Some(Crc32::new());
self.crc32 = Some(new_crc32());
}
Some(ChecksumAlgorithm::Crc32c) => {
self.crc32c = Some(Crc32c::default());
self.crc32c = Some(new_crc32c());
}
Some(ChecksumAlgorithm::Crc64Nvme) => {
self.crc64nvme = Some(Crc64Nvme::default());
self.crc64nvme = Some(new_crc64nvme());
}
Some(ChecksumAlgorithm::Sha1) => {
self.sha1 = Some(Sha1::new());
@@ -143,10 +155,10 @@ impl Checksummer {
crc32.update(bytes);
}
if let Some(crc32c) = &mut self.crc32c {
crc32c.write(bytes);
crc32c.update(bytes);
}
if let Some(crc64nvme) = &mut self.crc64nvme {
crc64nvme.write(bytes);
crc64nvme.update(bytes);
}
if let Some(md5) = &mut self.md5 {
md5.update(bytes);
@@ -161,11 +173,9 @@ impl Checksummer {
pub fn finalize(self) -> Checksums {
Checksums {
crc32: self.crc32.map(|x| u32::to_be_bytes(x.finalize())),
crc32c: self
.crc32c
.map(|x| u32::to_be_bytes(u32::try_from(x.finish()).unwrap())),
crc64nvme: self.crc64nvme.map(|x| u64::to_be_bytes(x.sum64())),
crc32: self.crc32.map(|x| u32::to_be_bytes(x.finalize() as u32)),
crc32c: self.crc32c.map(|x| u32::to_be_bytes(x.finalize() as u32)),
crc64nvme: self.crc64nvme.map(|x| u64::to_be_bytes(x.finalize())),
md5: self.md5.map(|x| x.finalize()[..].try_into().unwrap()),
sha1: self.sha1.map(|x| x.finalize()[..].try_into().unwrap()),
sha256: self.sha256.map(|x| x.finalize()[..].try_into().unwrap()),
@@ -197,10 +207,11 @@ impl Checksums {
}
if let Some(extra) = expected.extra {
let algo = extra.algorithm();
if self.extract(Some(algo)) != Some(extra) {
let calculated = self.extract(Some(algo));
if calculated != Some(extra) {
return Err(Error::InvalidDigest(format!(
"Failed to validate checksum for algorithm {:?}",
algo
"Failed to validate checksum for algorithm {:?}: calculated {:?}, expected {:?}",
algo, calculated, extra
)));
}
}