refactor(deps): replace md5 crate with md-5 (#5432)

Co-authored-by: heihutu <heihutu@gmail.com>
This commit is contained in:
houseme
2026-07-29 19:29:37 +08:00
committed by GitHub
parent f329d330df
commit f7c1b13c0f
16 changed files with 119 additions and 64 deletions
+1 -1
View File
@@ -164,7 +164,7 @@ const-str = { workspace = true, features = ["std", "proc"] }
datafusion = { workspace = true, default-features = false, features = ["parquet", "recursive_protection", "sql"] }
hex-simd.workspace = true
matchit = { workspace = true }
md5.workspace = true
md-5 = { workspace = true }
mime_guess = { workspace = true }
percent-encoding = { workspace = true }
pin-project-lite.workspace = true
+5 -5
View File
@@ -116,7 +116,7 @@ use crate::table_catalog;
use bytes::Bytes;
use futures::{Stream, StreamExt};
use http::{HeaderMap, HeaderValue, StatusCode};
use md5::Context as Md5Context;
use md5::{Digest as Md5Digest, Md5};
use metrics::{counter, histogram};
use pin_project_lite::pin_project;
use rustfs_concurrency::GetObjectQueueSnapshot;
@@ -801,7 +801,7 @@ pin_project! {
struct ExtractArchiveEtagReader<R> {
#[pin]
inner: R,
md5: Md5Context,
md5: Md5,
finished: bool,
etag: Arc<Mutex<Option<String>>>,
}
@@ -1854,7 +1854,7 @@ impl<R> ExtractArchiveEtagReader<R> {
fn new(inner: R, etag: Arc<Mutex<Option<String>>>) -> Self {
Self {
inner,
md5: Md5Context::new(),
md5: Md5::new(),
finished: false,
etag,
}
@@ -1870,11 +1870,11 @@ impl<R: AsyncRead> AsyncRead for ExtractArchiveEtagReader<R> {
Poll::Ready(Ok(())) => {
let filled = &buf.filled()[before..];
if !filled.is_empty() {
this.md5.consume(filled);
this.md5.update(filled);
} else if !*this.finished {
*this.finished = true;
if let Ok(mut etag) = this.etag.lock() {
*etag = Some(format!("{:x}", this.md5.clone().finalize()));
*etag = Some(hex_simd::encode_to_string(this.md5.clone().finalize(), hex_simd::AsciiCase::Lower));
}
}
Poll::Ready(Ok(()))
+39 -31
View File
@@ -84,6 +84,7 @@ use chacha20poly1305::ChaCha20Poly1305;
#[cfg(feature = "rio-v2")]
use hmac::{Hmac, Mac};
use http::{HeaderMap, HeaderValue};
use md5::{Digest as Md5Digest, Md5};
use rand::Rng;
#[cfg(feature = "rio-v2")]
use rand::RngExt;
@@ -135,6 +136,16 @@ const SEALED_KEY_SIZE: usize = DARE_HEADER_SIZE + 32 + DARE_TAG_SIZE;
#[cfg(feature = "rio-v2")]
const OBJECT_KEY_DERIVATION_CONTEXT: &[u8] = b"object-encryption-key generation";
fn md5_bytes(input: impl AsRef<[u8]>) -> [u8; 16] {
let mut hasher = Md5::new();
hasher.update(input.as_ref());
hasher.finalize().into()
}
fn md5_base64(input: impl AsRef<[u8]>) -> String {
BASE64_STANDARD.encode(md5_bytes(input))
}
use super::Error;
use super::get_bucket_sse_config;
use crate::error::ApiError;
@@ -2527,7 +2538,7 @@ pub fn validate_ssec_params(params: SsecParams) -> Result<ValidatedSsecParams, A
)));
}
let computed_md5 = BASE64_STANDARD.encode(md5::compute(&key_bytes).0);
let computed_md5 = md5_base64(&key_bytes);
if computed_md5 != params.key_md5 {
return Err(ssec_invalid_request(
"The calculated MD5 hash of the key did not match the hash that was provided.",
@@ -2552,9 +2563,9 @@ pub fn validate_ssec_params(params: SsecParams) -> Result<ValidatedSsecParams, A
/// 2. Different objects get different nonces
pub fn generate_ssec_nonce(bucket: &str, key: &str) -> [u8; 12] {
let nonce_source = format!("{bucket}-{key}");
let nonce_hash = md5::compute(nonce_source.as_bytes());
let nonce_hash = md5_bytes(nonce_source.as_bytes());
let mut nonce = [0u8; 12];
nonce.copy_from_slice(&nonce_hash.0[..12]);
nonce.copy_from_slice(&nonce_hash[..12]);
nonce
}
@@ -2640,10 +2651,10 @@ mod tests {
SseDekProvider, SsecParams, StorageError, TestSseDekProvider, apply_managed_decryption_material,
apply_managed_encryption_material, encryption_material_to_metadata, extract_server_side_encryption_from_headers,
extract_ssec_params_from_headers, extract_ssekms_context_from_headers, generate_ssec_nonce, is_managed_sse,
kms_operation_error, map_get_object_reader_error, mark_encrypted_multipart_metadata, normalize_managed_metadata,
reset_sse_dek_provider, resolve_effective_kms_key_id, sse_decryption, sse_encryption, sse_prepare_encryption,
strip_managed_encryption_metadata, validate_sse_headers_for_read, validate_sse_headers_for_write, validate_ssec_for_read,
validate_ssec_params, verify_ssec_key_match,
kms_operation_error, map_get_object_reader_error, mark_encrypted_multipart_metadata, md5_base64,
normalize_managed_metadata, reset_sse_dek_provider, resolve_effective_kms_key_id, sse_decryption, sse_encryption,
sse_prepare_encryption, strip_managed_encryption_metadata, validate_sse_headers_for_read, validate_sse_headers_for_write,
validate_ssec_for_read, validate_ssec_params, verify_ssec_key_match,
};
#[cfg(feature = "rio-v2")]
use super::{
@@ -2882,7 +2893,7 @@ mod tests {
#[test]
fn test_validate_ssec_params_success() {
let key = BASE64_STANDARD.encode([42u8; 32]);
let key_md5 = BASE64_STANDARD.encode(md5::compute([42u8; 32]).0);
let key_md5 = md5_base64([42u8; 32]);
let params = SsecParams {
algorithm: "AES256".to_string(),
@@ -2899,7 +2910,7 @@ mod tests {
#[test]
fn test_validate_ssec_params_wrong_algorithm() {
let key = BASE64_STANDARD.encode([42u8; 32]);
let key_md5 = BASE64_STANDARD.encode(md5::compute([42u8; 32]).0);
let key_md5 = md5_base64([42u8; 32]);
let params = SsecParams {
algorithm: "AES128".to_string(), // Wrong algorithm
@@ -2914,7 +2925,7 @@ mod tests {
#[test]
fn test_validate_ssec_params_wrong_key_length() {
let key = BASE64_STANDARD.encode([42u8; 16]); // Only 16 bytes
let key_md5 = BASE64_STANDARD.encode(md5::compute([42u8; 16]).0);
let key_md5 = md5_base64([42u8; 16]);
let params = SsecParams {
algorithm: "AES256".to_string(),
@@ -2946,7 +2957,7 @@ mod tests {
let bucket = "test-bucket";
let key = "test-key";
let sse_key = BASE64_STANDARD.encode([42u8; 32]);
let sse_key_md5 = BASE64_STANDARD.encode(md5::compute([42u8; 32]).0);
let sse_key_md5 = md5_base64([42u8; 32]);
let content_size = 1024;
let request_missing_md5 = EncryptionRequest {
@@ -2999,7 +3010,7 @@ mod tests {
async fn test_sse_prepare_encryption_rejects_partial_ssec_headers() {
let bucket = "test-bucket";
let key = "test-key";
let sse_key_md5 = BASE64_STANDARD.encode(md5::compute([42u8; 32]).0);
let sse_key_md5 = md5_base64([42u8; 32]);
let request_missing_algorithm = PrepareEncryptionRequest {
bucket,
@@ -3029,7 +3040,7 @@ mod tests {
async fn test_sse_prepare_encryption_rejects_ssec_headers_without_customer_key() {
let bucket = "test-bucket";
let key = "test-key";
let sse_key_md5 = BASE64_STANDARD.encode(md5::compute([42u8; 32]).0);
let sse_key_md5 = md5_base64([42u8; 32]);
let request = PrepareEncryptionRequest {
bucket,
@@ -3087,7 +3098,7 @@ mod tests {
let key = "object";
let customer_key_bytes = [0x24u8; 32];
let customer_key = BASE64_STANDARD.encode(customer_key_bytes);
let customer_key_md5 = BASE64_STANDARD.encode(md5::compute(customer_key_bytes).0);
let customer_key_md5 = md5_base64(customer_key_bytes);
let metadata_one = ssec_direct_put_metadata(bucket, key, &customer_key, &customer_key_md5).await;
let metadata_two = ssec_direct_put_metadata(bucket, key, &customer_key, &customer_key_md5).await;
@@ -3128,7 +3139,7 @@ mod tests {
let key = "object";
let customer_key_bytes = [0x24u8; 32];
let customer_key = BASE64_STANDARD.encode(customer_key_bytes);
let customer_key_md5 = BASE64_STANDARD.encode(md5::compute(customer_key_bytes).0);
let customer_key_md5 = md5_base64(customer_key_bytes);
let mut metadata = HashMap::new();
metadata.insert("x-amz-server-side-encryption-customer-algorithm".to_string(), "AES256".to_string());
@@ -3160,7 +3171,7 @@ mod tests {
let key = "object";
let customer_key_bytes = [0x51u8; 32];
let customer_key = BASE64_STANDARD.encode(customer_key_bytes);
let customer_key_md5 = BASE64_STANDARD.encode(md5::compute(customer_key_bytes).0);
let customer_key_md5 = md5_base64(customer_key_bytes);
let plaintext = b"attack at dawn - sse-c round trip".to_vec();
let metadata = ssec_direct_put_metadata(bucket, key, &customer_key, &customer_key_md5).await;
@@ -3199,7 +3210,7 @@ mod tests {
let key = "object";
let customer_key_bytes = [0x33u8; 32];
let customer_key = BASE64_STANDARD.encode(customer_key_bytes);
let customer_key_md5 = BASE64_STANDARD.encode(md5::compute(customer_key_bytes).0);
let customer_key_md5 = md5_base64(customer_key_bytes);
let material = sse_prepare_encryption(PrepareEncryptionRequest {
bucket,
@@ -3261,7 +3272,7 @@ mod tests {
let key = "test-key";
let customer_key_bytes = [0x24u8; 32];
let customer_key = BASE64_STANDARD.encode(customer_key_bytes);
let sse_key_md5 = BASE64_STANDARD.encode(md5::compute(customer_key_bytes).0);
let sse_key_md5 = md5_base64(customer_key_bytes);
let request = PrepareEncryptionRequest {
bucket,
@@ -3356,7 +3367,7 @@ mod tests {
let key = "test-key";
let content_size = 1024;
let sse_key = BASE64_STANDARD.encode([42u8; 32]);
let sse_key_md5 = BASE64_STANDARD.encode(md5::compute([42u8; 32]).0);
let sse_key_md5 = md5_base64([42u8; 32]);
let request = EncryptionRequest {
bucket,
@@ -3745,7 +3756,7 @@ mod tests {
async fn test_ssec_rio_v2_uses_sealed_object_key_metadata_roundtrip() {
let customer_key_bytes = [0x42u8; 32];
let customer_key = BASE64_STANDARD.encode(customer_key_bytes);
let customer_key_md5 = BASE64_STANDARD.encode(md5::compute(customer_key_bytes).0);
let customer_key_md5 = md5_base64(customer_key_bytes);
let material = sse_encryption(EncryptionRequest {
bucket: "bucket",
@@ -3825,7 +3836,7 @@ mod tests {
ssekms_context: None,
sse_customer_algorithm: Some("AES256".to_string()),
sse_customer_key: Some(BASE64_STANDARD.encode(key_bytes)),
sse_customer_key_md5: Some(BASE64_STANDARD.encode(md5::compute(key_bytes).0)),
sse_customer_key_md5: Some(md5_base64(key_bytes)),
content_size: 1,
}
}
@@ -3834,10 +3845,7 @@ mod tests {
let key_bytes = [key_byte; 32];
HashMap::from([
("x-amz-server-side-encryption-customer-algorithm".to_string(), "AES256".to_string()),
(
"x-amz-server-side-encryption-customer-key-md5".to_string(),
BASE64_STANDARD.encode(md5::compute(key_bytes).0),
),
("x-amz-server-side-encryption-customer-key-md5".to_string(), md5_base64(key_bytes)),
])
}
@@ -4547,7 +4555,7 @@ mod tests {
fn test_validate_ssec_for_read_wrong_key() {
// Key A is used to "encrypt" the object (stored MD5 is from key A).
let key_a = [42u8; 32];
let stored_md5 = BASE64_STANDARD.encode(md5::compute(key_a).0);
let stored_md5 = md5_base64(key_a);
let mut metadata = HashMap::new();
metadata.insert("x-amz-server-side-encryption-customer-algorithm".to_string(), "AES256".to_string());
@@ -4556,7 +4564,7 @@ mod tests {
// Key B is a different key; its MD5 won't match stored MD5.
let key_b = [99u8; 32];
let key_b_b64 = BASE64_STANDARD.encode(key_b);
let key_b_md5 = BASE64_STANDARD.encode(md5::compute(key_b).0);
let key_b_md5 = md5_base64(key_b);
let err = validate_ssec_for_read(&metadata, Some(&key_b_b64), Some(&key_b_md5)).unwrap_err();
assert_eq!(err.code, S3ErrorCode::InvalidRequest);
@@ -4566,7 +4574,7 @@ mod tests {
fn test_validate_ssec_for_read_correct_key() {
let key_bytes = [42u8; 32];
let key_b64 = BASE64_STANDARD.encode(key_bytes);
let key_md5 = BASE64_STANDARD.encode(md5::compute(key_bytes).0);
let key_md5 = md5_base64(key_bytes);
let mut metadata = HashMap::new();
metadata.insert("x-amz-server-side-encryption-customer-algorithm".to_string(), "AES256".to_string());
@@ -4582,7 +4590,7 @@ mod tests {
// DIFFERENT key. The server must recompute MD5 from the key bytes and
// reject the request because the recomputed MD5 won't match the header.
let real_key = [42u8; 32];
let stored_md5 = BASE64_STANDARD.encode(md5::compute(real_key).0);
let stored_md5 = md5_base64(real_key);
let mut metadata = HashMap::new();
metadata.insert("x-amz-server-side-encryption-customer-algorithm".to_string(), "AES256".to_string());
@@ -4694,7 +4702,7 @@ mod tests {
#[test]
fn test_validate_ssec_params_returns_invalid_request_on_bad_algorithm() {
let key = BASE64_STANDARD.encode([42u8; 32]);
let key_md5 = BASE64_STANDARD.encode(md5::compute([42u8; 32]).0);
let key_md5 = md5_base64([42u8; 32]);
let params = SsecParams {
algorithm: "AES128".to_string(),
key,
@@ -4780,7 +4788,7 @@ mod tests {
ssekms_context: None,
sse_customer_algorithm: Some("unsupported-algo".to_string()),
sse_customer_key: Some(sse_key),
sse_customer_key_md5: Some(BASE64_STANDARD.encode(md5::compute([42u8; 32]).0)),
sse_customer_key_md5: Some(md5_base64([42u8; 32])),
content_size: 1024,
};
let err = sse_encryption(request_unsupported_algorithm).await.unwrap_err();