nucypher_core/
access_control.rs1use alloc::boxed::Box;
2use alloc::string::String;
3
4use ferveo::api::{encrypt, Ciphertext, DkgPublicKey, SecretBox};
5use ferveo::Error;
6use serde::{Deserialize, Serialize};
7use umbral_pre::serde_bytes;
8
9use crate::conditions::Conditions;
10use crate::versioning::{
11 messagepack_deserialize, messagepack_serialize, ProtocolObject, ProtocolObjectInner,
12};
13
14#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
16pub struct AuthenticatedData {
17 pub public_key: DkgPublicKey,
19
20 pub conditions: Conditions,
22}
23
24impl Eq for AuthenticatedData {}
25
26impl AuthenticatedData {
27 pub fn new(public_key: &DkgPublicKey, conditions: &Conditions) -> Self {
29 AuthenticatedData {
30 public_key: *public_key,
31 conditions: conditions.clone(),
32 }
33 }
34
35 pub fn aad(&self) -> Result<Box<[u8]>, Error> {
37 Ok([
38 self.public_key.to_bytes()?.to_vec(),
39 self.conditions.as_ref().as_bytes().to_vec(),
40 ]
41 .concat()
42 .into_boxed_slice())
43 }
44}
45
46impl<'a> ProtocolObjectInner<'a> for AuthenticatedData {
47 fn version() -> (u16, u16) {
48 (1, 0)
49 }
50
51 fn brand() -> [u8; 4] {
52 *b"AuDa"
53 }
54
55 fn unversioned_to_bytes(&self) -> Box<[u8]> {
56 messagepack_serialize(&self)
57 }
58
59 fn unversioned_from_bytes(minor_version: u16, bytes: &[u8]) -> Option<Result<Self, String>> {
60 if minor_version == 0 {
61 Some(messagepack_deserialize(bytes))
62 } else {
63 None
64 }
65 }
66}
67
68impl<'a> ProtocolObject<'a> for AuthenticatedData {}
69
70pub fn encrypt_for_dkg(
72 data: &[u8],
73 public_key: &DkgPublicKey,
74 conditions: &Conditions,
75) -> Result<(Ciphertext, AuthenticatedData), Error> {
76 let auth_data = AuthenticatedData::new(public_key, conditions);
77 let ciphertext = encrypt(
78 SecretBox::new(data.to_vec()),
79 auth_data.aad()?.as_ref(),
80 public_key,
81 )?;
82 Ok((ciphertext, auth_data))
83}
84
85#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)]
87pub struct AccessControlPolicy {
88 pub auth_data: AuthenticatedData,
90
91 #[serde(with = "serde_bytes::as_base64")]
93 pub authorization: Box<[u8]>,
94}
95
96impl AccessControlPolicy {
97 pub fn new(auth_data: &AuthenticatedData, authorization: &[u8]) -> Self {
99 AccessControlPolicy {
100 auth_data: auth_data.clone(),
101 authorization: authorization.to_vec().into(),
102 }
103 }
104
105 pub fn aad(&self) -> Result<Box<[u8]>, Error> {
107 self.auth_data.aad()
108 }
109
110 pub fn public_key(&self) -> DkgPublicKey {
112 self.auth_data.public_key
113 }
114
115 pub fn conditions(&self) -> Conditions {
117 self.auth_data.conditions.clone()
118 }
119}
120
121impl<'a> ProtocolObjectInner<'a> for AccessControlPolicy {
122 fn version() -> (u16, u16) {
123 (1, 0)
124 }
125
126 fn brand() -> [u8; 4] {
127 *b"ACPo"
128 }
129
130 fn unversioned_to_bytes(&self) -> Box<[u8]> {
131 messagepack_serialize(&self)
132 }
133
134 fn unversioned_from_bytes(minor_version: u16, bytes: &[u8]) -> Option<Result<Self, String>> {
135 if minor_version == 0 {
136 Some(messagepack_deserialize(bytes))
137 } else {
138 None
139 }
140 }
141}
142
143impl<'a> ProtocolObject<'a> for AccessControlPolicy {}
144
145#[cfg(test)]
146mod tests {
147 use crate::access_control::{AccessControlPolicy, AuthenticatedData};
148 use crate::conditions::Conditions;
149 use crate::test_utils::util::random_dkg_pubkey;
150 use crate::versioning::ProtocolObject;
151
152 #[test]
153 fn authenticated_data() {
154 let dkg_pk = random_dkg_pubkey();
155 let conditions = Conditions::new("abcd");
156
157 let auth_data = AuthenticatedData::new(&dkg_pk, &conditions);
158
159 let mut expected_aad = dkg_pk.to_bytes().unwrap().to_vec();
161 expected_aad.extend(conditions.as_ref().as_bytes());
162 let auth_data_aad = auth_data.aad().unwrap();
163 assert_eq!(expected_aad.into_boxed_slice(), auth_data_aad);
164
165 assert_eq!(auth_data.public_key, dkg_pk);
166 assert_eq!(auth_data.conditions, conditions);
167
168 let auth_data_2 = AuthenticatedData::new(&dkg_pk, &conditions);
169 assert_eq!(auth_data, auth_data_2);
170
171 let serialized_auth_data = auth_data.to_bytes();
173 let deserialized_auth_data = AuthenticatedData::from_bytes(&serialized_auth_data).unwrap();
174 assert_eq!(auth_data.public_key, deserialized_auth_data.public_key);
175 assert_eq!(auth_data.conditions, deserialized_auth_data.conditions);
176 }
177
178 #[test]
179 fn access_control_policy() {
180 let dkg_pk = random_dkg_pubkey();
181 let conditions = Conditions::new("abcd");
182
183 let auth_data = AuthenticatedData::new(&dkg_pk, &conditions);
184 let authorization = b"we_dont_need_no_stinking_badges";
185 let acp = AccessControlPolicy::new(&auth_data, authorization);
186
187 assert_eq!(auth_data.aad().unwrap(), acp.aad().unwrap());
189
190 let serialized_acp = acp.to_bytes();
192 let deserialized_acp = AccessControlPolicy::from_bytes(&serialized_acp).unwrap();
193 assert_eq!(auth_data.public_key, deserialized_acp.public_key());
194 assert_eq!(auth_data.conditions, deserialized_acp.conditions());
195 assert_eq!(
196 authorization.to_vec().into_boxed_slice(),
197 deserialized_acp.authorization
198 );
199 }
200}