feat(secret): add alknet-secret crate and architecture spec for Phase 3
Create the alknet-secret crate with BIP39 mnemonic generation, SLIP-0010 Ed25519 HD key derivation, AES-256-GCM encryption, and SecretProtocol irpc service definition. This is Phase 3.1 from the integration plan. Architecture changes: - Promote secret-service.md to reviewed status with full spec format (crate structure, public API, security model, phase progression, ADR/OQ cross-references, wire format compatibility section) - Add ADR-038 (seed lifecycle and memory security): zeroize for v1, mlock deferred to Phase B - Add OQ-SEC-01 (mlock/VirtualLock for seed RAM) to open-questions.md - Update README.md with ADR-038 and secret-service status Crate structure: - src/mnemonic.rs: BIP39 phrase generation, validation, seed derivation - src/derivation.rs: SLIP-0010 HD key derivation, path constants (74') - src/encryption.rs: AES-256-GCM encrypt/decrypt, EncryptedData type - src/protocol.rs: SecretProtocol irpc enum, DerivedKey, KeyType - src/service.rs: SecretServiceHandle with Unlock/Lock lifecycle - 40 passing tests (unit + integration + doc)
This commit is contained in:
58
crates/alknet-secret/tests/encryption_tests.rs
Normal file
58
crates/alknet-secret/tests/encryption_tests.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
//! Integration tests for AES-256-GCM encryption and decryption.
|
||||
//!
|
||||
//! These tests verify round-trip encryption, key version handling,
|
||||
//! and wire format compatibility.
|
||||
|
||||
use alknet_secret::encryption::CURRENT_KEY_VERSION;
|
||||
use alknet_secret::service::SecretServiceHandle;
|
||||
|
||||
#[test]
|
||||
fn test_encrypt_decrypt_round_trip_via_service() {
|
||||
let service = SecretServiceHandle::new();
|
||||
service.unlock_new(24).unwrap();
|
||||
|
||||
let plaintext = "sk-proj-abc123xyz789";
|
||||
|
||||
let encrypted = service.encrypt(plaintext, CURRENT_KEY_VERSION).unwrap();
|
||||
let decrypted = service.decrypt(&encrypted).unwrap();
|
||||
|
||||
assert_eq!(decrypted, plaintext);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encrypt_produces_different_ciphertext_each_time() {
|
||||
let service = SecretServiceHandle::new();
|
||||
service.unlock_new(24).unwrap();
|
||||
|
||||
let plaintext = "same input different ciphertexts";
|
||||
|
||||
let encrypted1 = service.encrypt(plaintext, CURRENT_KEY_VERSION).unwrap();
|
||||
let encrypted2 = service.encrypt(plaintext, CURRENT_KEY_VERSION).unwrap();
|
||||
|
||||
// Different IVs mean different ciphertexts
|
||||
assert_ne!(encrypted1.iv, encrypted2.iv);
|
||||
assert_ne!(encrypted1.data, encrypted2.data);
|
||||
// But same key version
|
||||
assert_eq!(encrypted1.key_version, encrypted2.key_version);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encrypted_data_serialization() {
|
||||
let service = SecretServiceHandle::new();
|
||||
service.unlock_new(24).unwrap();
|
||||
|
||||
let plaintext = "test serialization";
|
||||
let encrypted = service.encrypt(plaintext, CURRENT_KEY_VERSION).unwrap();
|
||||
|
||||
// Verify EncryptedData serializes to JSON
|
||||
let json = serde_json::to_string(&encrypted).unwrap();
|
||||
assert!(json.contains("key_version"));
|
||||
assert!(json.contains("salt"));
|
||||
assert!(json.contains("iv"));
|
||||
assert!(json.contains("data"));
|
||||
|
||||
// Verify round-trip through JSON
|
||||
let deserialized: alknet_secret::encryption::EncryptedData =
|
||||
serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(deserialized, encrypted);
|
||||
}
|
||||
Reference in New Issue
Block a user