mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-29 16:37:07 +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",
|
"flatbuffers",
|
||||||
"flate2",
|
"flate2",
|
||||||
"futures",
|
"futures",
|
||||||
|
"hex",
|
||||||
"http 1.4.2",
|
"http 1.4.2",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"local-ip-address",
|
"local-ip-address",
|
||||||
"md5",
|
"md-5 0.11.0",
|
||||||
"opentelemetry-proto",
|
"opentelemetry-proto",
|
||||||
"prost 0.14.4",
|
"prost 0.14.4",
|
||||||
"rand 0.10.2",
|
"rand 0.10.2",
|
||||||
@@ -8890,7 +8891,7 @@ dependencies = [
|
|||||||
"libmimalloc-sys",
|
"libmimalloc-sys",
|
||||||
"libsystemd",
|
"libsystemd",
|
||||||
"matchit 0.9.2",
|
"matchit 0.9.2",
|
||||||
"md5",
|
"md-5 0.11.0",
|
||||||
"metrics",
|
"metrics",
|
||||||
"metrics-util",
|
"metrics-util",
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
@@ -9449,9 +9450,10 @@ dependencies = [
|
|||||||
"async-trait",
|
"async-trait",
|
||||||
"base64 0.23.0",
|
"base64 0.23.0",
|
||||||
"chacha20poly1305",
|
"chacha20poly1305",
|
||||||
|
"hex",
|
||||||
"insta",
|
"insta",
|
||||||
"jiff",
|
"jiff",
|
||||||
"md5",
|
"md-5 0.11.0",
|
||||||
"moka",
|
"moka",
|
||||||
"rand 0.10.2",
|
"rand 0.10.2",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@@ -9718,7 +9720,7 @@ dependencies = [
|
|||||||
"hyper-util",
|
"hyper-util",
|
||||||
"ipnetwork",
|
"ipnetwork",
|
||||||
"libunftp",
|
"libunftp",
|
||||||
"md5",
|
"md-5 0.11.0",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"proptest",
|
"proptest",
|
||||||
"quick-xml",
|
"quick-xml",
|
||||||
|
|||||||
@@ -265,7 +265,6 @@ memmap2 = "0.9.11"
|
|||||||
lz4 = "1.28.1"
|
lz4 = "1.28.1"
|
||||||
matchit = "0.9.2"
|
matchit = "0.9.2"
|
||||||
md-5 = "0.11.0"
|
md-5 = "0.11.0"
|
||||||
md5 = "0.8.1"
|
|
||||||
mime_guess = "2.0.5"
|
mime_guess = "2.0.5"
|
||||||
moka = { version = "0.12.15" }
|
moka = { version = "0.12.15" }
|
||||||
netif = "0.1.6"
|
netif = "0.1.6"
|
||||||
|
|||||||
@@ -70,7 +70,8 @@ walkdir.workspace = true
|
|||||||
base64 = { workspace = true }
|
base64 = { workspace = true }
|
||||||
rand = { workspace = true, features = ["serde"] }
|
rand = { workspace = true, features = ["serde"] }
|
||||||
chrono = { workspace = true, features = ["serde"] }
|
chrono = { workspace = true, features = ["serde"] }
|
||||||
md5 = { workspace = true }
|
hex = { workspace = true }
|
||||||
|
md-5 = { workspace = true }
|
||||||
opentelemetry-proto = { workspace = true }
|
opentelemetry-proto = { workspace = true }
|
||||||
prost.workspace = true
|
prost.workspace = true
|
||||||
sha2 = { workspace = true }
|
sha2 = { workspace = true }
|
||||||
|
|||||||
@@ -24,9 +24,10 @@ mod tests {
|
|||||||
use aws_sdk_s3::types::{ChecksumAlgorithm, ChecksumMode, CompletedMultipartUpload, CompletedPart};
|
use aws_sdk_s3::types::{ChecksumAlgorithm, ChecksumMode, CompletedMultipartUpload, CompletedPart};
|
||||||
use aws_smithy_http_client::Builder as SmithyHttpClientBuilder;
|
use aws_smithy_http_client::Builder as SmithyHttpClientBuilder;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
|
use md5::{Digest as Md5Digest, Md5};
|
||||||
use rustfs_rio::{Checksum, ChecksumType as RioChecksumType};
|
use rustfs_rio::{Checksum, ChecksumType as RioChecksumType};
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::Sha256;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
fn create_s3_client(env: &RustFSTestEnvironment) -> Client {
|
fn create_s3_client(env: &RustFSTestEnvironment) -> Client {
|
||||||
@@ -70,7 +71,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn content_md5_base64(body: &[u8]) -> String {
|
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())
|
base64::engine::general_purpose::STANDARD.encode(digest.as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ use hyper::body::Incoming;
|
|||||||
use hyper::server::conn::http1;
|
use hyper::server::conn::http1;
|
||||||
use hyper::service::service_fn;
|
use hyper::service::service_fn;
|
||||||
use hyper_util::rt::{TokioIo, TokioTimer};
|
use hyper_util::rt::{TokioIo, TokioTimer};
|
||||||
|
use md5::{Digest as Md5Digest, Md5};
|
||||||
use s3s::access::{S3Access, S3AccessContext};
|
use s3s::access::{S3Access, S3AccessContext};
|
||||||
use s3s::auth::SimpleAuth;
|
use s3s::auth::SimpleAuth;
|
||||||
use s3s::dto::{
|
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)> {
|
async fn md5_digest(body: Bytes, permit: OwnedSemaphorePermit) -> S3Result<([u8; 16], OwnedSemaphorePermit)> {
|
||||||
if body.len() < 1024 * 1024 {
|
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
|
.await
|
||||||
.map_err(|error| s3s::s3_error!(InternalError, "MD5 worker failed: {error}"))
|
.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 {
|
fn ensure_store_budget(state: &StoreState, removed_bytes: usize, added_bytes: usize, adds_version: bool) -> S3Result {
|
||||||
let total_bytes = state
|
let total_bytes = state
|
||||||
.total_bytes
|
.total_bytes
|
||||||
@@ -1005,7 +1018,7 @@ impl S3 for FakeBackend {
|
|||||||
Some(value) => value,
|
Some(value) => value,
|
||||||
None => {
|
None => {
|
||||||
let (digest, _body_permit) = md5_digest(body.clone(), _body_permit).await?;
|
let (digest, _body_permit) = md5_digest(body.clone(), _body_permit).await?;
|
||||||
format!("{:x}", md5::Digest(digest))
|
hex::encode(digest)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let version = ObjectVersion {
|
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 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 (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 mut state = lock(&self.store);
|
||||||
let existing_bytes = state
|
let existing_bytes = state
|
||||||
.uploads
|
.uploads
|
||||||
@@ -1336,7 +1349,7 @@ impl S3 for FakeBackend {
|
|||||||
.collect();
|
.collect();
|
||||||
let (body, digests, _body_permits) = assemble_multipart(assembly_parts, total_len, _body_permits).await?;
|
let (body, digests, _body_permits) = assemble_multipart(assembly_parts, total_len, _body_permits).await?;
|
||||||
let part_count = requested.len();
|
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 {
|
let version = ObjectVersion {
|
||||||
version_id: upload.version_id.clone(),
|
version_id: upload.version_id.clone(),
|
||||||
body,
|
body,
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ use aws_sdk_s3::primitives::ByteStream;
|
|||||||
use aws_sdk_s3::types::ServerSideEncryption;
|
use aws_sdk_s3::types::ServerSideEncryption;
|
||||||
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
||||||
use http::header::{CONTENT_TYPE, HOST};
|
use http::header::{CONTENT_TYPE, HOST};
|
||||||
|
use md5::{Digest as Md5Digest, Md5};
|
||||||
use rustfs_signer::constants::UNSIGNED_PAYLOAD;
|
use rustfs_signer::constants::UNSIGNED_PAYLOAD;
|
||||||
use rustfs_signer::sign_v4;
|
use rustfs_signer::sign_v4;
|
||||||
use s3s::Body;
|
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 {
|
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(
|
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 crate::common::{TEST_BUCKET, init_logging};
|
||||||
use aws_sdk_s3::types::ServerSideEncryption;
|
use aws_sdk_s3::types::ServerSideEncryption;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use md5::compute;
|
use md5::{Digest as Md5Digest, Md5};
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::Semaphore;
|
use tokio::sync::Semaphore;
|
||||||
use tracing::{info, warn};
|
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)
|
/// Test encryption of zero-byte files (empty files)
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[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");
|
info!("🔍 Testing invalid SSE-C key length");
|
||||||
let invalid_short_key = "short"; // Too short
|
let invalid_short_key = "short"; // Too short
|
||||||
let invalid_key_b64 = base64::engine::general_purpose::STANDARD.encode(invalid_short_key);
|
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
|
let invalid_key_result = s3_client
|
||||||
.put_object()
|
.put_object()
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ use chrono::{Duration as ChronoDuration, Utc};
|
|||||||
use flate2::{Compression, write::GzEncoder};
|
use flate2::{Compression, write::GzEncoder};
|
||||||
use http::HeaderValue;
|
use http::HeaderValue;
|
||||||
use http::header::{CONTENT_TYPE, HOST};
|
use http::header::{CONTENT_TYPE, HOST};
|
||||||
|
use md5::{Digest as Md5Digest, Md5};
|
||||||
use rustfs_signer::constants::UNSIGNED_PAYLOAD;
|
use rustfs_signer::constants::UNSIGNED_PAYLOAD;
|
||||||
use rustfs_signer::sign_v4;
|
use rustfs_signer::sign_v4;
|
||||||
use s3s::Body;
|
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 {
|
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.
|
/// 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?;
|
client.create_bucket().bucket(bucket).send().await?;
|
||||||
|
|
||||||
let archive = make_tar(&[("alpha.txt", b"alpha-body")], &[]).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
|
let response = client
|
||||||
.put_object()
|
.put_object()
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ use aws_sdk_s3::primitives::ByteStream;
|
|||||||
use aws_sdk_s3::types::{BucketVersioningStatus, CompletedMultipartUpload, CompletedPart, VersioningConfiguration};
|
use aws_sdk_s3::types::{BucketVersioningStatus, CompletedMultipartUpload, CompletedPart, VersioningConfiguration};
|
||||||
use aws_smithy_http_client::Builder as SmithyHttpClientBuilder;
|
use aws_smithy_http_client::Builder as SmithyHttpClientBuilder;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
|
use md5::{Digest as Md5Digest, Md5};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
@@ -102,10 +103,12 @@ impl Intercept for ResponseHeaderCapture {
|
|||||||
|
|
||||||
fn customer_key(byte: u8) -> CustomerKey {
|
fn customer_key(byte: u8) -> CustomerKey {
|
||||||
let raw = [byte; 32];
|
let raw = [byte; 32];
|
||||||
|
let mut hasher = Md5::new();
|
||||||
|
hasher.update(raw);
|
||||||
CustomerKey {
|
CustomerKey {
|
||||||
raw: String::from_utf8_lossy(&raw).into_owned(),
|
raw: String::from_utf8_lossy(&raw).into_owned(),
|
||||||
encoded: base64::engine::general_purpose::STANDARD.encode(raw),
|
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 }
|
chacha20poly1305 = { workspace = true }
|
||||||
rand = { workspace = true, features = ["serde"] }
|
rand = { workspace = true, features = ["serde"] }
|
||||||
base64 = { workspace = true }
|
base64 = { workspace = true }
|
||||||
|
hex = { workspace = true }
|
||||||
sha2 = { workspace = true }
|
sha2 = { workspace = true }
|
||||||
subtle = { workspace = true }
|
subtle = { workspace = true }
|
||||||
zeroize = { workspace = true, features = ["derive"] }
|
zeroize = { workspace = true, features = ["derive"] }
|
||||||
@@ -56,7 +57,7 @@ tempfile = { workspace = true }
|
|||||||
moka = { workspace = true, features = ["future"] }
|
moka = { workspace = true, features = ["future"] }
|
||||||
|
|
||||||
# Additional dependencies
|
# Additional dependencies
|
||||||
md5 = { workspace = true }
|
md-5 = { workspace = true }
|
||||||
arc-swap = { workspace = true }
|
arc-swap = { workspace = true }
|
||||||
rustfs-utils = { workspace = true }
|
rustfs-utils = { workspace = true }
|
||||||
rustfs-security-governance = { workspace = true }
|
rustfs-security-governance = { workspace = true }
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ use crate::manager::KmsManager;
|
|||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use jiff::Zoned;
|
use jiff::Zoned;
|
||||||
|
use md5::{Digest as Md5Digest, Md5};
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
@@ -27,6 +28,12 @@ use tokio::io::{AsyncRead, AsyncReadExt};
|
|||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
use zeroize::Zeroize;
|
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
|
/// Data key for object encryption
|
||||||
/// SECURITY: This struct automatically zeros sensitive key material when dropped
|
/// SECURITY: This struct automatically zeros sensitive key material when dropped
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -486,8 +493,7 @@ impl ObjectEncryptionService {
|
|||||||
|
|
||||||
// Validate key MD5 if provided
|
// Validate key MD5 if provided
|
||||||
if let Some(expected_md5) = customer_key_md5 {
|
if let Some(expected_md5) = customer_key_md5 {
|
||||||
let actual_md5 = md5::compute(customer_key);
|
let actual_md5_hex = md5_hex(customer_key);
|
||||||
let actual_md5_hex = format!("{actual_md5:x}");
|
|
||||||
if actual_md5_hex != expected_md5.to_lowercase() {
|
if actual_md5_hex != expected_md5.to_lowercase() {
|
||||||
return Err(KmsError::validation_error("Customer key MD5 mismatch"));
|
return Err(KmsError::validation_error("Customer key MD5 mismatch"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ swift = [
|
|||||||
"dep:tokio-util",
|
"dep:tokio-util",
|
||||||
"dep:serde",
|
"dep:serde",
|
||||||
"dep:urlencoding",
|
"dep:urlencoding",
|
||||||
"dep:md5",
|
"dep:md-5",
|
||||||
"dep:quick-xml",
|
"dep:quick-xml",
|
||||||
"dep:hmac",
|
"dep:hmac",
|
||||||
"dep:sha1",
|
"dep:sha1",
|
||||||
@@ -108,7 +108,7 @@ http-body-util = { workspace = true, optional = true }
|
|||||||
tokio-util = { workspace = true, optional = true, features = ["rt", "io", "compat"] }
|
tokio-util = { workspace = true, optional = true, features = ["rt", "io", "compat"] }
|
||||||
serde = { workspace = true, optional = true, features = ["derive"] }
|
serde = { workspace = true, optional = true, features = ["derive"] }
|
||||||
urlencoding = { workspace = true, optional = true }
|
urlencoding = { workspace = true, optional = true }
|
||||||
md5 = { workspace = true, optional = true }
|
md-5 = { workspace = true, optional = true }
|
||||||
quick-xml = { workspace = true, optional = true, features = ["serialize"] }
|
quick-xml = { workspace = true, optional = true, features = ["serialize"] }
|
||||||
hmac = { workspace = true, optional = true }
|
hmac = { workspace = true, optional = true }
|
||||||
sha1 = { workspace = true, optional = true }
|
sha1 = { workspace = true, optional = true }
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
use super::storage_api::large_object::HTTPRangeSpec;
|
use super::storage_api::large_object::HTTPRangeSpec;
|
||||||
use super::{SwiftError, object};
|
use super::{SwiftError, object};
|
||||||
use axum::http::{HeaderMap, Response, StatusCode};
|
use axum::http::{HeaderMap, Response, StatusCode};
|
||||||
|
use md5::{Digest as Md5Digest, Md5};
|
||||||
use rustfs_credentials::Credentials;
|
use rustfs_credentials::Credentials;
|
||||||
use s3s::Body;
|
use s3s::Body;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -81,9 +82,9 @@ impl SLOManifest {
|
|||||||
etag_concat.push_str(etag);
|
etag_concat.push_str(etag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate MD5 hash
|
let mut hasher = Md5::new();
|
||||||
let hash = md5::compute(etag_concat.as_bytes());
|
hasher.update(etag_concat.as_bytes());
|
||||||
format!("\"{:x}-{}\"", hash, self.segments.len())
|
format!("\"{}-{}\"", hex::encode(hasher.finalize()), self.segments.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validate manifest against actual segments
|
/// 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"] }
|
datafusion = { workspace = true, default-features = false, features = ["parquet", "recursive_protection", "sql"] }
|
||||||
hex-simd.workspace = true
|
hex-simd.workspace = true
|
||||||
matchit = { workspace = true }
|
matchit = { workspace = true }
|
||||||
md5.workspace = true
|
md-5 = { workspace = true }
|
||||||
mime_guess = { workspace = true }
|
mime_guess = { workspace = true }
|
||||||
percent-encoding = { workspace = true }
|
percent-encoding = { workspace = true }
|
||||||
pin-project-lite.workspace = true
|
pin-project-lite.workspace = true
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ use crate::table_catalog;
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use futures::{Stream, StreamExt};
|
use futures::{Stream, StreamExt};
|
||||||
use http::{HeaderMap, HeaderValue, StatusCode};
|
use http::{HeaderMap, HeaderValue, StatusCode};
|
||||||
use md5::Context as Md5Context;
|
use md5::{Digest as Md5Digest, Md5};
|
||||||
use metrics::{counter, histogram};
|
use metrics::{counter, histogram};
|
||||||
use pin_project_lite::pin_project;
|
use pin_project_lite::pin_project;
|
||||||
use rustfs_concurrency::GetObjectQueueSnapshot;
|
use rustfs_concurrency::GetObjectQueueSnapshot;
|
||||||
@@ -801,7 +801,7 @@ pin_project! {
|
|||||||
struct ExtractArchiveEtagReader<R> {
|
struct ExtractArchiveEtagReader<R> {
|
||||||
#[pin]
|
#[pin]
|
||||||
inner: R,
|
inner: R,
|
||||||
md5: Md5Context,
|
md5: Md5,
|
||||||
finished: bool,
|
finished: bool,
|
||||||
etag: Arc<Mutex<Option<String>>>,
|
etag: Arc<Mutex<Option<String>>>,
|
||||||
}
|
}
|
||||||
@@ -1854,7 +1854,7 @@ impl<R> ExtractArchiveEtagReader<R> {
|
|||||||
fn new(inner: R, etag: Arc<Mutex<Option<String>>>) -> Self {
|
fn new(inner: R, etag: Arc<Mutex<Option<String>>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner,
|
inner,
|
||||||
md5: Md5Context::new(),
|
md5: Md5::new(),
|
||||||
finished: false,
|
finished: false,
|
||||||
etag,
|
etag,
|
||||||
}
|
}
|
||||||
@@ -1870,11 +1870,11 @@ impl<R: AsyncRead> AsyncRead for ExtractArchiveEtagReader<R> {
|
|||||||
Poll::Ready(Ok(())) => {
|
Poll::Ready(Ok(())) => {
|
||||||
let filled = &buf.filled()[before..];
|
let filled = &buf.filled()[before..];
|
||||||
if !filled.is_empty() {
|
if !filled.is_empty() {
|
||||||
this.md5.consume(filled);
|
this.md5.update(filled);
|
||||||
} else if !*this.finished {
|
} else if !*this.finished {
|
||||||
*this.finished = true;
|
*this.finished = true;
|
||||||
if let Ok(mut etag) = this.etag.lock() {
|
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(()))
|
Poll::Ready(Ok(()))
|
||||||
|
|||||||
+39
-31
@@ -84,6 +84,7 @@ use chacha20poly1305::ChaCha20Poly1305;
|
|||||||
#[cfg(feature = "rio-v2")]
|
#[cfg(feature = "rio-v2")]
|
||||||
use hmac::{Hmac, Mac};
|
use hmac::{Hmac, Mac};
|
||||||
use http::{HeaderMap, HeaderValue};
|
use http::{HeaderMap, HeaderValue};
|
||||||
|
use md5::{Digest as Md5Digest, Md5};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
#[cfg(feature = "rio-v2")]
|
#[cfg(feature = "rio-v2")]
|
||||||
use rand::RngExt;
|
use rand::RngExt;
|
||||||
@@ -135,6 +136,16 @@ const SEALED_KEY_SIZE: usize = DARE_HEADER_SIZE + 32 + DARE_TAG_SIZE;
|
|||||||
#[cfg(feature = "rio-v2")]
|
#[cfg(feature = "rio-v2")]
|
||||||
const OBJECT_KEY_DERIVATION_CONTEXT: &[u8] = b"object-encryption-key generation";
|
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::Error;
|
||||||
use super::get_bucket_sse_config;
|
use super::get_bucket_sse_config;
|
||||||
use crate::error::ApiError;
|
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 {
|
if computed_md5 != params.key_md5 {
|
||||||
return Err(ssec_invalid_request(
|
return Err(ssec_invalid_request(
|
||||||
"The calculated MD5 hash of the key did not match the hash that was provided.",
|
"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
|
/// 2. Different objects get different nonces
|
||||||
pub fn generate_ssec_nonce(bucket: &str, key: &str) -> [u8; 12] {
|
pub fn generate_ssec_nonce(bucket: &str, key: &str) -> [u8; 12] {
|
||||||
let nonce_source = format!("{bucket}-{key}");
|
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];
|
let mut nonce = [0u8; 12];
|
||||||
nonce.copy_from_slice(&nonce_hash.0[..12]);
|
nonce.copy_from_slice(&nonce_hash[..12]);
|
||||||
nonce
|
nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2640,10 +2651,10 @@ mod tests {
|
|||||||
SseDekProvider, SsecParams, StorageError, TestSseDekProvider, apply_managed_decryption_material,
|
SseDekProvider, SsecParams, StorageError, TestSseDekProvider, apply_managed_decryption_material,
|
||||||
apply_managed_encryption_material, encryption_material_to_metadata, extract_server_side_encryption_from_headers,
|
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,
|
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,
|
kms_operation_error, map_get_object_reader_error, mark_encrypted_multipart_metadata, md5_base64,
|
||||||
reset_sse_dek_provider, resolve_effective_kms_key_id, sse_decryption, sse_encryption, sse_prepare_encryption,
|
normalize_managed_metadata, reset_sse_dek_provider, resolve_effective_kms_key_id, sse_decryption, sse_encryption,
|
||||||
strip_managed_encryption_metadata, validate_sse_headers_for_read, validate_sse_headers_for_write, validate_ssec_for_read,
|
sse_prepare_encryption, strip_managed_encryption_metadata, validate_sse_headers_for_read, validate_sse_headers_for_write,
|
||||||
validate_ssec_params, verify_ssec_key_match,
|
validate_ssec_for_read, validate_ssec_params, verify_ssec_key_match,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "rio-v2")]
|
#[cfg(feature = "rio-v2")]
|
||||||
use super::{
|
use super::{
|
||||||
@@ -2882,7 +2893,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_validate_ssec_params_success() {
|
fn test_validate_ssec_params_success() {
|
||||||
let key = BASE64_STANDARD.encode([42u8; 32]);
|
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 {
|
let params = SsecParams {
|
||||||
algorithm: "AES256".to_string(),
|
algorithm: "AES256".to_string(),
|
||||||
@@ -2899,7 +2910,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_validate_ssec_params_wrong_algorithm() {
|
fn test_validate_ssec_params_wrong_algorithm() {
|
||||||
let key = BASE64_STANDARD.encode([42u8; 32]);
|
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 {
|
let params = SsecParams {
|
||||||
algorithm: "AES128".to_string(), // Wrong algorithm
|
algorithm: "AES128".to_string(), // Wrong algorithm
|
||||||
@@ -2914,7 +2925,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_validate_ssec_params_wrong_key_length() {
|
fn test_validate_ssec_params_wrong_key_length() {
|
||||||
let key = BASE64_STANDARD.encode([42u8; 16]); // Only 16 bytes
|
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 {
|
let params = SsecParams {
|
||||||
algorithm: "AES256".to_string(),
|
algorithm: "AES256".to_string(),
|
||||||
@@ -2946,7 +2957,7 @@ mod tests {
|
|||||||
let bucket = "test-bucket";
|
let bucket = "test-bucket";
|
||||||
let key = "test-key";
|
let key = "test-key";
|
||||||
let sse_key = BASE64_STANDARD.encode([42u8; 32]);
|
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 content_size = 1024;
|
||||||
|
|
||||||
let request_missing_md5 = EncryptionRequest {
|
let request_missing_md5 = EncryptionRequest {
|
||||||
@@ -2999,7 +3010,7 @@ mod tests {
|
|||||||
async fn test_sse_prepare_encryption_rejects_partial_ssec_headers() {
|
async fn test_sse_prepare_encryption_rejects_partial_ssec_headers() {
|
||||||
let bucket = "test-bucket";
|
let bucket = "test-bucket";
|
||||||
let key = "test-key";
|
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 {
|
let request_missing_algorithm = PrepareEncryptionRequest {
|
||||||
bucket,
|
bucket,
|
||||||
@@ -3029,7 +3040,7 @@ mod tests {
|
|||||||
async fn test_sse_prepare_encryption_rejects_ssec_headers_without_customer_key() {
|
async fn test_sse_prepare_encryption_rejects_ssec_headers_without_customer_key() {
|
||||||
let bucket = "test-bucket";
|
let bucket = "test-bucket";
|
||||||
let key = "test-key";
|
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 {
|
let request = PrepareEncryptionRequest {
|
||||||
bucket,
|
bucket,
|
||||||
@@ -3087,7 +3098,7 @@ mod tests {
|
|||||||
let key = "object";
|
let key = "object";
|
||||||
let customer_key_bytes = [0x24u8; 32];
|
let customer_key_bytes = [0x24u8; 32];
|
||||||
let customer_key = BASE64_STANDARD.encode(customer_key_bytes);
|
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_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;
|
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 key = "object";
|
||||||
let customer_key_bytes = [0x24u8; 32];
|
let customer_key_bytes = [0x24u8; 32];
|
||||||
let customer_key = BASE64_STANDARD.encode(customer_key_bytes);
|
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();
|
let mut metadata = HashMap::new();
|
||||||
metadata.insert("x-amz-server-side-encryption-customer-algorithm".to_string(), "AES256".to_string());
|
metadata.insert("x-amz-server-side-encryption-customer-algorithm".to_string(), "AES256".to_string());
|
||||||
@@ -3160,7 +3171,7 @@ mod tests {
|
|||||||
let key = "object";
|
let key = "object";
|
||||||
let customer_key_bytes = [0x51u8; 32];
|
let customer_key_bytes = [0x51u8; 32];
|
||||||
let customer_key = BASE64_STANDARD.encode(customer_key_bytes);
|
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 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;
|
let metadata = ssec_direct_put_metadata(bucket, key, &customer_key, &customer_key_md5).await;
|
||||||
@@ -3199,7 +3210,7 @@ mod tests {
|
|||||||
let key = "object";
|
let key = "object";
|
||||||
let customer_key_bytes = [0x33u8; 32];
|
let customer_key_bytes = [0x33u8; 32];
|
||||||
let customer_key = BASE64_STANDARD.encode(customer_key_bytes);
|
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 {
|
let material = sse_prepare_encryption(PrepareEncryptionRequest {
|
||||||
bucket,
|
bucket,
|
||||||
@@ -3261,7 +3272,7 @@ mod tests {
|
|||||||
let key = "test-key";
|
let key = "test-key";
|
||||||
let customer_key_bytes = [0x24u8; 32];
|
let customer_key_bytes = [0x24u8; 32];
|
||||||
let customer_key = BASE64_STANDARD.encode(customer_key_bytes);
|
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 {
|
let request = PrepareEncryptionRequest {
|
||||||
bucket,
|
bucket,
|
||||||
@@ -3356,7 +3367,7 @@ mod tests {
|
|||||||
let key = "test-key";
|
let key = "test-key";
|
||||||
let content_size = 1024;
|
let content_size = 1024;
|
||||||
let sse_key = BASE64_STANDARD.encode([42u8; 32]);
|
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 {
|
let request = EncryptionRequest {
|
||||||
bucket,
|
bucket,
|
||||||
@@ -3745,7 +3756,7 @@ mod tests {
|
|||||||
async fn test_ssec_rio_v2_uses_sealed_object_key_metadata_roundtrip() {
|
async fn test_ssec_rio_v2_uses_sealed_object_key_metadata_roundtrip() {
|
||||||
let customer_key_bytes = [0x42u8; 32];
|
let customer_key_bytes = [0x42u8; 32];
|
||||||
let customer_key = BASE64_STANDARD.encode(customer_key_bytes);
|
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 {
|
let material = sse_encryption(EncryptionRequest {
|
||||||
bucket: "bucket",
|
bucket: "bucket",
|
||||||
@@ -3825,7 +3836,7 @@ mod tests {
|
|||||||
ssekms_context: None,
|
ssekms_context: None,
|
||||||
sse_customer_algorithm: Some("AES256".to_string()),
|
sse_customer_algorithm: Some("AES256".to_string()),
|
||||||
sse_customer_key: Some(BASE64_STANDARD.encode(key_bytes)),
|
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,
|
content_size: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3834,10 +3845,7 @@ mod tests {
|
|||||||
let key_bytes = [key_byte; 32];
|
let key_bytes = [key_byte; 32];
|
||||||
HashMap::from([
|
HashMap::from([
|
||||||
("x-amz-server-side-encryption-customer-algorithm".to_string(), "AES256".to_string()),
|
("x-amz-server-side-encryption-customer-algorithm".to_string(), "AES256".to_string()),
|
||||||
(
|
("x-amz-server-side-encryption-customer-key-md5".to_string(), md5_base64(key_bytes)),
|
||||||
"x-amz-server-side-encryption-customer-key-md5".to_string(),
|
|
||||||
BASE64_STANDARD.encode(md5::compute(key_bytes).0),
|
|
||||||
),
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4547,7 +4555,7 @@ mod tests {
|
|||||||
fn test_validate_ssec_for_read_wrong_key() {
|
fn test_validate_ssec_for_read_wrong_key() {
|
||||||
// Key A is used to "encrypt" the object (stored MD5 is from key A).
|
// Key A is used to "encrypt" the object (stored MD5 is from key A).
|
||||||
let key_a = [42u8; 32];
|
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();
|
let mut metadata = HashMap::new();
|
||||||
metadata.insert("x-amz-server-side-encryption-customer-algorithm".to_string(), "AES256".to_string());
|
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.
|
// Key B is a different key; its MD5 won't match stored MD5.
|
||||||
let key_b = [99u8; 32];
|
let key_b = [99u8; 32];
|
||||||
let key_b_b64 = BASE64_STANDARD.encode(key_b);
|
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();
|
let err = validate_ssec_for_read(&metadata, Some(&key_b_b64), Some(&key_b_md5)).unwrap_err();
|
||||||
assert_eq!(err.code, S3ErrorCode::InvalidRequest);
|
assert_eq!(err.code, S3ErrorCode::InvalidRequest);
|
||||||
@@ -4566,7 +4574,7 @@ mod tests {
|
|||||||
fn test_validate_ssec_for_read_correct_key() {
|
fn test_validate_ssec_for_read_correct_key() {
|
||||||
let key_bytes = [42u8; 32];
|
let key_bytes = [42u8; 32];
|
||||||
let key_b64 = BASE64_STANDARD.encode(key_bytes);
|
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();
|
let mut metadata = HashMap::new();
|
||||||
metadata.insert("x-amz-server-side-encryption-customer-algorithm".to_string(), "AES256".to_string());
|
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
|
// DIFFERENT key. The server must recompute MD5 from the key bytes and
|
||||||
// reject the request because the recomputed MD5 won't match the header.
|
// reject the request because the recomputed MD5 won't match the header.
|
||||||
let real_key = [42u8; 32];
|
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();
|
let mut metadata = HashMap::new();
|
||||||
metadata.insert("x-amz-server-side-encryption-customer-algorithm".to_string(), "AES256".to_string());
|
metadata.insert("x-amz-server-side-encryption-customer-algorithm".to_string(), "AES256".to_string());
|
||||||
@@ -4694,7 +4702,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_validate_ssec_params_returns_invalid_request_on_bad_algorithm() {
|
fn test_validate_ssec_params_returns_invalid_request_on_bad_algorithm() {
|
||||||
let key = BASE64_STANDARD.encode([42u8; 32]);
|
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 {
|
let params = SsecParams {
|
||||||
algorithm: "AES128".to_string(),
|
algorithm: "AES128".to_string(),
|
||||||
key,
|
key,
|
||||||
@@ -4780,7 +4788,7 @@ mod tests {
|
|||||||
ssekms_context: None,
|
ssekms_context: None,
|
||||||
sse_customer_algorithm: Some("unsupported-algo".to_string()),
|
sse_customer_algorithm: Some("unsupported-algo".to_string()),
|
||||||
sse_customer_key: Some(sse_key),
|
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,
|
content_size: 1024,
|
||||||
};
|
};
|
||||||
let err = sse_encryption(request_unsupported_algorithm).await.unwrap_err();
|
let err = sse_encryption(request_unsupported_algorithm).await.unwrap_err();
|
||||||
|
|||||||
Reference in New Issue
Block a user