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:
@@ -1,9 +1,9 @@
|
||||
use std::path::PathBuf;
|
||||
use sanctum::crypto::{
|
||||
derive_kek, generate_dek, generate_salt, wrap_dek, KdfParams, MIN_MEMORY_COST_KIB,
|
||||
MIN_TIME_COST,
|
||||
};
|
||||
use sanctum::storage::Database;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
fn test_reject_arbitrary_sqlite_database() {
|
||||
@@ -16,12 +16,10 @@ fn test_reject_arbitrary_sqlite_database() {
|
||||
// Erstelle eine fremde SQLite-Datenbank mit beliebigen Daten
|
||||
{
|
||||
let conn = rusqlite::Connection::open(&db_path).unwrap();
|
||||
conn.execute(
|
||||
"CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)",
|
||||
[],
|
||||
)
|
||||
.unwrap();
|
||||
conn.execute("INSERT INTO users (name) VALUES ('Alice')", []).unwrap();
|
||||
conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)", [])
|
||||
.unwrap();
|
||||
conn.execute("INSERT INTO users (name) VALUES ('Alice')", [])
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// Sanctum Database::open muss die Datei sofort fail-closed ablehnen
|
||||
@@ -114,7 +112,8 @@ fn test_reject_out_of_bounds_kdf_params() {
|
||||
let (wrapped_dek, nonce, tag) = wrap_dek(&kek, &dek).unwrap();
|
||||
|
||||
let db = Database::open(&db_path).unwrap();
|
||||
db.init_schema(&salt, &kdf_params, &wrapped_dek, &nonce, &tag).unwrap();
|
||||
db.init_schema(&salt, &kdf_params, &wrapped_dek, &nonce, &tag)
|
||||
.unwrap();
|
||||
db.checkpoint().unwrap();
|
||||
drop(db);
|
||||
|
||||
@@ -169,7 +168,8 @@ fn test_reject_out_of_bounds_kdf_params() {
|
||||
#[test]
|
||||
fn test_reject_corrupted_slot_lengths() {
|
||||
let temp_dir = std::env::temp_dir();
|
||||
let db_path: PathBuf = temp_dir.join(format!("test_slot_lengths_{}.sanctum", std::process::id()));
|
||||
let db_path: PathBuf =
|
||||
temp_dir.join(format!("test_slot_lengths_{}.sanctum", std::process::id()));
|
||||
if db_path.exists() {
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
}
|
||||
@@ -185,7 +185,8 @@ fn test_reject_corrupted_slot_lengths() {
|
||||
let (wrapped_dek, nonce, tag) = wrap_dek(&kek, &dek).unwrap();
|
||||
|
||||
let db = Database::open(&db_path).unwrap();
|
||||
db.init_schema(&salt, &kdf_params, &wrapped_dek, &nonce, &tag).unwrap();
|
||||
db.init_schema(&salt, &kdf_params, &wrapped_dek, &nonce, &tag)
|
||||
.unwrap();
|
||||
db.checkpoint().unwrap();
|
||||
drop(db);
|
||||
|
||||
@@ -214,3 +215,465 @@ fn test_reject_corrupted_slot_lengths() {
|
||||
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reject_slot_amplification_and_excessive_slots_dos() {
|
||||
let temp_dir = std::env::temp_dir();
|
||||
let salt = generate_salt();
|
||||
let kdf_params = KdfParams {
|
||||
memory_cost: MIN_MEMORY_COST_KIB,
|
||||
time_cost: MIN_TIME_COST,
|
||||
parallelism: 1,
|
||||
};
|
||||
let kek = derive_kek("TestPassword2026!", &salt, &kdf_params).unwrap();
|
||||
let dek = generate_dek();
|
||||
let (wrapped_dek, nonce, tag) = wrap_dek(&kek, &dek).unwrap();
|
||||
let params_json = serde_json::to_string(&kdf_params).unwrap();
|
||||
|
||||
// 1. Fall: 0 Slots (leere meta-Tabelle)
|
||||
{
|
||||
let db_path = temp_dir.join(format!("test_0_slots_{}.sanctum", std::process::id()));
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
{
|
||||
let conn = rusqlite::Connection::open(&db_path).unwrap();
|
||||
conn.execute(
|
||||
"CREATE TABLE meta (
|
||||
slot_id INTEGER PRIMARY KEY, magic BLOB NOT NULL, version INTEGER NOT NULL,
|
||||
kdf_salt BLOB NOT NULL, kdf_params TEXT NOT NULL, wrapped_dek BLOB NOT NULL,
|
||||
header_nonce BLOB NOT NULL, header_tag BLOB NOT NULL
|
||||
);",
|
||||
[],
|
||||
)
|
||||
.unwrap();
|
||||
conn.execute("CREATE TABLE nodes (id INTEGER PRIMARY KEY);", [])
|
||||
.unwrap();
|
||||
conn.execute("CREATE TABLE chunks (node_id INTEGER);", [])
|
||||
.unwrap();
|
||||
}
|
||||
let db = Database::open(&db_path).unwrap();
|
||||
let res = db.read_slots();
|
||||
assert!(res.is_err());
|
||||
let err_msg = res.err().unwrap().to_string();
|
||||
assert!(
|
||||
err_msg.contains("leer oder beschädigt"),
|
||||
"Fehlermeldung: {err_msg}"
|
||||
);
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
}
|
||||
|
||||
// 2. Fall: Genau 1 Slot (Slot 0 Decoy/Standard) -> MUSS erfolgreich sein
|
||||
{
|
||||
let db_path = temp_dir.join(format!("test_1_slot_{}.sanctum", std::process::id()));
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
let db = Database::open(&db_path).unwrap();
|
||||
db.init_schema(&salt, &kdf_params, &wrapped_dek, &nonce, &tag)
|
||||
.unwrap();
|
||||
// Lösche Dummy-Slot 1, um reinen 1-Slot Container zu simulieren
|
||||
{
|
||||
let conn = rusqlite::Connection::open(&db_path).unwrap();
|
||||
conn.execute("DELETE FROM meta WHERE slot_id = 1", [])
|
||||
.unwrap();
|
||||
}
|
||||
let db_reopened = Database::open(&db_path).unwrap();
|
||||
let slots = db_reopened
|
||||
.read_slots()
|
||||
.expect("1 gültiger Slot (Slot 0) muss erfolgreich gelesen werden");
|
||||
assert_eq!(slots.len(), 1);
|
||||
assert_eq!(slots[0].slot_id, 0);
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
}
|
||||
|
||||
// 3. Fall: Genau 2 Slots (Slot 0 & Slot 1) -> MUSS erfolgreich sein
|
||||
{
|
||||
let db_path = temp_dir.join(format!("test_2_slots_{}.sanctum", std::process::id()));
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
let db = Database::open(&db_path).unwrap();
|
||||
db.init_schema(&salt, &kdf_params, &wrapped_dek, &nonce, &tag)
|
||||
.unwrap();
|
||||
let slots = db
|
||||
.read_slots()
|
||||
.expect("2 gültige Slots müssen erfolgreich gelesen werden");
|
||||
assert_eq!(slots.len(), 2);
|
||||
assert_eq!(slots[0].slot_id, 0);
|
||||
assert_eq!(slots[1].slot_id, 1);
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
}
|
||||
|
||||
// 4. Fall: 3 Slots (Überschreitung des Limits von 2) -> MUSS fail-closed abgewehrt werden
|
||||
{
|
||||
let db_path = temp_dir.join(format!("test_3_slots_{}.sanctum", std::process::id()));
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
{
|
||||
let conn = rusqlite::Connection::open(&db_path).unwrap();
|
||||
conn.execute(
|
||||
"CREATE TABLE meta (
|
||||
slot_id INTEGER, magic BLOB NOT NULL, version INTEGER NOT NULL,
|
||||
kdf_salt BLOB NOT NULL, kdf_params TEXT NOT NULL, wrapped_dek BLOB NOT NULL,
|
||||
header_nonce BLOB NOT NULL, header_tag BLOB NOT NULL
|
||||
);",
|
||||
[],
|
||||
)
|
||||
.unwrap();
|
||||
for i in 0..3 {
|
||||
conn.execute(
|
||||
"INSERT INTO meta VALUES (?1, ?2, 2, ?3, ?4, ?5, ?6, ?7)",
|
||||
rusqlite::params![
|
||||
i,
|
||||
b"SANCTUM\0",
|
||||
&salt[..],
|
||||
¶ms_json,
|
||||
&wrapped_dek[..],
|
||||
&nonce[..],
|
||||
&tag[..]
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
let open_res = Database::open(&db_path);
|
||||
assert!(
|
||||
open_res.is_err(),
|
||||
"Database::open muss 3 Slots sofort abweisen"
|
||||
);
|
||||
let err_msg = open_res.err().unwrap().to_string();
|
||||
assert!(
|
||||
err_msg.contains("Ungültige Slot-Anzahl"),
|
||||
"Fehlermeldung: {err_msg}"
|
||||
);
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
}
|
||||
|
||||
// 5. Fall: 100 Slots (KDF-Amplification DoS Angriff) -> MUSS sofort ohne KDF abgewehrt werden
|
||||
{
|
||||
let db_path = temp_dir.join(format!("test_100_slots_{}.sanctum", std::process::id()));
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
{
|
||||
let conn = rusqlite::Connection::open(&db_path).unwrap();
|
||||
conn.execute(
|
||||
"CREATE TABLE meta (
|
||||
slot_id INTEGER, magic BLOB NOT NULL, version INTEGER NOT NULL,
|
||||
kdf_salt BLOB NOT NULL, kdf_params TEXT NOT NULL, wrapped_dek BLOB NOT NULL,
|
||||
header_nonce BLOB NOT NULL, header_tag BLOB NOT NULL
|
||||
);",
|
||||
[],
|
||||
)
|
||||
.unwrap();
|
||||
for i in 0..100 {
|
||||
conn.execute(
|
||||
"INSERT INTO meta VALUES (?1, ?2, 2, ?3, ?4, ?5, ?6, ?7)",
|
||||
rusqlite::params![
|
||||
i,
|
||||
b"SANCTUM\0",
|
||||
&salt[..],
|
||||
¶ms_json,
|
||||
&wrapped_dek[..],
|
||||
&nonce[..],
|
||||
&tag[..]
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
let open_res = Database::open(&db_path);
|
||||
assert!(
|
||||
open_res.is_err(),
|
||||
"100 Slots müssen sofort abgewiesen werden"
|
||||
);
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
}
|
||||
|
||||
// 6. Fall: 1000 Slots (Massiver DoS-Angriff) -> MUSS sofort abgewehrt werden
|
||||
{
|
||||
let db_path = temp_dir.join(format!("test_1000_slots_{}.sanctum", std::process::id()));
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
{
|
||||
let conn = rusqlite::Connection::open(&db_path).unwrap();
|
||||
conn.execute(
|
||||
"CREATE TABLE meta (
|
||||
slot_id INTEGER, magic BLOB NOT NULL, version INTEGER NOT NULL,
|
||||
kdf_salt BLOB NOT NULL, kdf_params TEXT NOT NULL, wrapped_dek BLOB NOT NULL,
|
||||
header_nonce BLOB NOT NULL, header_tag BLOB NOT NULL
|
||||
);",
|
||||
[],
|
||||
)
|
||||
.unwrap();
|
||||
let mut stmt = conn
|
||||
.prepare("INSERT INTO meta VALUES (?1, ?2, 2, ?3, ?4, ?5, ?6, ?7)")
|
||||
.unwrap();
|
||||
for i in 0..1000 {
|
||||
stmt.execute(rusqlite::params![
|
||||
i,
|
||||
b"SANCTUM\0",
|
||||
&salt[..],
|
||||
¶ms_json,
|
||||
&wrapped_dek[..],
|
||||
&nonce[..],
|
||||
&tag[..]
|
||||
])
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
let open_res = Database::open(&db_path);
|
||||
assert!(
|
||||
open_res.is_err(),
|
||||
"1000 Slots müssen sofort abgewiesen werden"
|
||||
);
|
||||
let err_msg = open_res.err().unwrap().to_string();
|
||||
assert!(
|
||||
err_msg.contains("Ungültige Slot-Anzahl"),
|
||||
"Fehlermeldung: {err_msg}"
|
||||
);
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reject_duplicate_and_invalid_slot_ids() {
|
||||
let temp_dir = std::env::temp_dir();
|
||||
let salt = generate_salt();
|
||||
let kdf_params = KdfParams {
|
||||
memory_cost: MIN_MEMORY_COST_KIB,
|
||||
time_cost: MIN_TIME_COST,
|
||||
parallelism: 1,
|
||||
};
|
||||
let kek = derive_kek("TestPassword2026!", &salt, &kdf_params).unwrap();
|
||||
let dek = generate_dek();
|
||||
let (wrapped_dek, nonce, tag) = wrap_dek(&kek, &dek).unwrap();
|
||||
let params_json = serde_json::to_string(&kdf_params).unwrap();
|
||||
|
||||
// 1. Fall: Doppelte Slot-ID (zwei Slots mit slot_id = 0)
|
||||
{
|
||||
let db_path = temp_dir.join(format!("test_dup_slot_0_{}.sanctum", std::process::id()));
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
{
|
||||
let conn = rusqlite::Connection::open(&db_path).unwrap();
|
||||
conn.execute(
|
||||
"CREATE TABLE meta (
|
||||
slot_id INTEGER, magic BLOB NOT NULL, version INTEGER NOT NULL,
|
||||
kdf_salt BLOB NOT NULL, kdf_params TEXT NOT NULL, wrapped_dek BLOB NOT NULL,
|
||||
header_nonce BLOB NOT NULL, header_tag BLOB NOT NULL
|
||||
);",
|
||||
[],
|
||||
)
|
||||
.unwrap();
|
||||
conn.execute(
|
||||
"INSERT INTO meta VALUES (0, ?1, 2, ?2, ?3, ?4, ?5, ?6)",
|
||||
rusqlite::params![
|
||||
b"SANCTUM\0",
|
||||
&salt[..],
|
||||
¶ms_json,
|
||||
&wrapped_dek[..],
|
||||
&nonce[..],
|
||||
&tag[..]
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
conn.execute(
|
||||
"INSERT INTO meta VALUES (0, ?1, 2, ?2, ?3, ?4, ?5, ?6)",
|
||||
rusqlite::params![
|
||||
b"SANCTUM\0",
|
||||
&salt[..],
|
||||
¶ms_json,
|
||||
&wrapped_dek[..],
|
||||
&nonce[..],
|
||||
&tag[..]
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
let db = Database::open(&db_path).unwrap();
|
||||
let res = db.read_slots();
|
||||
assert!(res.is_err(), "Doppelte Slot-ID 0 muss abgewiesen werden");
|
||||
let err_msg = res.err().unwrap().to_string();
|
||||
assert!(
|
||||
err_msg.contains("Doppelte Slot-ID 0"),
|
||||
"Fehlermeldung: {err_msg}"
|
||||
);
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
}
|
||||
|
||||
// 2. Fall: Ungültige Slot-ID (z. B. slot_id = 5 statt 0 oder 1)
|
||||
{
|
||||
let db_path = temp_dir.join(format!(
|
||||
"test_invalid_slot_id_{}.sanctum",
|
||||
std::process::id()
|
||||
));
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
{
|
||||
let conn = rusqlite::Connection::open(&db_path).unwrap();
|
||||
conn.execute(
|
||||
"CREATE TABLE meta (
|
||||
slot_id INTEGER, magic BLOB NOT NULL, version INTEGER NOT NULL,
|
||||
kdf_salt BLOB NOT NULL, kdf_params TEXT NOT NULL, wrapped_dek BLOB NOT NULL,
|
||||
header_nonce BLOB NOT NULL, header_tag BLOB NOT NULL
|
||||
);",
|
||||
[],
|
||||
)
|
||||
.unwrap();
|
||||
conn.execute(
|
||||
"INSERT INTO meta VALUES (5, ?1, 2, ?2, ?3, ?4, ?5, ?6)",
|
||||
rusqlite::params![
|
||||
b"SANCTUM\0",
|
||||
&salt[..],
|
||||
¶ms_json,
|
||||
&wrapped_dek[..],
|
||||
&nonce[..],
|
||||
&tag[..]
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
let db = Database::open(&db_path).unwrap();
|
||||
let res = db.read_slots();
|
||||
assert!(res.is_err(), "Ungültige Slot-ID 5 muss abgewiesen werden");
|
||||
let err_msg = res.err().unwrap().to_string();
|
||||
assert!(
|
||||
err_msg.contains("Ungültige Slot-ID 5"),
|
||||
"Fehlermeldung: {err_msg}"
|
||||
);
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
}
|
||||
|
||||
// 3. Fall: Fehlender Slot 0 (nur Slot 1 vorhanden)
|
||||
{
|
||||
let db_path = temp_dir.join(format!(
|
||||
"test_missing_slot_0_{}.sanctum",
|
||||
std::process::id()
|
||||
));
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
{
|
||||
let conn = rusqlite::Connection::open(&db_path).unwrap();
|
||||
conn.execute(
|
||||
"CREATE TABLE meta (
|
||||
slot_id INTEGER, magic BLOB NOT NULL, version INTEGER NOT NULL,
|
||||
kdf_salt BLOB NOT NULL, kdf_params TEXT NOT NULL, wrapped_dek BLOB NOT NULL,
|
||||
header_nonce BLOB NOT NULL, header_tag BLOB NOT NULL
|
||||
);",
|
||||
[],
|
||||
)
|
||||
.unwrap();
|
||||
conn.execute(
|
||||
"INSERT INTO meta VALUES (1, ?1, 2, ?2, ?3, ?4, ?5, ?6)",
|
||||
rusqlite::params![
|
||||
b"SANCTUM\0",
|
||||
&salt[..],
|
||||
¶ms_json,
|
||||
&wrapped_dek[..],
|
||||
&nonce[..],
|
||||
&tag[..]
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
let db = Database::open(&db_path).unwrap();
|
||||
let res = db.read_slots();
|
||||
assert!(res.is_err(), "Fehlender Slot 0 muss abgewiesen werden");
|
||||
let err_msg = res.err().unwrap().to_string();
|
||||
assert!(
|
||||
err_msg.contains("Slot 0 (Standard/Decoy Vault) fehlt"),
|
||||
"Fehlermeldung: {err_msg}"
|
||||
);
|
||||
let _ = std::fs::remove_file(&db_path);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_container_meta_authenticate_defense_in_depth() {
|
||||
use sanctum::storage::{ContainerMeta, SlotMeta};
|
||||
|
||||
let salt = generate_salt();
|
||||
let kdf_params = KdfParams {
|
||||
memory_cost: MIN_MEMORY_COST_KIB,
|
||||
time_cost: MIN_TIME_COST,
|
||||
parallelism: 1,
|
||||
};
|
||||
let kek = derive_kek("TestPassword2026!", &salt, &kdf_params).unwrap();
|
||||
let dek = generate_dek();
|
||||
let (wrapped_dek, nonce, tag) = wrap_dek(&kek, &dek).unwrap();
|
||||
|
||||
let valid_slot_0 = SlotMeta {
|
||||
slot_id: 0,
|
||||
version: 2,
|
||||
kdf_salt: salt,
|
||||
kdf_params: kdf_params.clone(),
|
||||
wrapped_dek: wrapped_dek.clone(),
|
||||
header_nonce: nonce,
|
||||
header_tag: tag,
|
||||
};
|
||||
|
||||
let valid_slot_1 = SlotMeta {
|
||||
slot_id: 1,
|
||||
version: 2,
|
||||
kdf_salt: salt,
|
||||
kdf_params: kdf_params.clone(),
|
||||
wrapped_dek: wrapped_dek.clone(),
|
||||
header_nonce: nonce,
|
||||
header_tag: tag,
|
||||
};
|
||||
|
||||
// A. Leere Slots -> sofort None
|
||||
let meta_empty = ContainerMeta {
|
||||
version: 2,
|
||||
kdf_salt: salt,
|
||||
kdf_params: kdf_params.clone(),
|
||||
wrapped_dek: wrapped_dek.clone(),
|
||||
header_nonce: nonce,
|
||||
header_tag: tag,
|
||||
slots: vec![],
|
||||
};
|
||||
assert!(meta_empty.authenticate("TestPassword2026!").is_none());
|
||||
|
||||
// B. Mehr als 2 Slots -> sofort None (keine KDF-Berechnung!)
|
||||
let meta_3_slots = ContainerMeta {
|
||||
version: 2,
|
||||
kdf_salt: salt,
|
||||
kdf_params: kdf_params.clone(),
|
||||
wrapped_dek: wrapped_dek.clone(),
|
||||
header_nonce: nonce,
|
||||
header_tag: tag,
|
||||
slots: vec![
|
||||
valid_slot_0.clone(),
|
||||
valid_slot_1.clone(),
|
||||
valid_slot_0.clone(),
|
||||
],
|
||||
};
|
||||
assert!(meta_3_slots.authenticate("TestPassword2026!").is_none());
|
||||
|
||||
// C. Fehlender Slot 0 (nur Slot 1) -> sofort None
|
||||
let meta_no_slot0 = ContainerMeta {
|
||||
version: 2,
|
||||
kdf_salt: salt,
|
||||
kdf_params: kdf_params.clone(),
|
||||
wrapped_dek: wrapped_dek.clone(),
|
||||
header_nonce: nonce,
|
||||
header_tag: tag,
|
||||
slots: vec![valid_slot_1.clone()],
|
||||
};
|
||||
assert!(meta_no_slot0.authenticate("TestPassword2026!").is_none());
|
||||
|
||||
// D. Ungültige Slot-ID (> 1) -> sofort None
|
||||
let mut invalid_slot = valid_slot_0.clone();
|
||||
invalid_slot.slot_id = 99;
|
||||
let meta_invalid_id = ContainerMeta {
|
||||
version: 2,
|
||||
kdf_salt: salt,
|
||||
kdf_params: kdf_params.clone(),
|
||||
wrapped_dek: wrapped_dek.clone(),
|
||||
header_nonce: nonce,
|
||||
header_tag: tag,
|
||||
slots: vec![valid_slot_0.clone(), invalid_slot],
|
||||
};
|
||||
assert!(meta_invalid_id.authenticate("TestPassword2026!").is_none());
|
||||
|
||||
// E. Korrekter 1-Slot Container -> Erfolgreiche Authentifizierung
|
||||
let meta_valid_1 = ContainerMeta {
|
||||
version: 2,
|
||||
kdf_salt: salt,
|
||||
kdf_params: kdf_params.clone(),
|
||||
wrapped_dek: wrapped_dek.clone(),
|
||||
header_nonce: nonce,
|
||||
header_tag: tag,
|
||||
slots: vec![valid_slot_0.clone()],
|
||||
};
|
||||
assert!(meta_valid_1.authenticate("TestPassword2026!").is_some());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user