test(crypto): M-05 — verify schema equality between standard and hidden vault containers
This commit is contained in:
@@ -774,3 +774,155 @@ async fn test_v01_carrier_fs_copy_delegation_and_functionality() {
|
|||||||
let _ = std::fs::remove_file(&path);
|
let _ = std::fs::remove_file(&path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_m05_deniability_schema_equality_standard_vs_hidden() {
|
||||||
|
let path_std = temp_db_path("schema_std");
|
||||||
|
let path_hidden = temp_db_path("schema_hidden");
|
||||||
|
|
||||||
|
let kdf_params = KdfParams {
|
||||||
|
memory_cost: MIN_MEMORY_COST_KIB,
|
||||||
|
time_cost: MIN_TIME_COST,
|
||||||
|
parallelism: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let salt_std = generate_salt();
|
||||||
|
let kek_std = derive_kek("StandardPass123!", &salt_std, &kdf_params).unwrap();
|
||||||
|
let dek_std = generate_dek();
|
||||||
|
let (wrapped_std, nonce_std, tag_std) = wrap_slot0_payload(&kek_std, &dek_std, 0).unwrap();
|
||||||
|
|
||||||
|
let db_std = Database::open(&path_std).expect("Open std db");
|
||||||
|
db_std
|
||||||
|
.init_schema(
|
||||||
|
&salt_std,
|
||||||
|
&kdf_params,
|
||||||
|
&wrapped_std,
|
||||||
|
&nonce_std,
|
||||||
|
&tag_std,
|
||||||
|
)
|
||||||
|
.expect("Init std schema");
|
||||||
|
db_std.checkpoint().unwrap();
|
||||||
|
|
||||||
|
let salt_0 = generate_salt();
|
||||||
|
let kek_0 = derive_kek("DecoyPass123!", &salt_0, &kdf_params).unwrap();
|
||||||
|
let dek_0 = generate_dek();
|
||||||
|
|
||||||
|
let salt_1 = generate_salt();
|
||||||
|
let kek_1 = derive_kek("HiddenPass123!", &salt_1, &kdf_params).unwrap();
|
||||||
|
let dek_1 = generate_dek();
|
||||||
|
|
||||||
|
let carrier_node_id = 3i64;
|
||||||
|
let (wrapped_0, nonce_0, tag_0) = wrap_slot0_payload(&kek_0, &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();
|
||||||
|
|
||||||
|
let db_hidden = Database::open(&path_hidden).expect("Open hidden db");
|
||||||
|
db_hidden
|
||||||
|
.init_schema_with_carrier(
|
||||||
|
&salt_0,
|
||||||
|
&kdf_params,
|
||||||
|
&wrapped_0,
|
||||||
|
&nonce_0,
|
||||||
|
&tag_0,
|
||||||
|
Some((
|
||||||
|
"carrier.dat",
|
||||||
|
1024 * 1024,
|
||||||
|
&salt_1,
|
||||||
|
&kdf_params,
|
||||||
|
&wrapped_1,
|
||||||
|
&nonce_1,
|
||||||
|
&tag_1,
|
||||||
|
&dek_0,
|
||||||
|
&dek_1,
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.expect("Init carrier schema");
|
||||||
|
db_hidden.checkpoint().unwrap();
|
||||||
|
|
||||||
|
// Vergleiche Schemas via rusqlite
|
||||||
|
let conn_std = rusqlite::Connection::open(&path_std).unwrap();
|
||||||
|
let conn_hidden = rusqlite::Connection::open(&path_hidden).unwrap();
|
||||||
|
|
||||||
|
let get_schema_elements = |conn: &rusqlite::Connection| -> Vec<(String, String, Option<String>)> {
|
||||||
|
let mut stmt = conn
|
||||||
|
.prepare(
|
||||||
|
"SELECT type, name, sql FROM sqlite_master
|
||||||
|
WHERE type IN ('table', 'index') AND name NOT LIKE 'sqlite_%'
|
||||||
|
ORDER BY type, name",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let rows = stmt
|
||||||
|
.query_map([], |row| {
|
||||||
|
Ok((
|
||||||
|
row.get::<_, String>(0)?,
|
||||||
|
row.get::<_, String>(1)?,
|
||||||
|
row.get::<_, Option<String>>(2)?,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
rows.map(|r| r.unwrap()).collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
let schema_std = get_schema_elements(&conn_std);
|
||||||
|
let schema_hidden = get_schema_elements(&conn_hidden);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
schema_std, schema_hidden,
|
||||||
|
"M-05: SQLite-Schema (Tabellen, Indizes, DDL) muss zwischen Standard- und Hidden-Vault identisch sein"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Spalten- und Typinformationen vergleichen
|
||||||
|
for table in &["meta", "nodes", "chunks"] {
|
||||||
|
let get_table_info = |conn: &rusqlite::Connection| -> Vec<(i64, String, String, i64, Option<String>, i64)> {
|
||||||
|
let mut stmt = conn.prepare(&format!("PRAGMA table_info({});", table)).unwrap();
|
||||||
|
let rows = stmt
|
||||||
|
.query_map([], |row| {
|
||||||
|
Ok((
|
||||||
|
row.get::<_, i64>(0)?,
|
||||||
|
row.get::<_, String>(1)?,
|
||||||
|
row.get::<_, String>(2)?,
|
||||||
|
row.get::<_, i64>(3)?,
|
||||||
|
row.get::<_, Option<String>>(4)?,
|
||||||
|
row.get::<_, i64>(5)?,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
rows.map(|r| r.unwrap()).collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
let cols_std = get_table_info(&conn_std);
|
||||||
|
let cols_hidden = get_table_info(&conn_hidden);
|
||||||
|
assert_eq!(
|
||||||
|
cols_std, cols_hidden,
|
||||||
|
"M-05: Spalten und Typen für Tabelle '{}' müssen identisch sein",
|
||||||
|
table
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pragmas vergleichen (page_size, auto_vacuum, secure_delete)
|
||||||
|
let get_pragma = |conn: &rusqlite::Connection, pragma: &str| -> i64 {
|
||||||
|
conn.query_row(&format!("PRAGMA {};", pragma), [], |r| r.get(0))
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_pragma(&conn_std, "page_size"),
|
||||||
|
get_pragma(&conn_hidden, "page_size")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
get_pragma(&conn_std, "auto_vacuum"),
|
||||||
|
get_pragma(&conn_hidden, "auto_vacuum")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
get_pragma(&conn_std, "secure_delete"),
|
||||||
|
get_pragma(&conn_hidden, "secure_delete")
|
||||||
|
);
|
||||||
|
|
||||||
|
drop(conn_std);
|
||||||
|
drop(conn_hidden);
|
||||||
|
drop(db_std);
|
||||||
|
drop(db_hidden);
|
||||||
|
|
||||||
|
let _ = std::fs::remove_file(&path_std);
|
||||||
|
let _ = std::fs::remove_file(&path_hidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user