release: v0.7.2 — Security Audit Remediation (SA-01 bis SA-07)
- SA-01: Container-DoS / KDF-Amplification Schutz mit Pre-KDF Validierung, max 2 Slots (nur 0 und 1), Slot 0 Pflicht und strikten BLOB-Laengen - SA-02: Release-Signierung in CI entkoppelt (getrennte build und sign-and-release Jobs, Secret-Isolation) - SA-03: Pinned Download-Integritaet fuer minisign.exe in CI via SHA-256 - SA-04: Immutable Action-Pinning (@sha) und Toolchain-Pinning (1.85.0) in CI - SA-05: Session-Token vollstaendig aus URIs verbannt (403 Forbidden bei Vorkommen im Pfad/Query) - SA-06: Constant-Time Token- und Auth-Vergleiche via subtle::ConstantTimeEq - SA-07: Dokumentations-Klarstellung bzgl. logischem Shredding vs. physischer SSD/FTL/CoW-Persistenz
This commit is contained in:
+185
-63
@@ -101,11 +101,7 @@ pub fn check_password_prefix_collision(pass0: &str, pass1: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
/// Leitet aus dem Master-Passwort und dem Salt einen 256-Bit Key Encryption Key (KEK) via Argon2id ab.
|
||||
pub fn derive_kek(
|
||||
password: &str,
|
||||
salt: &[u8],
|
||||
params: &KdfParams,
|
||||
) -> Result<Zeroizing<[u8; 32]>> {
|
||||
pub fn derive_kek(password: &str, salt: &[u8], params: &KdfParams) -> Result<Zeroizing<[u8; 32]>> {
|
||||
validate_kdf_params(params)?;
|
||||
|
||||
let argon2_params = Params::new(
|
||||
@@ -145,10 +141,7 @@ pub fn generate_salt() -> [u8; 16] {
|
||||
}
|
||||
|
||||
/// Verschlüsselt beliebige Schlüsseldaten (32B DEK, 40B Slot0-Payload oder 72B Slot1-Payload) via AES-256-GCM.
|
||||
pub fn wrap_key_payload(
|
||||
kek: &[u8; 32],
|
||||
payload: &[u8],
|
||||
) -> Result<(Vec<u8>, [u8; 12], [u8; 16])> {
|
||||
pub fn wrap_key_payload(kek: &[u8; 32], payload: &[u8]) -> Result<(Vec<u8>, [u8; 12], [u8; 16])> {
|
||||
let cipher = Aes256Gcm::new_from_slice(kek)
|
||||
.map_err(|e| anyhow::anyhow!("AES-GCM Initialisierungsfehler: {e}"))?;
|
||||
|
||||
@@ -183,17 +176,18 @@ pub fn unwrap_key_payload(
|
||||
let mut buffer = wrapped_payload.to_vec();
|
||||
cipher
|
||||
.decrypt_in_place_detached(nonce, b"SANCTUM_HEADER_DEK", &mut buffer, tag)
|
||||
.map_err(|_| anyhow::anyhow!("Passwort falsch oder Header beschädigt (AEAD Authentifizierungsfehler)"))?;
|
||||
.map_err(|_| {
|
||||
anyhow::anyhow!(
|
||||
"Passwort falsch oder Header beschädigt (AEAD Authentifizierungsfehler)"
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(Zeroizing::new(buffer))
|
||||
}
|
||||
|
||||
/// Verschlüsselt den DEK (32 Bytes) mit dem KEK via AES-256-GCM.
|
||||
/// Gibt (wrapped_dek_32_bytes, nonce_12_bytes, tag_16_bytes) zurück.
|
||||
pub fn wrap_dek(
|
||||
kek: &[u8; 32],
|
||||
dek: &[u8; 32],
|
||||
) -> Result<(Vec<u8>, [u8; 12], [u8; 16])> {
|
||||
pub fn wrap_dek(kek: &[u8; 32], dek: &[u8; 32]) -> Result<(Vec<u8>, [u8; 12], [u8; 16])> {
|
||||
wrap_key_payload(kek, dek)
|
||||
}
|
||||
|
||||
@@ -206,7 +200,10 @@ pub fn unwrap_dek(
|
||||
) -> Result<Zeroizing<[u8; 32]>> {
|
||||
let payload = unwrap_key_payload(kek, wrapped_dek, nonce_bytes, tag_bytes)?;
|
||||
if payload.len() < 32 {
|
||||
bail!("Ungültige wrapped_dek Länge: erwartet mindestens 32 Bytes, erhalten {}", payload.len());
|
||||
bail!(
|
||||
"Ungültige wrapped_dek Länge: erwartet mindestens 32 Bytes, erhalten {}",
|
||||
payload.len()
|
||||
);
|
||||
}
|
||||
|
||||
let mut dek = Zeroizing::new([0u8; 32]);
|
||||
@@ -265,7 +262,8 @@ pub fn build_name_aad(parent_id: i64) -> [u8; 16] {
|
||||
aad
|
||||
}
|
||||
|
||||
static ALLOW_LEGACY_NAMES: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
|
||||
static ALLOW_LEGACY_NAMES: std::sync::atomic::AtomicBool =
|
||||
std::sync::atomic::AtomicBool::new(false);
|
||||
|
||||
/// Aktiviert oder deaktiviert den veralteten AAD-Fallback für Dateinamen (S-10).
|
||||
pub fn set_allow_legacy_names(allow: bool) {
|
||||
@@ -289,7 +287,11 @@ pub fn encrypt_node_name(dek: &[u8; 32], parent_id: i64, name: &str) -> String {
|
||||
};
|
||||
let mut buffer = name.as_bytes().to_vec();
|
||||
let aad = build_name_aad(parent_id);
|
||||
let tag = match cipher.encrypt_in_place_detached(Nonce::from_slice(&nonce_bytes), &aad, &mut buffer) {
|
||||
let tag = match cipher.encrypt_in_place_detached(
|
||||
Nonce::from_slice(&nonce_bytes),
|
||||
&aad,
|
||||
&mut buffer,
|
||||
) {
|
||||
Ok(t) => t,
|
||||
Err(_) => return String::new(),
|
||||
};
|
||||
@@ -303,7 +305,12 @@ pub fn encrypt_node_name(dek: &[u8; 32], parent_id: i64, name: &str) -> String {
|
||||
/// Entschlüsselt den Dateinamen eines Knotens im Hidden Vault mit AES-256-GCM.
|
||||
/// Prüft primär die kryptografische Bindung an parent_id; bietet optional Fallback
|
||||
/// auf die statische AAD für ältere Container, wenn `allow_legacy` aktiv ist (S-10).
|
||||
pub fn decrypt_node_name_ext(dek: &[u8; 32], parent_id: i64, stored: &str, allow_legacy: bool) -> Option<String> {
|
||||
pub fn decrypt_node_name_ext(
|
||||
dek: &[u8; 32],
|
||||
parent_id: i64,
|
||||
stored: &str,
|
||||
allow_legacy: bool,
|
||||
) -> Option<String> {
|
||||
// Abwärtskompatibilität für alte v0.2.0 $h$<nonce>$<tag>$<ct> Namen
|
||||
if let Some(rest) = stored.strip_prefix("$h$") {
|
||||
let parts: Vec<&str> = rest.split('$').collect();
|
||||
@@ -423,7 +430,11 @@ pub fn levenshtein_distance(a: &str, b: &str) -> usize {
|
||||
|
||||
for i in 1..=m {
|
||||
for j in 1..=n {
|
||||
let cost = if a_chars[i - 1] == b_chars[j - 1] { 0 } else { 1 };
|
||||
let cost = if a_chars[i - 1] == b_chars[j - 1] {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
};
|
||||
dp[i][j] = (dp[i - 1][j] + 1)
|
||||
.min(dp[i][j - 1] + 1)
|
||||
.min(dp[i - 1][j - 1] + cost);
|
||||
@@ -471,10 +482,7 @@ pub fn normalize_mnemonic_phrase(phrase: &str) -> Vec<String> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
cleaned
|
||||
.split_whitespace()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
cleaned.split_whitespace().map(|s| s.to_string()).collect()
|
||||
}
|
||||
|
||||
/// Dekodiert eine 24-Wort BIP-39 Notfall-Wiederherstellungsphrase zurück in den 32-Byte DEK.
|
||||
@@ -500,9 +508,18 @@ pub fn mnemonic_to_dek(phrase: &str) -> Result<Zeroizing<[u8; 32]>> {
|
||||
if !word_list.contains(&word.as_str()) {
|
||||
let suggestion = suggest_bip39_word(word);
|
||||
let msg = if let Some(sug) = suggestion {
|
||||
format!("Wort #{} '{}' ist ungültig (Meinten Sie '{}'?)", idx + 1, word, sug)
|
||||
format!(
|
||||
"Wort #{} '{}' ist ungültig (Meinten Sie '{}'?)",
|
||||
idx + 1,
|
||||
word,
|
||||
sug
|
||||
)
|
||||
} else {
|
||||
format!("Wort #{} '{}' ist ungültig (nicht im BIP-39 Wörterbuch)", idx + 1, word)
|
||||
format!(
|
||||
"Wort #{} '{}' ist ungültig (nicht im BIP-39 Wörterbuch)",
|
||||
idx + 1,
|
||||
word
|
||||
)
|
||||
};
|
||||
invalid_words.push(msg);
|
||||
}
|
||||
@@ -620,7 +637,11 @@ pub fn decrypt_chunk(
|
||||
let mut buffer = ciphertext.to_vec();
|
||||
cipher
|
||||
.decrypt_in_place_detached(nonce, &aad, &mut buffer, tag)
|
||||
.map_err(|_| anyhow::anyhow!("Chunk-Integritätsprüfung fehlgeschlagen (AEAD Auth-Fehler oder Swap-Angriff)"))?;
|
||||
.map_err(|_| {
|
||||
anyhow::anyhow!(
|
||||
"Chunk-Integritätsprüfung fehlgeschlagen (AEAD Auth-Fehler oder Swap-Angriff)"
|
||||
)
|
||||
})?;
|
||||
|
||||
if format_version >= FORMAT_VERSION_V2 {
|
||||
if buffer.is_empty() {
|
||||
@@ -654,7 +675,6 @@ pub fn decrypt_chunk(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -700,26 +720,55 @@ mod tests {
|
||||
encrypt_chunk(&dek, node_id, chunk_index, plaintext, FORMAT_VERSION_V2).unwrap();
|
||||
|
||||
// Reguläre Entschlüsselung (v2)
|
||||
let decrypted =
|
||||
decrypt_chunk(&dek, node_id, chunk_index, &ciphertext, &nonce, &tag, FORMAT_VERSION_V2).unwrap();
|
||||
let decrypted = decrypt_chunk(
|
||||
&dek,
|
||||
node_id,
|
||||
chunk_index,
|
||||
&ciphertext,
|
||||
&nonce,
|
||||
&tag,
|
||||
FORMAT_VERSION_V2,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(decrypted, plaintext);
|
||||
|
||||
// Swap Attack 1: Falsche node_id (Chunk in andere Datei verschoben)
|
||||
let swap_node_err =
|
||||
decrypt_chunk(&dek, 99i64, chunk_index, &ciphertext, &nonce, &tag, FORMAT_VERSION_V2);
|
||||
let swap_node_err = decrypt_chunk(
|
||||
&dek,
|
||||
99i64,
|
||||
chunk_index,
|
||||
&ciphertext,
|
||||
&nonce,
|
||||
&tag,
|
||||
FORMAT_VERSION_V2,
|
||||
);
|
||||
assert!(swap_node_err.is_err());
|
||||
|
||||
// Swap Attack 2: Falscher chunk_index (Chunk innerhalb derselben Datei verschoben)
|
||||
let swap_idx_err =
|
||||
decrypt_chunk(&dek, node_id, 1u32, &ciphertext, &nonce, &tag, FORMAT_VERSION_V2);
|
||||
let swap_idx_err = decrypt_chunk(
|
||||
&dek,
|
||||
node_id,
|
||||
1u32,
|
||||
&ciphertext,
|
||||
&nonce,
|
||||
&tag,
|
||||
FORMAT_VERSION_V2,
|
||||
);
|
||||
assert!(swap_idx_err.is_err());
|
||||
|
||||
// Manipulation des Ciphertexts
|
||||
let mut tampered_ct = ciphertext.clone();
|
||||
tampered_ct[0] ^= 0x01;
|
||||
assert!(
|
||||
decrypt_chunk(&dek, node_id, chunk_index, &tampered_ct, &nonce, &tag, FORMAT_VERSION_V2).is_err()
|
||||
);
|
||||
assert!(decrypt_chunk(
|
||||
&dek,
|
||||
node_id,
|
||||
chunk_index,
|
||||
&tampered_ct,
|
||||
&nonce,
|
||||
&tag,
|
||||
FORMAT_VERSION_V2
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -742,8 +791,16 @@ mod tests {
|
||||
plaintext.len()
|
||||
);
|
||||
|
||||
let decrypted =
|
||||
decrypt_chunk(&dek, node_id, chunk_index, &ciphertext, &nonce, &tag, FORMAT_VERSION_V2).unwrap();
|
||||
let decrypted = decrypt_chunk(
|
||||
&dek,
|
||||
node_id,
|
||||
chunk_index,
|
||||
&ciphertext,
|
||||
&nonce,
|
||||
&tag,
|
||||
FORMAT_VERSION_V2,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(decrypted, plaintext);
|
||||
}
|
||||
|
||||
@@ -754,8 +811,7 @@ mod tests {
|
||||
let mut random_bytes = vec![0u8; 1000];
|
||||
OsRng.fill_bytes(&mut random_bytes);
|
||||
|
||||
let (ct, nonce, tag) =
|
||||
encrypt_chunk(&dek, 1, 0, &random_bytes, FORMAT_VERSION_V2).unwrap();
|
||||
let (ct, nonce, tag) = encrypt_chunk(&dek, 1, 0, &random_bytes, FORMAT_VERSION_V2).unwrap();
|
||||
// Da Kompression keine 64 Bytes spart, wird COMPRESSION_NONE (1 Byte) + Plaintext gespeichert
|
||||
assert_eq!(ct.len(), random_bytes.len() + 1);
|
||||
|
||||
@@ -775,8 +831,16 @@ mod tests {
|
||||
encrypt_chunk(&dek, node_id, chunk_index, plaintext, FORMAT_VERSION_V1).unwrap();
|
||||
assert_eq!(ciphertext.len(), plaintext.len());
|
||||
|
||||
let decrypted =
|
||||
decrypt_chunk(&dek, node_id, chunk_index, &ciphertext, &nonce, &tag, FORMAT_VERSION_V1).unwrap();
|
||||
let decrypted = decrypt_chunk(
|
||||
&dek,
|
||||
node_id,
|
||||
chunk_index,
|
||||
&ciphertext,
|
||||
&nonce,
|
||||
&tag,
|
||||
FORMAT_VERSION_V1,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(decrypted, plaintext);
|
||||
}
|
||||
|
||||
@@ -788,10 +852,17 @@ mod tests {
|
||||
assert_eq!(words.len(), 24, "Mnemonic must have exactly 24 words");
|
||||
|
||||
let recovered_dek = mnemonic_to_dek(&mnemonic_str).expect("Recover DEK");
|
||||
assert_eq!(*dek, *recovered_dek, "Recovered DEK must match original DEK");
|
||||
assert_eq!(
|
||||
*dek, *recovered_dek,
|
||||
"Recovered DEK must match original DEK"
|
||||
);
|
||||
|
||||
// Whitespace-Toleranz (z. B. doppelte Leerzeichen, Zeilenumbrüche)
|
||||
let messy_phrase = format!(" {} \n\t {} ", words[0..12].join(" "), words[12..24].join(" \n "));
|
||||
let messy_phrase = format!(
|
||||
" {} \n\t {} ",
|
||||
words[0..12].join(" "),
|
||||
words[12..24].join(" \n ")
|
||||
);
|
||||
let recovered_messy = mnemonic_to_dek(&messy_phrase).expect("Recover messy");
|
||||
assert_eq!(*dek, *recovered_messy);
|
||||
}
|
||||
@@ -815,9 +886,16 @@ mod tests {
|
||||
.collect();
|
||||
// Tausche das letzte Wort gegen ein anderes gültiges BIP-39 Wort
|
||||
let original_last = words[23].clone();
|
||||
words[23] = if original_last == "abandon" { "zoo".to_string() } else { "abandon".to_string() };
|
||||
words[23] = if original_last == "abandon" {
|
||||
"zoo".to_string()
|
||||
} else {
|
||||
"abandon".to_string()
|
||||
};
|
||||
let corrupted_phrase = words.join(" ");
|
||||
assert!(mnemonic_to_dek(&corrupted_phrase).is_err(), "Checksum check must fail");
|
||||
assert!(
|
||||
mnemonic_to_dek(&corrupted_phrase).is_err(),
|
||||
"Checksum check must fail"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -860,8 +938,14 @@ mod tests {
|
||||
assert_eq!(decrypted, filename);
|
||||
|
||||
// Abwärtskompatibilität: Legacy $h$<nonce>$<tag>$<ct> Format muss weiter entschlüsselt werden
|
||||
let legacy_format = format!("$h${}${}${}", &encrypted[0..24], &encrypted[24..56], &encrypted[56..]);
|
||||
let decrypted_legacy = decrypt_node_name(&dek, parent_id, &legacy_format).expect("Decrypt legacy $h$ name");
|
||||
let legacy_format = format!(
|
||||
"$h${}${}${}",
|
||||
&encrypted[0..24],
|
||||
&encrypted[24..56],
|
||||
&encrypted[56..]
|
||||
);
|
||||
let decrypted_legacy =
|
||||
decrypt_node_name(&dek, parent_id, &legacy_format).expect("Decrypt legacy $h$ name");
|
||||
assert_eq!(decrypted_legacy, filename);
|
||||
|
||||
// Echte statische AAD Legacy-Verschlüsselung (b"SANCTUM_NODE_NAME")
|
||||
@@ -869,7 +953,11 @@ mod tests {
|
||||
let mut static_buf = filename.as_bytes().to_vec();
|
||||
let static_nonce = [42u8; 12];
|
||||
let static_tag = cipher
|
||||
.encrypt_in_place_detached(Nonce::from_slice(&static_nonce), b"SANCTUM_NODE_NAME", &mut static_buf)
|
||||
.encrypt_in_place_detached(
|
||||
Nonce::from_slice(&static_nonce),
|
||||
b"SANCTUM_NODE_NAME",
|
||||
&mut static_buf,
|
||||
)
|
||||
.unwrap();
|
||||
let legacy_static_format = format!(
|
||||
"$h${}${}${}",
|
||||
@@ -882,7 +970,8 @@ mod tests {
|
||||
|
||||
// Mit aktiviertem Legacy-Flag darf es entschlüsselt werden
|
||||
set_allow_legacy_names(true);
|
||||
let decrypted_static = decrypt_node_name(&dek, parent_id, &legacy_static_format).expect("Decrypt legacy static AAD name with flag");
|
||||
let decrypted_static = decrypt_node_name(&dek, parent_id, &legacy_static_format)
|
||||
.expect("Decrypt legacy static AAD name with flag");
|
||||
assert_eq!(decrypted_static, filename);
|
||||
set_allow_legacy_names(false);
|
||||
|
||||
@@ -904,17 +993,33 @@ mod tests {
|
||||
let enc_folder_a = encrypt_node_name(&dek, 10, "secrets.txt");
|
||||
let enc_folder_b = encrypt_node_name(&dek, 20, "passwords.txt");
|
||||
// Gültige parent_ids entschlüsseln erfolgreich
|
||||
assert_eq!(decrypt_node_name(&dek, 10, &enc_folder_a).unwrap(), "secrets.txt");
|
||||
assert_eq!(decrypt_node_name(&dek, 20, &enc_folder_b).unwrap(), "passwords.txt");
|
||||
assert_eq!(
|
||||
decrypt_node_name(&dek, 10, &enc_folder_a).unwrap(),
|
||||
"secrets.txt"
|
||||
);
|
||||
assert_eq!(
|
||||
decrypt_node_name(&dek, 20, &enc_folder_b).unwrap(),
|
||||
"passwords.txt"
|
||||
);
|
||||
|
||||
// Swap-Angriff: Ein Angreifer verschiebt enc_folder_a in Ordner 20
|
||||
assert!(decrypt_node_name(&dek, 20, &enc_folder_a).is_none(), "Swap in anderen Ordner muss durch AAD fehlschlagen!");
|
||||
assert!(decrypt_node_name(&dek, 10, &enc_folder_b).is_none(), "Swap in anderen Ordner muss durch AAD fehlschlagen!");
|
||||
assert!(
|
||||
decrypt_node_name(&dek, 20, &enc_folder_a).is_none(),
|
||||
"Swap in anderen Ordner muss durch AAD fehlschlagen!"
|
||||
);
|
||||
assert!(
|
||||
decrypt_node_name(&dek, 10, &enc_folder_b).is_none(),
|
||||
"Swap in anderen Ordner muss durch AAD fehlschlagen!"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_model_a_slot_payloads() {
|
||||
let test_kdf = KdfParams { memory_cost: MIN_MEMORY_COST_KIB, time_cost: MIN_TIME_COST, parallelism: 1 };
|
||||
let test_kdf = KdfParams {
|
||||
memory_cost: MIN_MEMORY_COST_KIB,
|
||||
time_cost: MIN_TIME_COST,
|
||||
parallelism: 1,
|
||||
};
|
||||
let kek_0 = derive_kek("DecoyPass123!", &generate_salt(), &test_kdf).unwrap();
|
||||
let kek_1 = derive_kek("HiddenPass123!", &generate_salt(), &test_kdf).unwrap();
|
||||
let dek_0 = generate_dek();
|
||||
@@ -922,7 +1027,8 @@ mod tests {
|
||||
let carrier_node_id = 42i64;
|
||||
|
||||
// Slot 0 Payload: 40 Bytes
|
||||
let (wrapped_0, nonce_0, tag_0) = wrap_slot0_payload(&kek_0, &dek_0, carrier_node_id).unwrap();
|
||||
let (wrapped_0, nonce_0, tag_0) =
|
||||
wrap_slot0_payload(&kek_0, &dek_0, carrier_node_id).unwrap();
|
||||
assert_eq!(wrapped_0.len(), 40);
|
||||
|
||||
let unwrapped_0 = unwrap_key_payload(&kek_0, &wrapped_0, &nonce_0, &tag_0).unwrap();
|
||||
@@ -932,7 +1038,8 @@ mod tests {
|
||||
assert_eq!(recovered_cid_0, carrier_node_id);
|
||||
|
||||
// Slot 1 Payload: 72 Bytes
|
||||
let (wrapped_1, nonce_1, tag_1) = wrap_slot1_payload(&kek_1, &dek_1, &dek_0, carrier_node_id).unwrap();
|
||||
let (wrapped_1, nonce_1, tag_1) =
|
||||
wrap_slot1_payload(&kek_1, &dek_1, &dek_0, carrier_node_id).unwrap();
|
||||
assert_eq!(wrapped_1.len(), 72);
|
||||
|
||||
let unwrapped_1 = unwrap_key_payload(&kek_1, &wrapped_1, &nonce_1, &tag_1).unwrap();
|
||||
@@ -964,15 +1071,30 @@ mod tests {
|
||||
let nonce = Nonce::from_slice(&nonce_bytes);
|
||||
|
||||
let mut ct = malicious_plaintext.clone();
|
||||
let tag = cipher.encrypt_in_place_detached(nonce, &aad, &mut ct).unwrap();
|
||||
let tag = cipher
|
||||
.encrypt_in_place_detached(nonce, &aad, &mut ct)
|
||||
.unwrap();
|
||||
let tag_bytes: [u8; 16] = tag.as_slice().try_into().unwrap();
|
||||
|
||||
// Entschlüsselung muss fehlschlagen, da Dekomprimierungs-Bomb-Schutz greift
|
||||
let res = decrypt_chunk(&dek, node_id, chunk_index, &ct, &nonce_bytes, &tag_bytes, FORMAT_VERSION_V2);
|
||||
assert!(res.is_err(), "Dekomprimierungs-Bomb über 1 MB muss abgewiesen werden!");
|
||||
let res = decrypt_chunk(
|
||||
&dek,
|
||||
node_id,
|
||||
chunk_index,
|
||||
&ct,
|
||||
&nonce_bytes,
|
||||
&tag_bytes,
|
||||
FORMAT_VERSION_V2,
|
||||
);
|
||||
assert!(
|
||||
res.is_err(),
|
||||
"Dekomprimierungs-Bomb über 1 MB muss abgewiesen werden!"
|
||||
);
|
||||
let err_msg = res.err().unwrap().to_string();
|
||||
assert!(err_msg.contains("Decompression-Bomb Schutz ausgelöst"), "Fehlermeldung erwartet: {}", err_msg);
|
||||
assert!(
|
||||
err_msg.contains("Decompression-Bomb Schutz ausgelöst"),
|
||||
"Fehlermeldung erwartet: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user