chie_crypto/
abe.rs

1//! Attribute-Based Encryption (ABE) for fine-grained access control.
2//!
3//! This module provides Ciphertext-Policy ABE (CP-ABE), where access policies
4//! are embedded in ciphertexts and user keys are associated with attributes.
5//!
6//! # Overview
7//!
8//! ABE enables encryption to a set of attributes rather than to specific public keys.
9//! Only users whose attributes satisfy the access policy can decrypt.
10//!
11//! # Architecture
12//!
13//! - **Authority**: Generates master keys and issues user keys based on attributes
14//! - **Encryptor**: Encrypts data with an access policy (e.g., "admin AND (vip OR premium)")
15//! - **Decryptor**: Can decrypt if their attributes satisfy the policy
16//!
17//! # Use Cases in CHIE
18//!
19//! - Content access control based on subscription tiers
20//! - Geographic restrictions (region attributes)
21//! - Time-based access (time-period attributes)
22//! - Role-based access (role attributes)
23//!
24//! # Example
25//!
26//! ```
27//! use chie_crypto::abe::{AbeAuthority, AccessPolicy, PolicyNode};
28//!
29//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
30//! // Authority generates master keys
31//! let mut authority = AbeAuthority::new();
32//!
33//! // Issue user key with attributes
34//! let user_attrs = vec!["premium".to_string(), "us-region".to_string()];
35//! let user_key = authority.generate_user_key(&user_attrs)?;
36//!
37//! // Encrypt with policy: premium AND us-region
38//! let policy = AccessPolicy::and(vec![
39//!     PolicyNode::Attribute("premium".to_string()),
40//!     PolicyNode::Attribute("us-region".to_string()),
41//! ]);
42//! let plaintext = b"Premium US content";
43//! let ciphertext = authority.encrypt(&policy, plaintext)?;
44//!
45//! // User can decrypt because they have both attributes
46//! let decrypted = authority.decrypt(&user_key, &ciphertext)?;
47//! assert_eq!(decrypted, plaintext);
48//! # Ok(())
49//! # }
50//! ```
51
52#![allow(dead_code)]
53
54use crate::encryption::{EncryptionKey, decrypt, encrypt, generate_nonce};
55use blake3::Hasher;
56use serde::{Deserialize, Serialize};
57use std::collections::{HashMap, HashSet};
58use thiserror::Error;
59
60/// Errors that can occur in ABE operations.
61#[derive(Debug, Error)]
62pub enum AbeError {
63    #[error("Encryption failed: {0}")]
64    EncryptionFailed(String),
65
66    #[error("Decryption failed: {0}")]
67    DecryptionFailed(String),
68
69    #[error("Policy evaluation failed: {0}")]
70    PolicyFailed(String),
71
72    #[error("Invalid attributes: {0}")]
73    InvalidAttributes(String),
74
75    #[error("Key derivation failed: {0}")]
76    KeyDerivationFailed(String),
77
78    #[error("Serialization error: {0}")]
79    SerializationError(String),
80}
81
82/// Result type for ABE operations.
83pub type AbeResult<T> = Result<T, AbeError>;
84
85/// A node in an access policy tree.
86#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
87pub enum PolicyNode {
88    /// Leaf node: requires a specific attribute
89    Attribute(String),
90    /// AND gate: all children must be satisfied
91    And(Vec<PolicyNode>),
92    /// OR gate: at least one child must be satisfied
93    Or(Vec<PolicyNode>),
94    /// Threshold gate: at least k of n children must be satisfied
95    Threshold { k: usize, children: Vec<PolicyNode> },
96}
97
98impl PolicyNode {
99    /// Evaluate if a set of attributes satisfies this policy node.
100    pub fn evaluate(&self, attributes: &HashSet<String>) -> bool {
101        match self {
102            PolicyNode::Attribute(attr) => attributes.contains(attr),
103            PolicyNode::And(children) => children.iter().all(|c| c.evaluate(attributes)),
104            PolicyNode::Or(children) => children.iter().any(|c| c.evaluate(attributes)),
105            PolicyNode::Threshold { k, children } => {
106                let satisfied = children.iter().filter(|c| c.evaluate(attributes)).count();
107                satisfied >= *k
108            }
109        }
110    }
111
112    /// Get all attributes mentioned in this policy.
113    pub fn get_attributes(&self) -> HashSet<String> {
114        let mut attrs = HashSet::new();
115        self.collect_attributes(&mut attrs);
116        attrs
117    }
118
119    fn collect_attributes(&self, attrs: &mut HashSet<String>) {
120        match self {
121            PolicyNode::Attribute(attr) => {
122                attrs.insert(attr.clone());
123            }
124            PolicyNode::And(children) | PolicyNode::Or(children) => {
125                for child in children {
126                    child.collect_attributes(attrs);
127                }
128            }
129            PolicyNode::Threshold { children, .. } => {
130                for child in children {
131                    child.collect_attributes(attrs);
132                }
133            }
134        }
135    }
136}
137
138/// Access policy for CP-ABE encryption.
139#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct AccessPolicy {
141    /// Root of the policy tree
142    root: PolicyNode,
143}
144
145impl AccessPolicy {
146    /// Create a new access policy from a policy node.
147    pub fn new(root: PolicyNode) -> Self {
148        Self { root }
149    }
150
151    /// Create an AND policy (all attributes required).
152    pub fn and(nodes: Vec<PolicyNode>) -> Self {
153        Self::new(PolicyNode::And(nodes))
154    }
155
156    /// Create an OR policy (any attribute suffices).
157    pub fn or(nodes: Vec<PolicyNode>) -> Self {
158        Self::new(PolicyNode::Or(nodes))
159    }
160
161    /// Create a threshold policy (k-of-n).
162    pub fn threshold(k: usize, children: Vec<PolicyNode>) -> Self {
163        Self::new(PolicyNode::Threshold { k, children })
164    }
165
166    /// Evaluate if attributes satisfy this policy.
167    pub fn evaluate(&self, attributes: &HashSet<String>) -> bool {
168        self.root.evaluate(attributes)
169    }
170
171    /// Get all attributes mentioned in this policy.
172    pub fn get_attributes(&self) -> HashSet<String> {
173        self.root.get_attributes()
174    }
175}
176
177/// Master secret key for ABE authority.
178#[derive(Clone)]
179pub struct MasterSecretKey {
180    /// Secret seed for key derivation
181    seed: [u8; 32],
182}
183
184impl MasterSecretKey {
185    /// Generate a new random master secret key.
186    fn new() -> Self {
187        let mut seed = [0u8; 32];
188        rand::Rng::fill(&mut rand::thread_rng(), &mut seed);
189        Self { seed }
190    }
191
192    /// Derive an attribute key from the master secret.
193    fn derive_attribute_key(&self, attribute: &str) -> [u8; 32] {
194        let mut hasher = Hasher::new();
195        hasher.update(&self.seed);
196        hasher.update(b"attribute:");
197        hasher.update(attribute.as_bytes());
198        *hasher.finalize().as_bytes()
199    }
200}
201
202/// User secret key containing keys for specific attributes.
203#[derive(Clone, Serialize, Deserialize)]
204pub struct UserSecretKey {
205    /// Map from attribute to derived key
206    attribute_keys: HashMap<String, [u8; 32]>,
207}
208
209impl UserSecretKey {
210    /// Create a new user secret key.
211    fn new(attribute_keys: HashMap<String, [u8; 32]>) -> Self {
212        Self { attribute_keys }
213    }
214
215    /// Get the set of attributes this key possesses.
216    pub fn get_attributes(&self) -> HashSet<String> {
217        self.attribute_keys.keys().cloned().collect()
218    }
219
220    /// Check if this key has a specific attribute.
221    pub fn has_attribute(&self, attribute: &str) -> bool {
222        self.attribute_keys.contains_key(attribute)
223    }
224}
225
226/// Encrypted DEK with its nonce.
227#[derive(Clone, Serialize, Deserialize)]
228struct EncryptedDek {
229    /// Encrypted DEK bytes
230    ciphertext: Vec<u8>,
231    /// Nonce used for encryption
232    nonce: [u8; 12],
233}
234
235/// Attribute-based ciphertext.
236#[derive(Clone, Serialize, Deserialize)]
237pub struct AbeCiphertext {
238    /// Access policy for this ciphertext
239    policy: AccessPolicy,
240    /// Encrypted data encryption key for each attribute with nonces
241    encrypted_keys: HashMap<String, EncryptedDek>,
242    /// Encrypted payload
243    ciphertext: Vec<u8>,
244    /// Nonce for payload encryption
245    nonce: [u8; 12],
246}
247
248impl AbeCiphertext {
249    /// Get the access policy for this ciphertext.
250    pub fn policy(&self) -> &AccessPolicy {
251        &self.policy
252    }
253
254    /// Serialize to bytes.
255    pub fn to_bytes(&self) -> AbeResult<Vec<u8>> {
256        crate::codec::encode(self)
257            .map_err(|e| AbeError::SerializationError(format!("Serialization failed: {}", e)))
258    }
259
260    /// Deserialize from bytes.
261    pub fn from_bytes(bytes: &[u8]) -> AbeResult<Self> {
262        crate::codec::decode(bytes)
263            .map_err(|e| AbeError::SerializationError(format!("Deserialization failed: {}", e)))
264    }
265}
266
267/// ABE authority that manages keys and performs encryption/decryption.
268pub struct AbeAuthority {
269    /// Master secret key
270    master_key: MasterSecretKey,
271}
272
273impl AbeAuthority {
274    /// Create a new ABE authority with a random master key.
275    pub fn new() -> Self {
276        Self {
277            master_key: MasterSecretKey::new(),
278        }
279    }
280
281    /// Create an authority from existing master key bytes.
282    pub fn from_master_key(seed: [u8; 32]) -> Self {
283        Self {
284            master_key: MasterSecretKey { seed },
285        }
286    }
287
288    /// Generate a user secret key for a set of attributes.
289    pub fn generate_user_key(&self, attributes: &[String]) -> AbeResult<UserSecretKey> {
290        if attributes.is_empty() {
291            return Err(AbeError::InvalidAttributes(
292                "Attributes list cannot be empty".to_string(),
293            ));
294        }
295
296        let mut attribute_keys = HashMap::new();
297        for attr in attributes {
298            let key = self.master_key.derive_attribute_key(attr);
299            attribute_keys.insert(attr.clone(), key);
300        }
301
302        Ok(UserSecretKey::new(attribute_keys))
303    }
304
305    /// Encrypt data with an access policy.
306    pub fn encrypt(&self, policy: &AccessPolicy, plaintext: &[u8]) -> AbeResult<AbeCiphertext> {
307        // Generate random data encryption key
308        let mut dek = [0u8; 32];
309        rand::Rng::fill(&mut rand::thread_rng(), &mut dek);
310
311        // Generate nonce
312        let nonce = generate_nonce();
313
314        // Encrypt plaintext with DEK
315        let encryption_key = EncryptionKey::from(dek);
316        let ciphertext = encrypt(plaintext, &encryption_key, &nonce)
317            .map_err(|e| AbeError::EncryptionFailed(format!("Failed to encrypt: {}", e)))?;
318
319        // Encrypt DEK for each attribute in the policy
320        let mut encrypted_keys = HashMap::new();
321        for attr in policy.get_attributes() {
322            let attr_key = self.master_key.derive_attribute_key(&attr);
323
324            // Derive encryption key from attribute key
325            let attr_enc_key = EncryptionKey::from(attr_key);
326
327            // Generate unique nonce for this attribute
328            let attr_nonce = generate_nonce();
329
330            let encrypted_dek_bytes = encrypt(&dek, &attr_enc_key, &attr_nonce)
331                .map_err(|e| AbeError::EncryptionFailed(format!("Failed to encrypt DEK: {}", e)))?;
332
333            encrypted_keys.insert(
334                attr,
335                EncryptedDek {
336                    ciphertext: encrypted_dek_bytes,
337                    nonce: attr_nonce,
338                },
339            );
340        }
341
342        Ok(AbeCiphertext {
343            policy: policy.clone(),
344            encrypted_keys,
345            ciphertext,
346            nonce,
347        })
348    }
349
350    /// Decrypt ciphertext using a user secret key.
351    pub fn decrypt(
352        &self,
353        user_key: &UserSecretKey,
354        ciphertext: &AbeCiphertext,
355    ) -> AbeResult<Vec<u8>> {
356        // Check if user attributes satisfy the policy
357        let user_attrs = user_key.get_attributes();
358        if !ciphertext.policy.evaluate(&user_attrs) {
359            return Err(AbeError::DecryptionFailed(
360                "User attributes do not satisfy access policy".to_string(),
361            ));
362        }
363
364        // Find an attribute the user has that can decrypt the DEK
365        let mut dek = None;
366        for (attr, attr_key) in &user_key.attribute_keys {
367            if let Some(encrypted_dek) = ciphertext.encrypted_keys.get(attr) {
368                // Try to decrypt the DEK with this attribute key
369                let attr_enc_key = EncryptionKey::from(*attr_key);
370
371                // Try to decrypt the DEK
372                let decrypted = decrypt(
373                    &encrypted_dek.ciphertext,
374                    &attr_enc_key,
375                    &encrypted_dek.nonce,
376                );
377
378                if let Ok(dek_bytes) = decrypted {
379                    if dek_bytes.len() == 32 {
380                        let mut dek_arr = [0u8; 32];
381                        dek_arr.copy_from_slice(&dek_bytes);
382                        dek = Some(dek_arr);
383                        break;
384                    }
385                }
386            }
387        }
388
389        let dek = dek.ok_or_else(|| {
390            AbeError::DecryptionFailed("Could not recover data encryption key".to_string())
391        })?;
392
393        // Decrypt the payload
394        let encryption_key = EncryptionKey::from(dek);
395        decrypt(&ciphertext.ciphertext, &encryption_key, &ciphertext.nonce)
396            .map_err(|e| AbeError::DecryptionFailed(format!("Failed to decrypt payload: {}", e)))
397    }
398
399    /// Get the master key seed (for backup/recovery).
400    pub fn export_master_key(&self) -> [u8; 32] {
401        self.master_key.seed
402    }
403}
404
405impl Default for AbeAuthority {
406    fn default() -> Self {
407        Self::new()
408    }
409}
410
411#[cfg(test)]
412mod tests {
413    use super::*;
414
415    #[test]
416    fn test_policy_evaluation_single_attribute() {
417        let policy = PolicyNode::Attribute("admin".to_string());
418
419        let mut attrs = HashSet::new();
420        attrs.insert("admin".to_string());
421        assert!(policy.evaluate(&attrs));
422
423        attrs.clear();
424        attrs.insert("user".to_string());
425        assert!(!policy.evaluate(&attrs));
426    }
427
428    #[test]
429    fn test_policy_evaluation_and() {
430        let policy = PolicyNode::And(vec![
431            PolicyNode::Attribute("admin".to_string()),
432            PolicyNode::Attribute("premium".to_string()),
433        ]);
434
435        let mut attrs = HashSet::new();
436        attrs.insert("admin".to_string());
437        attrs.insert("premium".to_string());
438        assert!(policy.evaluate(&attrs));
439
440        attrs.clear();
441        attrs.insert("admin".to_string());
442        assert!(!policy.evaluate(&attrs));
443    }
444
445    #[test]
446    fn test_policy_evaluation_or() {
447        let policy = PolicyNode::Or(vec![
448            PolicyNode::Attribute("admin".to_string()),
449            PolicyNode::Attribute("moderator".to_string()),
450        ]);
451
452        let mut attrs = HashSet::new();
453        attrs.insert("admin".to_string());
454        assert!(policy.evaluate(&attrs));
455
456        attrs.clear();
457        attrs.insert("moderator".to_string());
458        assert!(policy.evaluate(&attrs));
459
460        attrs.clear();
461        attrs.insert("user".to_string());
462        assert!(!policy.evaluate(&attrs));
463    }
464
465    #[test]
466    fn test_policy_evaluation_threshold() {
467        let policy = PolicyNode::Threshold {
468            k: 2,
469            children: vec![
470                PolicyNode::Attribute("admin".to_string()),
471                PolicyNode::Attribute("moderator".to_string()),
472                PolicyNode::Attribute("premium".to_string()),
473            ],
474        };
475
476        let mut attrs = HashSet::new();
477        attrs.insert("admin".to_string());
478        attrs.insert("moderator".to_string());
479        assert!(policy.evaluate(&attrs));
480
481        attrs.clear();
482        attrs.insert("admin".to_string());
483        assert!(!policy.evaluate(&attrs));
484    }
485
486    #[test]
487    fn test_user_key_generation() {
488        let authority = AbeAuthority::new();
489        let attrs = vec!["admin".to_string(), "premium".to_string()];
490
491        let user_key = authority.generate_user_key(&attrs).unwrap();
492        assert_eq!(user_key.get_attributes().len(), 2);
493        assert!(user_key.has_attribute("admin"));
494        assert!(user_key.has_attribute("premium"));
495        assert!(!user_key.has_attribute("user"));
496    }
497
498    #[test]
499    fn test_encrypt_decrypt_simple() {
500        let authority = AbeAuthority::new();
501
502        let policy = AccessPolicy::new(PolicyNode::Attribute("premium".to_string()));
503        let user_key = authority
504            .generate_user_key(&["premium".to_string()])
505            .unwrap();
506
507        let plaintext = b"Secret premium content";
508        let ciphertext = authority.encrypt(&policy, plaintext).unwrap();
509        let decrypted = authority.decrypt(&user_key, &ciphertext).unwrap();
510
511        assert_eq!(decrypted, plaintext);
512    }
513
514    #[test]
515    fn test_encrypt_decrypt_and_policy() {
516        let authority = AbeAuthority::new();
517
518        let policy = AccessPolicy::and(vec![
519            PolicyNode::Attribute("premium".to_string()),
520            PolicyNode::Attribute("us-region".to_string()),
521        ]);
522
523        let user_key = authority
524            .generate_user_key(&["premium".to_string(), "us-region".to_string()])
525            .unwrap();
526
527        let plaintext = b"Premium US content";
528        let ciphertext = authority.encrypt(&policy, plaintext).unwrap();
529        let decrypted = authority.decrypt(&user_key, &ciphertext).unwrap();
530
531        assert_eq!(decrypted, plaintext);
532    }
533
534    #[test]
535    fn test_decrypt_fails_without_attributes() {
536        let authority = AbeAuthority::new();
537
538        let policy = AccessPolicy::new(PolicyNode::Attribute("premium".to_string()));
539        let user_key = authority.generate_user_key(&["basic".to_string()]).unwrap();
540
541        let plaintext = b"Secret premium content";
542        let ciphertext = authority.encrypt(&policy, plaintext).unwrap();
543
544        assert!(authority.decrypt(&user_key, &ciphertext).is_err());
545    }
546
547    #[test]
548    fn test_decrypt_fails_partial_and() {
549        let authority = AbeAuthority::new();
550
551        let policy = AccessPolicy::and(vec![
552            PolicyNode::Attribute("premium".to_string()),
553            PolicyNode::Attribute("us-region".to_string()),
554        ]);
555
556        // User has only one of the required attributes
557        let user_key = authority
558            .generate_user_key(&["premium".to_string()])
559            .unwrap();
560
561        let plaintext = b"Premium US content";
562        let ciphertext = authority.encrypt(&policy, plaintext).unwrap();
563
564        assert!(authority.decrypt(&user_key, &ciphertext).is_err());
565    }
566
567    #[test]
568    fn test_or_policy_decryption() {
569        let authority = AbeAuthority::new();
570
571        let policy = AccessPolicy::or(vec![
572            PolicyNode::Attribute("admin".to_string()),
573            PolicyNode::Attribute("premium".to_string()),
574        ]);
575
576        // User with admin attribute
577        let user_key1 = authority.generate_user_key(&["admin".to_string()]).unwrap();
578
579        // User with premium attribute
580        let user_key2 = authority
581            .generate_user_key(&["premium".to_string()])
582            .unwrap();
583
584        let plaintext = b"Admin or Premium content";
585        let ciphertext = authority.encrypt(&policy, plaintext).unwrap();
586
587        // Both should be able to decrypt
588        let decrypted1 = authority.decrypt(&user_key1, &ciphertext).unwrap();
589        assert_eq!(decrypted1, plaintext);
590
591        let decrypted2 = authority.decrypt(&user_key2, &ciphertext).unwrap();
592        assert_eq!(decrypted2, plaintext);
593    }
594
595    #[test]
596    fn test_threshold_policy() {
597        let authority = AbeAuthority::new();
598
599        let policy = AccessPolicy::threshold(
600            2,
601            vec![
602                PolicyNode::Attribute("attr1".to_string()),
603                PolicyNode::Attribute("attr2".to_string()),
604                PolicyNode::Attribute("attr3".to_string()),
605            ],
606        );
607
608        // User with 2 of 3 attributes
609        let user_key = authority
610            .generate_user_key(&["attr1".to_string(), "attr2".to_string()])
611            .unwrap();
612
613        let plaintext = b"Threshold content";
614        let ciphertext = authority.encrypt(&policy, plaintext).unwrap();
615        let decrypted = authority.decrypt(&user_key, &ciphertext).unwrap();
616
617        assert_eq!(decrypted, plaintext);
618    }
619
620    #[test]
621    fn test_complex_nested_policy() {
622        let authority = AbeAuthority::new();
623
624        // (admin OR moderator) AND premium
625        let policy = AccessPolicy::and(vec![
626            PolicyNode::Or(vec![
627                PolicyNode::Attribute("admin".to_string()),
628                PolicyNode::Attribute("moderator".to_string()),
629            ]),
630            PolicyNode::Attribute("premium".to_string()),
631        ]);
632
633        let user_key = authority
634            .generate_user_key(&["moderator".to_string(), "premium".to_string()])
635            .unwrap();
636
637        let plaintext = b"Complex policy content";
638        let ciphertext = authority.encrypt(&policy, plaintext).unwrap();
639        let decrypted = authority.decrypt(&user_key, &ciphertext).unwrap();
640
641        assert_eq!(decrypted, plaintext);
642    }
643
644    #[test]
645    fn test_ciphertext_serialization() {
646        let authority = AbeAuthority::new();
647
648        let policy = AccessPolicy::new(PolicyNode::Attribute("test".to_string()));
649        let plaintext = b"Serialization test";
650        let ciphertext = authority.encrypt(&policy, plaintext).unwrap();
651
652        let bytes = ciphertext.to_bytes().unwrap();
653        let restored = AbeCiphertext::from_bytes(&bytes).unwrap();
654
655        let user_key = authority.generate_user_key(&["test".to_string()]).unwrap();
656        let decrypted = authority.decrypt(&user_key, &restored).unwrap();
657
658        assert_eq!(decrypted, plaintext);
659    }
660
661    #[test]
662    fn test_empty_attributes_fails() {
663        let authority = AbeAuthority::new();
664        let result = authority.generate_user_key(&[]);
665        assert!(result.is_err());
666    }
667
668    #[test]
669    fn test_master_key_export_import() {
670        let authority1 = AbeAuthority::new();
671        let seed = authority1.export_master_key();
672
673        let authority2 = AbeAuthority::from_master_key(seed);
674
675        // Keys generated by both authorities should be compatible
676        let user_key = authority1.generate_user_key(&["test".to_string()]).unwrap();
677
678        let policy = AccessPolicy::new(PolicyNode::Attribute("test".to_string()));
679        let plaintext = b"Cross-authority test";
680        let ciphertext = authority2.encrypt(&policy, plaintext).unwrap();
681
682        let decrypted = authority1.decrypt(&user_key, &ciphertext).unwrap();
683        assert_eq!(decrypted, plaintext);
684    }
685
686    #[test]
687    fn test_multiple_plaintexts_same_policy() {
688        let authority = AbeAuthority::new();
689        let policy = AccessPolicy::new(PolicyNode::Attribute("premium".to_string()));
690        let user_key = authority
691            .generate_user_key(&["premium".to_string()])
692            .unwrap();
693
694        let plaintext1 = b"First message";
695        let plaintext2 = b"Second message";
696
697        let ciphertext1 = authority.encrypt(&policy, plaintext1).unwrap();
698        let ciphertext2 = authority.encrypt(&policy, plaintext2).unwrap();
699
700        let decrypted1 = authority.decrypt(&user_key, &ciphertext1).unwrap();
701        let decrypted2 = authority.decrypt(&user_key, &ciphertext2).unwrap();
702
703        assert_eq!(decrypted1, plaintext1);
704        assert_eq!(decrypted2, plaintext2);
705    }
706}