mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-30 10:08:58 +00:00
refactor(deps): replace md5 crate with md-5 (#5432)
Co-authored-by: heihutu <heihutu@gmail.com>
This commit is contained in:
Generated
+6
-4
@@ -3671,12 +3671,13 @@ dependencies = [
|
||||
"flatbuffers",
|
||||
"flate2",
|
||||
"futures",
|
||||
"hex",
|
||||
"http 1.4.2",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"local-ip-address",
|
||||
"md5",
|
||||
"md-5 0.11.0",
|
||||
"opentelemetry-proto",
|
||||
"prost 0.14.4",
|
||||
"rand 0.10.2",
|
||||
@@ -8890,7 +8891,7 @@ dependencies = [
|
||||
"libmimalloc-sys",
|
||||
"libsystemd",
|
||||
"matchit 0.9.2",
|
||||
"md5",
|
||||
"md-5 0.11.0",
|
||||
"metrics",
|
||||
"metrics-util",
|
||||
"mimalloc",
|
||||
@@ -9449,9 +9450,10 @@ dependencies = [
|
||||
"async-trait",
|
||||
"base64 0.23.0",
|
||||
"chacha20poly1305",
|
||||
"hex",
|
||||
"insta",
|
||||
"jiff",
|
||||
"md5",
|
||||
"md-5 0.11.0",
|
||||
"moka",
|
||||
"rand 0.10.2",
|
||||
"reqwest",
|
||||
@@ -9718,7 +9720,7 @@ dependencies = [
|
||||
"hyper-util",
|
||||
"ipnetwork",
|
||||
"libunftp",
|
||||
"md5",
|
||||
"md-5 0.11.0",
|
||||
"percent-encoding",
|
||||
"proptest",
|
||||
"quick-xml",
|
||||
|
||||
@@ -265,7 +265,6 @@ memmap2 = "0.9.11"
|
||||
lz4 = "1.28.1"
|
||||
matchit = "0.9.2"
|
||||
md-5 = "0.11.0"
|
||||
md5 = "0.8.1"
|
||||
mime_guess = "2.0.5"
|
||||
moka = { version = "0.12.15" }
|
||||
netif = "0.1.6"
|
||||
|
||||
@@ -70,7 +70,8 @@ walkdir.workspace = true
|
||||
base64 = { workspace = true }
|
||||
rand = { workspace = true, features = ["serde"] }
|
||||
chrono = { workspace = true, features = ["serde"] }
|
||||
md5 = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
md-5 = { workspace = true }
|
||||
opentelemetry-proto = { workspace = true }
|
||||
prost.workspace = true
|
||||
sha2 = { workspace = true }
|
||||
|
||||
@@ -24,9 +24,10 @@ mod tests {
|
||||
use aws_sdk_s3::types::{ChecksumAlgorithm, ChecksumMode, CompletedMultipartUpload, CompletedPart};
|
||||
use aws_smithy_http_client::Builder as SmithyHttpClientBuilder;
|
||||
use base64::Engine;
|
||||
use md5::{Digest as Md5Digest, Md5};
|
||||
use rustfs_rio::{Checksum, ChecksumType as RioChecksumType};
|
||||
use serial_test::serial;
|
||||
use sha2::{Digest, Sha256};
|
||||
use sha2::Sha256;
|
||||
use tracing::info;
|
||||
|
||||
fn create_s3_client(env: &RustFSTestEnvironment) -> Client {
|
||||
@@ -70,7 +71,9 @@ mod tests {
|
||||
}
|
||||
|
||||
fn content_md5_base64(body: &[u8]) -> String {
|
||||
let digest = md5::compute(body);
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(body);
|
||||
let digest = hasher.finalize();
|
||||
base64::engine::general_purpose::STANDARD.encode(digest.as_slice())
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ use hyper::body::Incoming;
|
||||
use hyper::server::conn::http1;
|
||||
use hyper::service::service_fn;
|
||||
use hyper_util::rt::{TokioIo, TokioTimer};
|
||||
use md5::{Digest as Md5Digest, Md5};
|
||||
use s3s::access::{S3Access, S3AccessContext};
|
||||
use s3s::auth::SimpleAuth;
|
||||
use s3s::dto::{
|
||||
@@ -827,13 +828,25 @@ fn ensure_body_growth(current: usize, added: usize) -> S3Result {
|
||||
|
||||
async fn md5_digest(body: Bytes, permit: OwnedSemaphorePermit) -> S3Result<([u8; 16], OwnedSemaphorePermit)> {
|
||||
if body.len() < 1024 * 1024 {
|
||||
return Ok((md5::compute(body).0, permit));
|
||||
return Ok((md5_bytes(body), permit));
|
||||
}
|
||||
tokio::task::spawn_blocking(move || (md5::compute(body).0, permit))
|
||||
tokio::task::spawn_blocking(move || (md5_bytes(body), permit))
|
||||
.await
|
||||
.map_err(|error| s3s::s3_error!(InternalError, "MD5 worker failed: {error}"))
|
||||
}
|
||||
|
||||
fn md5_bytes(input: impl AsRef<[u8]>) -> [u8; 16] {
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(input.as_ref());
|
||||
hasher.finalize().into()
|
||||
}
|
||||
|
||||
fn md5_hex(input: impl AsRef<[u8]>) -> String {
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(input.as_ref());
|
||||
hex::encode(hasher.finalize())
|
||||
}
|
||||
|
||||
fn ensure_store_budget(state: &StoreState, removed_bytes: usize, added_bytes: usize, adds_version: bool) -> S3Result {
|
||||
let total_bytes = state
|
||||
.total_bytes
|
||||
@@ -1005,7 +1018,7 @@ impl S3 for FakeBackend {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
let (digest, _body_permit) = md5_digest(body.clone(), _body_permit).await?;
|
||||
format!("{:x}", md5::Digest(digest))
|
||||
hex::encode(digest)
|
||||
}
|
||||
};
|
||||
let version = ObjectVersion {
|
||||
@@ -1208,7 +1221,7 @@ impl S3 for FakeBackend {
|
||||
}
|
||||
let body = collect_stream(input.body, input.content_length, fault.as_ref(), &self.control).await?;
|
||||
let (digest, _body_permit) = md5_digest(body.clone(), _body_permit).await?;
|
||||
let e_tag = format!("{:x}", md5::Digest(digest));
|
||||
let e_tag = hex::encode(digest);
|
||||
let mut state = lock(&self.store);
|
||||
let existing_bytes = state
|
||||
.uploads
|
||||
@@ -1336,7 +1349,7 @@ impl S3 for FakeBackend {
|
||||
.collect();
|
||||
let (body, digests, _body_permits) = assemble_multipart(assembly_parts, total_len, _body_permits).await?;
|
||||
let part_count = requested.len();
|
||||
let e_tag = source_etag(&headers)?.unwrap_or_else(|| format!("{:x}-{part_count}", md5::compute(digests)));
|
||||
let e_tag = source_etag(&headers)?.unwrap_or_else(|| format!("{}-{part_count}", md5_hex(digests)));
|
||||
let version = ObjectVersion {
|
||||
version_id: upload.version_id.clone(),
|
||||
body,
|
||||
|
||||
@@ -30,6 +30,7 @@ use aws_sdk_s3::primitives::ByteStream;
|
||||
use aws_sdk_s3::types::ServerSideEncryption;
|
||||
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
||||
use http::header::{CONTENT_TYPE, HOST};
|
||||
use md5::{Digest as Md5Digest, Md5};
|
||||
use rustfs_signer::constants::UNSIGNED_PAYLOAD;
|
||||
use rustfs_signer::sign_v4;
|
||||
use s3s::Body;
|
||||
@@ -68,7 +69,9 @@ pub fn skip_if_kms_admin_tool_unavailable(test_name: &str) -> bool {
|
||||
}
|
||||
|
||||
pub fn sse_customer_key_md5_base64(key: &str) -> String {
|
||||
BASE64.encode(md5::compute(key).0)
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(key.as_bytes());
|
||||
BASE64.encode(hasher.finalize())
|
||||
}
|
||||
|
||||
pub async fn kms_admin_request(
|
||||
|
||||
@@ -25,12 +25,18 @@ use super::common::{LocalKMSTestEnvironment, sse_customer_key_md5_base64};
|
||||
use crate::common::{TEST_BUCKET, init_logging};
|
||||
use aws_sdk_s3::types::ServerSideEncryption;
|
||||
use base64::Engine;
|
||||
use md5::compute;
|
||||
use md5::{Digest as Md5Digest, Md5};
|
||||
use serial_test::serial;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Semaphore;
|
||||
use tracing::{info, warn};
|
||||
|
||||
fn md5_hex(input: impl AsRef<[u8]>) -> String {
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(input.as_ref());
|
||||
hex::encode(hasher.finalize())
|
||||
}
|
||||
|
||||
/// Test encryption of zero-byte files (empty files)
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
@@ -294,7 +300,7 @@ async fn test_kms_invalid_key_scenarios() -> Result<(), Box<dyn std::error::Erro
|
||||
info!("🔍 Testing invalid SSE-C key length");
|
||||
let invalid_short_key = "short"; // Too short
|
||||
let invalid_key_b64 = base64::engine::general_purpose::STANDARD.encode(invalid_short_key);
|
||||
let invalid_key_md5 = format!("{:x}", compute(invalid_short_key));
|
||||
let invalid_key_md5 = md5_hex(invalid_short_key);
|
||||
|
||||
let invalid_key_result = s3_client
|
||||
.put_object()
|
||||
|
||||
@@ -26,6 +26,7 @@ use chrono::{Duration as ChronoDuration, Utc};
|
||||
use flate2::{Compression, write::GzEncoder};
|
||||
use http::HeaderValue;
|
||||
use http::header::{CONTENT_TYPE, HOST};
|
||||
use md5::{Digest as Md5Digest, Md5};
|
||||
use rustfs_signer::constants::UNSIGNED_PAYLOAD;
|
||||
use rustfs_signer::sign_v4;
|
||||
use s3s::Body;
|
||||
@@ -50,7 +51,15 @@ fn encode_post_policy(conditions: Vec<serde_json::Value>) -> String {
|
||||
}
|
||||
|
||||
fn sse_customer_key_md5_base64(key: &str) -> String {
|
||||
base64::engine::general_purpose::STANDARD.encode(md5::compute(key).0)
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(key.as_bytes());
|
||||
base64::engine::general_purpose::STANDARD.encode(hasher.finalize())
|
||||
}
|
||||
|
||||
fn md5_hex(input: impl AsRef<[u8]>) -> String {
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(input.as_ref());
|
||||
hex::encode(hasher.finalize())
|
||||
}
|
||||
|
||||
/// Env var consumed by the local SSE-S3 DEK provider when KMS is not configured.
|
||||
@@ -5664,7 +5673,7 @@ async fn test_signed_put_object_extract_returns_archive_etag() -> Result<(), Box
|
||||
client.create_bucket().bucket(bucket).send().await?;
|
||||
|
||||
let archive = make_tar(&[("alpha.txt", b"alpha-body")], &[]).await;
|
||||
let expected_etag = format!("\"{:x}\"", md5::compute(&archive));
|
||||
let expected_etag = format!("\"{}\"", md5_hex(&archive));
|
||||
|
||||
let response = client
|
||||
.put_object()
|
||||
|
||||
@@ -22,6 +22,7 @@ use aws_sdk_s3::primitives::ByteStream;
|
||||
use aws_sdk_s3::types::{BucketVersioningStatus, CompletedMultipartUpload, CompletedPart, VersioningConfiguration};
|
||||
use aws_smithy_http_client::Builder as SmithyHttpClientBuilder;
|
||||
use base64::Engine;
|
||||
use md5::{Digest as Md5Digest, Md5};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
@@ -102,10 +103,12 @@ impl Intercept for ResponseHeaderCapture {
|
||||
|
||||
fn customer_key(byte: u8) -> CustomerKey {
|
||||
let raw = [byte; 32];
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(raw);
|
||||
CustomerKey {
|
||||
raw: String::from_utf8_lossy(&raw).into_owned(),
|
||||
encoded: base64::engine::general_purpose::STANDARD.encode(raw),
|
||||
md5: base64::engine::general_purpose::STANDARD.encode(md5::compute(raw).0),
|
||||
md5: base64::engine::general_purpose::STANDARD.encode(hasher.finalize()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ argon2 = { workspace = true }
|
||||
chacha20poly1305 = { workspace = true }
|
||||
rand = { workspace = true, features = ["serde"] }
|
||||
base64 = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
sha2 = { workspace = true }
|
||||
subtle = { workspace = true }
|
||||
zeroize = { workspace = true, features = ["derive"] }
|
||||
@@ -56,7 +57,7 @@ tempfile = { workspace = true }
|
||||
moka = { workspace = true, features = ["future"] }
|
||||
|
||||
# Additional dependencies
|
||||
md5 = { workspace = true }
|
||||
md-5 = { workspace = true }
|
||||
arc-swap = { workspace = true }
|
||||
rustfs-utils = { workspace = true }
|
||||
rustfs-security-governance = { workspace = true }
|
||||
|
||||
@@ -20,6 +20,7 @@ use crate::manager::KmsManager;
|
||||
use crate::types::*;
|
||||
use base64::Engine;
|
||||
use jiff::Zoned;
|
||||
use md5::{Digest as Md5Digest, Md5};
|
||||
use rand::random;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Cursor;
|
||||
@@ -27,6 +28,12 @@ use tokio::io::{AsyncRead, AsyncReadExt};
|
||||
use tracing::debug;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
fn md5_hex(input: impl AsRef<[u8]>) -> String {
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(input.as_ref());
|
||||
hex::encode(hasher.finalize())
|
||||
}
|
||||
|
||||
/// Data key for object encryption
|
||||
/// SECURITY: This struct automatically zeros sensitive key material when dropped
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -486,8 +493,7 @@ impl ObjectEncryptionService {
|
||||
|
||||
// Validate key MD5 if provided
|
||||
if let Some(expected_md5) = customer_key_md5 {
|
||||
let actual_md5 = md5::compute(customer_key);
|
||||
let actual_md5_hex = format!("{actual_md5:x}");
|
||||
let actual_md5_hex = md5_hex(customer_key);
|
||||
if actual_md5_hex != expected_md5.to_lowercase() {
|
||||
return Err(KmsError::validation_error("Customer key MD5 mismatch"));
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ swift = [
|
||||
"dep:tokio-util",
|
||||
"dep:serde",
|
||||
"dep:urlencoding",
|
||||
"dep:md5",
|
||||
"dep:md-5",
|
||||
"dep:quick-xml",
|
||||
"dep:hmac",
|
||||
"dep:sha1",
|
||||
@@ -108,7 +108,7 @@ http-body-util = { workspace = true, optional = true }
|
||||
tokio-util = { workspace = true, optional = true, features = ["rt", "io", "compat"] }
|
||||
serde = { workspace = true, optional = true, features = ["derive"] }
|
||||
urlencoding = { workspace = true, optional = true }
|
||||
md5 = { workspace = true, optional = true }
|
||||
md-5 = { workspace = true, optional = true }
|
||||
quick-xml = { workspace = true, optional = true, features = ["serialize"] }
|
||||
hmac = { workspace = true, optional = true }
|
||||
sha1 = { workspace = true, optional = true }
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
use super::storage_api::large_object::HTTPRangeSpec;
|
||||
use super::{SwiftError, object};
|
||||
use axum::http::{HeaderMap, Response, StatusCode};
|
||||
use md5::{Digest as Md5Digest, Md5};
|
||||
use rustfs_credentials::Credentials;
|
||||
use s3s::Body;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -81,9 +82,9 @@ impl SLOManifest {
|
||||
etag_concat.push_str(etag);
|
||||
}
|
||||
|
||||
// Calculate MD5 hash
|
||||
let hash = md5::compute(etag_concat.as_bytes());
|
||||
format!("\"{:x}-{}\"", hash, self.segments.len())
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(etag_concat.as_bytes());
|
||||
format!("\"{}-{}\"", hex::encode(hasher.finalize()), self.segments.len())
|
||||
}
|
||||
|
||||
/// Validate manifest against actual segments
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user