Skip to main content

appcore_dnt/
crypto.rs

1// =============================================================================
2//        #######
3//     ###       ###     F: crypto.rs
4//    ##   ## ##   ##    P: AppCore-Runtime
5//         ## ##
6//                       C: 2026/08/02 00:04:12 by dnettoRaw
7//    ##   ## ##   ##    U: 2026/08/02 00:04:12 by dnettoRaw
8//      ###########      S: 1.0.1-rc.8
9// =============================================================================
10
11//! DNT key-provider contracts and in-memory test provider.
12
13use crate::{DntContext, DntKeyError, DntResult, KeyId};
14use std::collections::HashMap;
15use std::fmt;
16use zeroize::Zeroize;
17
18/// Symmetric 256-bit AEAD key material.
19#[derive(Clone, PartialEq, Eq)]
20pub struct SecretKey([u8; 32]);
21
22impl SecretKey {
23    /// Creates a key from exactly 32 bytes.
24    pub fn new(bytes: [u8; 32]) -> Self {
25        Self(bytes)
26    }
27
28    /// Copies a key from a slice with strict length validation.
29    pub fn from_slice(bytes: &[u8]) -> Result<Self, DntKeyError> {
30        if bytes.len() != 32 {
31            return Err(DntKeyError::InvalidKey);
32        }
33        let mut key = [0u8; 32];
34        key.copy_from_slice(bytes);
35        Ok(Self(key))
36    }
37
38    /// Exposes key bytes to the AEAD implementation.
39    pub fn expose_key(&self) -> &[u8; 32] {
40        &self.0
41    }
42}
43
44impl fmt::Debug for SecretKey {
45    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
46        formatter.write_str("SecretKey(REDACTED)")
47    }
48}
49
50impl Drop for SecretKey {
51    fn drop(&mut self) {
52        self.0.zeroize();
53    }
54}
55
56/// Resolves DNT encryption keys by identity and authenticated context.
57pub trait DntKeyProvider: Send + Sync {
58    /// Resolves one key or returns a controlled key error.
59    fn resolve_key(&self, key_id: &KeyId, context: &DntContext) -> Result<SecretKey, DntKeyError>;
60}
61
62/// Deterministic in-memory provider for tests and development-only adapters.
63#[derive(Clone, Default)]
64pub struct StaticDntKeyProvider {
65    keys: HashMap<KeyId, SecretKey>,
66}
67
68impl fmt::Debug for StaticDntKeyProvider {
69    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
70        formatter
71            .debug_struct("StaticDntKeyProvider")
72            .field("keys", &self.keys.len())
73            .finish()
74    }
75}
76
77impl StaticDntKeyProvider {
78    /// Creates an empty provider.
79    pub fn new() -> Self {
80        Self::default()
81    }
82
83    /// Inserts or replaces one test/development key.
84    pub fn with_key(mut self, key_id: KeyId, key: SecretKey) -> Self {
85        self.keys.insert(key_id, key);
86        self
87    }
88
89    /// Inserts one key into an existing provider.
90    pub fn insert(&mut self, key_id: KeyId, key: SecretKey) -> DntResult<()> {
91        self.keys.insert(key_id, key);
92        Ok(())
93    }
94}
95
96impl DntKeyProvider for StaticDntKeyProvider {
97    fn resolve_key(&self, key_id: &KeyId, _context: &DntContext) -> Result<SecretKey, DntKeyError> {
98        self.keys.get(key_id).cloned().ok_or(DntKeyError::NotFound)
99    }
100}