Skip to main content

object_rainbow_encrypted/
lib.rs

1//! See [`Encrypted`], [`encrypt`] and [`encrypt_point`].
2//!
3//! Political/historical note regarding this whole object encryption thing: originally
4//! [`object_rainbow`] (or, rather, its predecessor) was meant for fully open plaintext, but at some
5//! point encryption was added in as a proof-of-concept mechanism. The goal since the beginning was
6//! to make encryption an "outside" capability: have core tools powerful enough to allow for such.
7//! In process of making the original Python implementation, I effectively had to invent quite a lot
8//! of things including custom dynamic tracing, since the trickiness of the whole resolution
9//! choreography was quite excessive to track. One of the first things we got to facilitate
10//! encryption was fairly implicit in Python: downcasting [`object_rainbow::Fetch`]es (`Origin`s),
11//! which is now the same thing that powers object stores. Then we had to introduce [`Address`] to
12//! have resolution translation be less messy (before that, it used to be just [`Hash`]). In this
13//! actual project, main changes were in ways to forward keys. The now-removed first solution was
14//! with dynamically typed extensions, which got replaced with so called "`Extra`", the system now
15//! responsible for a lot of advanced functionality we have. Probably the only encryption-specific
16//! concession which we just had to make (I did try doing it differently, didn't work) was mangle
17//! hash. It is a bit of a tax on the project as a whole, so we are looking for some potentially
18//! more local alternatives.
19use std::{
20    ops::{Deref, DerefMut},
21    sync::Arc,
22};
23
24use futures_concurrency::future::TryJoin;
25use object_rainbow::{
26    Address, ByteNode, Error, ExtraFor, FailFuture, Fetch, FetchBytes, Hash, ListHashes, Parse,
27    ParseInline, ParseSliceExtra, PointInput, PointVisitor, Resolve, Singular, SingularFetch,
28    Tagged, TagsHash, ToOutput, TopoVec, Topological, Traversible,
29    addressed::ExtractResolve,
30    derive_for_wrapped,
31    fn_fetch::{FnFetch, closure_fetch},
32    length_prefixed::LpVec,
33    map_extra::MappedExtra,
34    tuple_extra::Extra0,
35};
36use object_rainbow_point::{Extras, Point};
37
38pub mod tuple_key;
39
40#[derive_for_wrapped]
41pub trait Key: 'static + Sized + Send + Sync + Clone + PartialEq + Eq {
42    type Error: 'static + Send + Sync + std::error::Error;
43    fn encrypt(&self, data: &[u8]) -> Vec<u8>;
44    fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>, Self::Error>;
45    fn mangle_prefix(&self) -> Vec<u8> {
46        self.encrypt(b"this encrypted constant is followed by an unencrypted inner hash")
47    }
48    fn encrypt_output(&self, object: impl ToOutput) -> Vec<u8> {
49        self.encrypt(&object.vec())
50    }
51}
52
53#[derive(ToOutput, Parse, ParseInline, Clone)]
54struct RawResolve<K> {
55    key: Extras<K>,
56    resolve: Arc<dyn Resolve>,
57    addresses: Arc<LpVec<Address>>,
58}
59
60impl<K> RawResolve<K> {
61    fn translate(&self, address: Address) -> object_rainbow::Result<Address> {
62        self.addresses
63            .get(address.index)
64            .copied()
65            .ok_or(Error::AddressOutOfBounds)
66    }
67}
68
69fn side_parse<K: Key>(
70    key: &K,
71    data: &[u8],
72    resolve: &Arc<dyn Resolve>,
73) -> object_rainbow::Result<(InnerHeader<K>, Vec<u8>)> {
74    let data = key
75        .decrypt(data)
76        .map_err(object_rainbow::Error::consistency)?;
77    <(InnerHeader<K>, Vec<u8>) as ParseSliceExtra<K>>::parse_slice_extra(&data, resolve, key)
78}
79
80impl<K: Key> Resolve for RawResolve<K> {
81    fn resolve<'a>(
82        &'a self,
83        address: Address,
84        _: &'a Arc<dyn Resolve>,
85    ) -> FailFuture<'a, ByteNode> {
86        Box::pin(async move {
87            let address = self.translate(address)?;
88            let (data, resolve) = self.resolve.resolve(address, &self.resolve).await?;
89            let (InnerHeader { resolve, .. }, data) = side_parse(&self.key.0, &data, &resolve)?;
90            let resolve = Arc::new(resolve) as _;
91            Ok((data, resolve))
92        })
93    }
94
95    fn resolve_data(&'_ self, address: Address) -> FailFuture<'_, Vec<u8>> {
96        Box::pin(async move {
97            let address = self.translate(address)?;
98            let (data, resolve) = self.resolve.resolve(address, &self.resolve).await?;
99            let (_, data) = side_parse(&self.key.0, &data, &resolve)?;
100            Ok(data)
101        })
102    }
103
104    fn try_resolve_local(
105        &self,
106        address: Address,
107        _: &Arc<dyn Resolve>,
108    ) -> object_rainbow::Result<Option<ByteNode>> {
109        let address = self.translate(address)?;
110        let Some((data, resolve)) = self.resolve.try_resolve_local(address, &self.resolve)? else {
111            return Ok(None);
112        };
113        let (InnerHeader { resolve, .. }, data) = side_parse(&self.key.0, &data, &resolve)?;
114        let resolve = Arc::new(resolve) as _;
115        Ok(Some((data, resolve)))
116    }
117}
118
119#[derive(Parse, ParseInline)]
120struct InnerHeader<K> {
121    tags: Hash,
122    resolve: RawResolve<K>,
123}
124
125impl<K: Key> InnerHeader<K> {
126    fn with<T: Topological + Tagged>(self, decrypted: T) -> object_rainbow::Result<Inner<K, T>> {
127        if self.tags != decrypted.tags_hash() {
128            return Err(object_rainbow::error_consistency!("tags mismatch"));
129        }
130        let mut topology = TopoVec::new();
131        let mut v = RawVisit {
132            at: 0,
133            resolve: &self.resolve,
134            visitor: &mut topology,
135        };
136        decrypted.traverse(&mut v);
137        v.done()?;
138        let topology = Arc::new(LpVec(topology));
139        let decrypted = Arc::new(decrypted);
140        Ok(Inner {
141            tags: self.tags,
142            key: self.resolve.key,
143            topology,
144            decrypted,
145        })
146    }
147}
148
149#[derive(ToOutput)]
150struct Inner<K, T> {
151    tags: Hash,
152    key: Extras<K>,
153    topology: Arc<LpVec<Arc<dyn Singular>>>,
154    decrypted: Arc<T>,
155}
156
157struct RawVisit<'a, K, V> {
158    at: usize,
159    resolve: &'a RawResolve<K>,
160    visitor: &'a mut V,
161}
162
163impl<'a, K, V> RawVisit<'a, K, V> {
164    fn done(self) -> object_rainbow::Result<()> {
165        if self.at != self.resolve.addresses.len() {
166            Err(Error::AddressOutOfBounds)
167        } else {
168            Ok(())
169        }
170    }
171}
172
173#[derive(Clone)]
174struct RawFetch<K, D> {
175    key: K,
176    resolve: Arc<dyn Resolve>,
177    address: Address,
178    decrypted: D,
179}
180
181impl<K, D> FetchBytes for RawFetch<K, D> {
182    fn fetch_bytes(&'_ self) -> FailFuture<'_, ByteNode> {
183        self.resolve.resolve(self.address, &self.resolve)
184    }
185
186    fn fetch_data(&'_ self) -> FailFuture<'_, Vec<u8>> {
187        self.resolve.resolve_data(self.address)
188    }
189
190    fn fetch_bytes_local(&self) -> object_rainbow::Result<Option<ByteNode>> {
191        self.resolve.try_resolve_local(self.address, &self.resolve)
192    }
193}
194
195impl<K: Key, D: Fetch<T: Topological + Tagged>> Fetch for RawFetch<K, D> {
196    type T = Encrypted<K, D::T>;
197
198    fn fetch(&'_ self) -> FailFuture<'_, Self::T> {
199        Box::pin(async move {
200            let (encrypted, resolve) = self.resolve.resolve(self.address, &self.resolve).await?;
201            let (header, _) = side_parse(&self.key, &encrypted, &resolve)?;
202            let decrypted = self.decrypted.fetch().await?;
203            let inner = header.with(decrypted)?;
204            Ok(Encrypted { inner })
205        })
206    }
207
208    fn try_fetch_local(&self) -> object_rainbow::Result<Option<Self::T>> {
209        let Some((encrypted, resolve)) = self
210            .resolve
211            .try_resolve_local(self.address, &self.resolve)?
212        else {
213            return Ok(None);
214        };
215        let (header, _) = side_parse(&self.key, &encrypted, &resolve)?;
216        let Some(decrypted) = self.decrypted.try_fetch_local()? else {
217            return Ok(None);
218        };
219        let inner = header.with(decrypted)?;
220        Ok(Some(Encrypted { inner }))
221    }
222}
223
224impl<K: Send + Sync, D: Send + Sync> Singular for RawFetch<K, D> {
225    fn hash(&self) -> Hash {
226        self.address.hash
227    }
228}
229
230impl<'a, K: Key, V: PointVisitor> PointVisitor for RawVisit<'a, K, V> {
231    fn visit(&mut self, point: &(impl 'static + SingularFetch<T: Traversible> + Clone)) {
232        let at = self.at;
233        self.at += 1;
234        if let Some(address) = self.resolve.addresses.get(at).copied() {
235            let key = self.resolve.key.0.clone();
236            let resolve = self.resolve.resolve.clone();
237            let decrypted = point.clone();
238            self.visitor.visit(&RawFetch {
239                key,
240                resolve,
241                address,
242                decrypted,
243            });
244        }
245    }
246}
247
248impl<
249    K: Key,
250    T: Topological + Tagged,
251    Extra: 'static + Send + Sync + Clone + ExtraFor<T>,
252    I: PointInput<Extra = (K, Extra)>,
253> Parse<I> for Inner<K, T>
254{
255    fn parse(mut input: I) -> object_rainbow::Result<Self> {
256        let header = input
257            .parse_inline::<MappedExtra<InnerHeader<K>, Extra0>>()?
258            .1;
259        let extra = input.extra().1.clone();
260        let decrypted = extra.parse(
261            &input.parse_all()?,
262            &(Arc::new(header.resolve.clone()) as _),
263        )?;
264        if decrypted.point_count() != header.resolve.addresses.len() {
265            return Err(object_rainbow::error_consistency!(
266                "too many addresses in the header",
267            ));
268        }
269        header.with(decrypted)
270    }
271}
272
273impl<K: Clone, T> Clone for Inner<K, T> {
274    fn clone(&self) -> Self {
275        Self {
276            tags: self.tags,
277            key: self.key.clone(),
278            topology: self.topology.clone(),
279            decrypted: self.decrypted.clone(),
280        }
281    }
282}
283
284#[derive(Clone)]
285struct InnerFetch<K, D> {
286    key: K,
287    encrypted: Arc<dyn Singular>,
288    decrypted: D,
289}
290
291impl<K, D> FetchBytes for InnerFetch<K, D> {
292    fn fetch_bytes(&'_ self) -> FailFuture<'_, ByteNode> {
293        self.encrypted.fetch_bytes()
294    }
295
296    fn fetch_data(&'_ self) -> FailFuture<'_, Vec<u8>> {
297        self.encrypted.fetch_data()
298    }
299
300    fn fetch_bytes_local(&self) -> object_rainbow::Result<Option<ByteNode>> {
301        self.encrypted.fetch_bytes_local()
302    }
303
304    fn fetch_data_local(&self) -> Option<Vec<u8>> {
305        self.encrypted.fetch_data_local()
306    }
307}
308
309impl<K: Key, D: Fetch<T: Topological + Tagged>> Fetch for InnerFetch<K, D> {
310    type T = Encrypted<K, D::T>;
311
312    fn fetch(&'_ self) -> FailFuture<'_, Self::T> {
313        Box::pin(async move {
314            let (encrypted, resolve) = self.encrypted.fetch_bytes().await?;
315            let (header, _) = side_parse(&self.key, &encrypted, &resolve)?;
316            let decrypted = self.decrypted.fetch().await?;
317            let inner = header.with(decrypted)?;
318            Ok(Encrypted { inner })
319        })
320    }
321
322    fn try_fetch_local(&self) -> object_rainbow::Result<Option<Self::T>> {
323        let Some((encrypted, resolve)) = self.encrypted.fetch_bytes_local()? else {
324            return Ok(None);
325        };
326        let (header, _) = side_parse(&self.key, &encrypted, &resolve)?;
327        let Some(decrypted) = self.decrypted.try_fetch_local()? else {
328            return Ok(None);
329        };
330        let inner = header.with(decrypted)?;
331        Ok(Some(Encrypted { inner }))
332    }
333}
334
335impl<K: Send + Sync, D: Send + Sync> Singular for InnerFetch<K, D> {
336    fn hash(&self) -> Hash {
337        self.encrypted.hash()
338    }
339}
340
341struct IterateResolution<'a, 'r, K, V: ?Sized> {
342    key: &'a K,
343    topology: &'r mut std::slice::Iter<'a, Arc<dyn Singular>>,
344    visitor: &'a mut V,
345}
346
347impl<'a, K: Key, V: ?Sized + PointVisitor> PointVisitor for IterateResolution<'a, '_, K, V> {
348    fn visit(&mut self, decrypted: &(impl 'static + SingularFetch<T: Traversible> + Clone)) {
349        let decrypted = decrypted.clone();
350        let encrypted = self.topology.next().expect("length mismatch").clone();
351        let point = Point::from_singular_fetch(InnerFetch {
352            key: self.key.clone(),
353            decrypted,
354            encrypted,
355        });
356        self.visitor.visit(&point);
357    }
358}
359
360impl<K, T> ListHashes for Inner<K, T> {
361    fn list_hashes(&self, f: &mut (impl ?Sized + FnMut(Hash))) {
362        self.topology.list_hashes(f);
363    }
364
365    fn topology_hash(&self) -> Hash {
366        self.topology.0.data_hash()
367    }
368
369    fn point_count(&self) -> usize {
370        self.topology.len()
371    }
372}
373
374impl<K: Key, T: Topological> Topological for Inner<K, T> {
375    fn traverse(&self, visitor: &mut (impl ?Sized + PointVisitor)) {
376        let topology = &mut self.topology.iter();
377        self.decrypted.traverse(&mut IterateResolution {
378            key: &self.key.0,
379            topology,
380            visitor,
381        });
382        assert!(topology.next().is_none());
383    }
384
385    fn topology(&self) -> TopoVec {
386        self.topology.0.clone()
387    }
388}
389
390pub struct Encrypted<K, T> {
391    inner: Inner<K, T>,
392}
393
394impl<K, T: Clone> Encrypted<K, T> {
395    pub fn into_inner(self) -> T {
396        Arc::unwrap_or_clone(self.inner.decrypted)
397    }
398}
399
400impl<K, T> Deref for Encrypted<K, T> {
401    type Target = T;
402
403    fn deref(&self) -> &Self::Target {
404        self.inner.decrypted.as_ref()
405    }
406}
407
408impl<K: Clone, T> Clone for Encrypted<K, T> {
409    fn clone(&self) -> Self {
410        Self {
411            inner: self.inner.clone(),
412        }
413    }
414}
415
416impl<K, T> ListHashes for Encrypted<K, T> {
417    fn list_hashes(&self, f: &mut (impl ?Sized + FnMut(Hash))) {
418        self.inner.list_hashes(f);
419    }
420
421    fn topology_hash(&self) -> Hash {
422        self.inner.topology_hash()
423    }
424
425    fn point_count(&self) -> usize {
426        self.inner.point_count()
427    }
428}
429
430impl<K: Key, T: Topological> Topological for Encrypted<K, T> {
431    fn traverse(&self, visitor: &mut (impl ?Sized + PointVisitor)) {
432        self.inner.traverse(visitor);
433    }
434}
435
436impl<K: Key, T: ToOutput> ToOutput for Encrypted<K, T> {
437    fn to_output(&self, output: &mut (impl ?Sized + object_rainbow::Output)) {
438        if output.is_mangling() {
439            output.write(&*self.inner.key.mangle_prefix().data_hash());
440            output.write(&*self.inner.decrypted.data_hash());
441        }
442        if output.is_real() {
443            output.write(&self.inner.key.encrypt_output(&self.inner));
444        }
445    }
446}
447
448trait EncryptedExtra<K>: 'static + Send + Sync + Clone {
449    type Extra: 'static + Send + Sync + Clone;
450    fn parts(&self) -> (K, Self::Extra);
451}
452
453impl<K: 'static + Send + Sync + Clone, Extra: 'static + Send + Sync + Clone> EncryptedExtra<K>
454    for (K, Extra)
455{
456    type Extra = Extra;
457
458    fn parts(&self) -> (K, Self::Extra) {
459        self.clone()
460    }
461}
462
463impl<K: 'static + Send + Sync + Clone> EncryptedExtra<K> for K {
464    type Extra = ();
465
466    fn parts(&self) -> (K, Self::Extra) {
467        (self.clone(), ())
468    }
469}
470
471impl<
472    K: Key,
473    T: Topological + Tagged,
474    Extra: 'static + Send + Sync + Clone + ExtraFor<T>,
475    I: PointInput<Extra: EncryptedExtra<K, Extra = Extra>>,
476> Parse<I> for Encrypted<K, T>
477{
478    fn parse(input: I) -> object_rainbow::Result<Self> {
479        let with_key = input.extra().parts();
480        let resolve = input.resolve().clone();
481        let source = with_key
482            .0
483            .decrypt(&input.parse_all()?)
484            .map_err(object_rainbow::Error::consistency)?;
485        let inner = Inner::<K, T>::parse_slice_extra(&source, &resolve, &with_key)?;
486        Ok(Self { inner })
487    }
488}
489
490impl<K, T> Tagged for Encrypted<K, T> {}
491
492type Extracted =
493    Vec<std::pin::Pin<Box<dyn Future<Output = Result<Arc<dyn Singular>, Error>> + Send + 'static>>>;
494
495struct ExtractResolution<'a, K> {
496    extracted: &'a mut Extracted,
497    key: &'a K,
498}
499
500impl<K: Key> PointVisitor for ExtractResolution<'_, K> {
501    fn visit(&mut self, decrypted: &(impl 'static + SingularFetch<T: Traversible> + Clone)) {
502        let decrypted = decrypted.clone();
503        let key = self.key.clone();
504        self.extracted.push(Box::pin(async move {
505            Ok(Arc::new(encrypt_point(key, decrypted).await?) as _)
506        }));
507    }
508}
509
510pub async fn encrypt_point<K: Key, T: Traversible>(
511    key: K,
512    decrypted: impl 'static + SingularFetch<T = T>,
513) -> object_rainbow::Result<Point<Encrypted<K, T>>> {
514    if let Some((address, resolve)) = decrypted.extract_resolve::<RawResolve<K>>()
515        && resolve.key.0 == key
516    {
517        let address = resolve.translate(*address)?;
518        let point = Point::from_singular_fetch(RawFetch {
519            key,
520            resolve: resolve.resolve.clone(),
521            address,
522            decrypted,
523        });
524        return Ok(point);
525    };
526    let encrypted = encrypt(key.clone(), decrypted.fetch().await?).await?;
527    let topology = encrypted.inner.topology.clone();
528    let point = Point::from_alternate_source(
529        &encrypted,
530        FnFetch::new(closure_fetch(
531            (key, decrypted, topology),
532            async |(key, decrypted, topology)| {
533                let decrypted = decrypted.fetch().await?;
534                let topology = topology.clone();
535                let key = key.clone();
536                Ok(Encrypted::from_topology(key, topology, decrypted))
537            },
538        )),
539    );
540    Ok(point)
541}
542
543pub async fn encrypt<K: Key, T: Traversible>(
544    key: K,
545    decrypted: T,
546) -> object_rainbow::Result<Encrypted<K, T>> {
547    let mut futures = Vec::with_capacity(decrypted.point_count());
548    decrypted.traverse(&mut ExtractResolution {
549        extracted: &mut futures,
550        key: &key,
551    });
552    let topology = futures.try_join().await?;
553    let topology = Arc::new(LpVec(topology));
554    Ok(Encrypted::from_topology(key, topology, decrypted))
555}
556
557impl<K: Key, T: Traversible> Encrypted<K, T> {
558    fn from_topology(key: K, topology: Arc<LpVec<Arc<dyn Singular>>>, decrypted: T) -> Self {
559        let decrypted = Arc::new(decrypted);
560        let inner = Inner {
561            tags: decrypted.tags_hash(),
562            key: Extras(key),
563            topology,
564            decrypted,
565        };
566        Self { inner }
567    }
568}
569
570impl<K: Key, T: Traversible + Clone> Encrypted<K, T> {
571    pub fn as_mut(&mut self) -> EncryptedMut<'_, K, T> {
572        let object = self.inner.decrypted.as_ref().clone();
573        EncryptedMut {
574            encrypted: self,
575            object,
576        }
577    }
578}
579
580pub struct EncryptedMut<'a, K, T> {
581    encrypted: &'a mut Encrypted<K, T>,
582    object: T,
583}
584
585impl<K, T> Deref for EncryptedMut<'_, K, T> {
586    type Target = T;
587
588    fn deref(&self) -> &Self::Target {
589        &self.object
590    }
591}
592
593impl<K, T> DerefMut for EncryptedMut<'_, K, T> {
594    fn deref_mut(&mut self) -> &mut Self::Target {
595        &mut self.object
596    }
597}
598
599impl<'a, K: Key, T: Traversible> EncryptedMut<'a, K, T> {
600    pub async fn save(self) -> object_rainbow::Result<()> {
601        *self.encrypted = encrypt(self.encrypted.inner.key.0.clone(), self.object).await?;
602        Ok(())
603    }
604}