Skip to content

Commit d0db44e

Browse files
committed
Updated methods on encrypted table for dataset awareness
1 parent e45e10b commit d0db44e

File tree

9 files changed

+89
-67
lines changed

9 files changed

+89
-67
lines changed

docker-compose.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
version: '3'
2-
31
services:
42
dynamodb:
53
build: ./local-dynamodb

src/crypto/attrs/flattened_encrypted_attributes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
crypto::{attrs::flattened_protected_attributes::FlattenedAttrName, SealError},
3-
encrypted_table::{ScopedCipherWithCreds, TableAttributes},
3+
encrypted_table::{TableAttributes, ZeroKmsCipher},
44
traits::TableAttribute,
55
};
66
use cipherstash_client::{
@@ -34,7 +34,7 @@ impl FlattenedEncryptedAttributes {
3434
/// Decrypt self, returning a [FlattenedProtectedAttributes].
3535
pub(crate) async fn decrypt_all(
3636
self,
37-
cipher: &ScopedCipherWithCreds,
37+
cipher: &ZeroKmsCipher,
3838
) -> Result<FlattenedProtectedAttributes, SealError> {
3939
let descriptors = self
4040
.attrs

src/crypto/attrs/flattened_protected_attributes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::{
22
flattened_encrypted_attributes::FlattenedEncryptedAttributes,
33
normalized_protected_attributes::NormalizedKey,
44
};
5-
use crate::{crypto::SealError, encrypted_table::{AttributeName, ScopedCipherWithCreds}};
5+
use crate::{crypto::SealError, encrypted_table::{AttributeName, ScopedZeroKmsCipher}};
66
use cipherstash_client::{
77
encryption::{BytesWithDescriptor, Plaintext}, zerokms::EncryptPayload,
88
};
@@ -31,7 +31,7 @@ impl FlattenedProtectedAttributes {
3131
/// The output is a vec of `chunk_into` [FlattenedEncryptedAttributes] objects.
3232
pub(crate) async fn encrypt_all(
3333
self,
34-
cipher: &ScopedCipherWithCreds,
34+
cipher: &ScopedZeroKmsCipher,
3535
chunk_into: usize,
3636
) -> Result<Vec<FlattenedEncryptedAttributes>, SealError> {
3737
let chunk_size = self.0.len() / chunk_into;

src/crypto/sealed.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
crypto::attrs::FlattenedEncryptedAttributes,
3-
encrypted_table::{ScopedCipherWithCreds, TableEntry},
3+
encrypted_table::{TableEntry, ZeroKmsCipher},
44
traits::{ReadConversionError, WriteConversionError},
55
Decryptable, Identifiable,
66
};
@@ -68,7 +68,7 @@ impl SealedTableEntry {
6868
pub(crate) async fn unseal_all(
6969
items: Vec<Self>,
7070
spec: UnsealSpec<'_>,
71-
cipher: &ScopedCipherWithCreds,
71+
cipher: &ZeroKmsCipher,
7272
) -> Result<Vec<Unsealed>, SealError> {
7373
let UnsealSpec {
7474
protected_attributes,
@@ -130,7 +130,7 @@ impl SealedTableEntry {
130130
pub(crate) async fn unseal(
131131
self,
132132
spec: UnsealSpec<'_>,
133-
cipher: &ScopedCipherWithCreds,
133+
cipher: &ZeroKmsCipher,
134134
) -> Result<Unsealed, SealError> {
135135
let mut vec = Self::unseal_all(vec![self], spec, cipher).await?;
136136

@@ -203,18 +203,17 @@ impl TryFrom<SealedTableEntry> for HashMap<String, AttributeValue> {
203203

204204
#[cfg(test)]
205205
mod tests {
206-
use crate::encrypted_table::{Cipher, ScopedCipherWithCreds};
206+
use crate::encrypted_table::{ZeroKmsCipher};
207207

208208
use super::SealedTableEntry;
209209
use cipherstash_client::{
210210
credentials::auto_refresh::AutoRefresh, ConsoleConfig, ZeroKMS, ZeroKMSConfig
211211
};
212212
use miette::IntoDiagnostic;
213-
use uuid::Uuid;
214213
use std::{borrow::Cow, sync::Arc};
215214

216215
// FIXME: Use the test cipher from CipherStash Client when that's ready
217-
async fn get_cipher() -> Result<Arc<Cipher>, Box<dyn std::error::Error>> {
216+
async fn get_cipher() -> Result<Arc<ZeroKmsCipher>, Box<dyn std::error::Error>> {
218217
let console_config = ConsoleConfig::builder().with_env().build().into_diagnostic()?;
219218
let zero_kms_config = ZeroKMSConfig::builder()
220219
.decryption_log(true)
@@ -240,11 +239,7 @@ mod tests {
240239
sort_key_prefix: "test".to_string(),
241240
};
242241
let cipher = get_cipher().await?;
243-
// TODO: Temporary obvs
244-
let dataset_id = Uuid::parse_str("93e10481-2692-4d65-a619-37e36a496e64").unwrap();
245-
let scoped_cipher = ScopedCipherWithCreds::init(cipher, dataset_id).await.unwrap();
246-
247-
let results = SealedTableEntry::unseal_all(vec![], spec, &scoped_cipher)
242+
let results = SealedTableEntry::unseal_all(vec![], spec, &cipher)
248243
.await
249244
.into_diagnostic()?;
250245

src/crypto/sealer.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::{
22
attrs::FlattenedProtectedAttributes, b64_encode, format_term_key, SealError, SealedTableEntry, Unsealed, MAX_TERMS_PER_INDEX
33
};
44
use crate::{
5-
encrypted_table::{AttributeName, ScopedCipherWithCreds, TableAttribute, TableAttributes, TableEntry},
5+
encrypted_table::{AttributeName, ScopedZeroKmsCipher, TableAttribute, TableAttributes, TableEntry},
66
traits::PrimaryKeyParts,
77
IndexType,
88
};
@@ -53,7 +53,7 @@ impl RecordsWithTerms {
5353

5454
async fn encrypt(
5555
self,
56-
cipher: &ScopedCipherWithCreds,
56+
cipher: &ScopedZeroKmsCipher,
5757
) -> Result<Vec<Sealed>, SealError> {
5858
let num_records = self.records.len();
5959
let mut pksks = Vec::with_capacity(num_records);
@@ -134,7 +134,7 @@ impl Sealer {
134134
fn index_all_terms<'a>(
135135
records: impl IntoIterator<Item = Sealer>,
136136
protected_attributes: impl AsRef<[Cow<'a, str>]>,
137-
cipher: &ScopedCipherWithCreds,
137+
cipher: &ScopedZeroKmsCipher,
138138
// FIXME: This might need to be a const generic
139139
term_length: usize,
140140
) -> Result<RecordsWithTerms, SealError> {
@@ -210,7 +210,7 @@ impl Sealer {
210210
pub(crate) async fn seal_all<'a>(
211211
records: impl IntoIterator<Item = Sealer>,
212212
protected_attributes: impl AsRef<[Cow<'a, str>]>,
213-
cipher: &ScopedCipherWithCreds,
213+
cipher: &ScopedZeroKmsCipher,
214214
term_length: usize,
215215
) -> Result<Vec<Sealed>, SealError> {
216216
Self::index_all_terms(records, protected_attributes, &cipher, term_length)?
@@ -221,7 +221,7 @@ impl Sealer {
221221
pub(crate) async fn seal<'a>(
222222
self,
223223
protected_attributes: impl AsRef<[Cow<'a, str>]>,
224-
cipher: &ScopedCipherWithCreds,
224+
cipher: &ScopedZeroKmsCipher,
225225
term_length: usize,
226226
) -> Result<Sealed, SealError> {
227227
let mut vec = Self::seal_all([self], protected_attributes, cipher, term_length).await?;

src/encrypted_table/mod.rs

Lines changed: 63 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,16 @@ impl Deref for Dynamo {
4949
}
5050
}
5151

52-
pub type Cipher = ZeroKMSWithClientKey<AutoRefresh<ServiceCredentials>>;
53-
pub type ScopedCipherWithCreds = ScopedCipher<AutoRefresh<ServiceCredentials>>;
52+
pub type ZeroKmsCipher = ZeroKMSWithClientKey<AutoRefresh<ServiceCredentials>>;
53+
pub type ScopedZeroKmsCipher = ScopedCipher<AutoRefresh<ServiceCredentials>>;
5454

5555
pub struct EncryptedTable<D = Dynamo> {
5656
db: D,
57-
cipher: Arc<Cipher>,
57+
cipher: Arc<ZeroKmsCipher>,
5858
}
5959

6060
impl<D> EncryptedTable<D> {
61-
pub fn cipher(&self) -> Arc<Cipher> {
61+
pub fn cipher(&self) -> Arc<ZeroKmsCipher> {
6262
self.cipher.clone()
6363
}
6464
}
@@ -279,20 +279,15 @@ impl<D> EncryptedTable<D> {
279279
) -> Result<Vec<T>, DecryptError>
280280
where T: Decryptable + Identifiable,
281281
{
282-
// TODO: Temporary obvs
283-
let dataset_id = Uuid::parse_str("93e10481-2692-4d65-a619-37e36a496e64").unwrap();
284-
let scoped_cipher = ScopedCipherWithCreds::init(self.cipher.clone(), dataset_id).await.unwrap();
285-
286-
decrypt_all(&scoped_cipher, items).await
282+
decrypt_all(&self.cipher, items).await
287283
}
288284

289285
pub async fn create_delete_patch(
290286
&self,
291287
delete: PreparedDelete,
288+
dataset_id: Option<Uuid>,
292289
) -> Result<DynamoRecordPatch, DeleteError> {
293-
// TODO: Temporary obvs
294-
let dataset_id = Uuid::parse_str("93e10481-2692-4d65-a619-37e36a496e64").unwrap();
295-
let scoped_cipher = ScopedCipherWithCreds::init(self.cipher.clone(), dataset_id).await.unwrap();
290+
let scoped_cipher = ScopedZeroKmsCipher::init(self.cipher.clone(), dataset_id).await.unwrap();
296291

297292
let PrimaryKeyParts { pk, sk } = encrypt_primary_key_parts(&scoped_cipher, delete.primary_key)?;
298293

@@ -323,14 +318,13 @@ impl<D> EncryptedTable<D> {
323318
pub async fn create_put_patch(
324319
&self,
325320
record: PreparedRecord,
321+
dataset_id: Option<Uuid>,
326322
// TODO: Make sure the index_predicate is used correctly
327323
index_predicate: impl FnMut(&AttributeName, &TableAttribute) -> bool,
328324
) -> Result<DynamoRecordPatch, PutError> {
329325
let mut seen_sk = HashSet::new();
330326

331-
// TODO: Temporary obvs
332-
let dataset_id = Uuid::parse_str("93e10481-2692-4d65-a619-37e36a496e64").unwrap();
333-
let indexable_cipher = ScopedCipherWithCreds::init(self.cipher.clone(), dataset_id).await.unwrap();
327+
let indexable_cipher = ScopedZeroKmsCipher::init(self.cipher.clone(), dataset_id).await.unwrap();
334328

335329
let PreparedRecord {
336330
protected_attributes,
@@ -403,13 +397,26 @@ impl EncryptedTable<Dynamo> {
403397
where
404398
T: Decryptable + Identifiable,
405399
{
406-
// TODO: Temporary obvs
407-
let dataset_id = Uuid::parse_str("93e10481-2692-4d65-a619-37e36a496e64").unwrap();
408-
let scoped_cipher = ScopedCipherWithCreds::init(self.cipher.clone(), dataset_id).await.unwrap();
400+
// TODO: Don't unwrap
401+
let scoped_cipher = ScopedZeroKmsCipher::init(self.cipher.clone(), None).await.unwrap();
402+
self.get_inner(k, scoped_cipher).await
403+
}
409404

410-
let PrimaryKeyParts { pk, sk } =
411-
encrypt_primary_key_parts(&scoped_cipher, PreparedPrimaryKey::new::<T>(k))?;
405+
pub async fn get_via<T>(&self, k: impl Into<T::PrimaryKey>, dataset_id: Uuid) -> Result<Option<T>, GetError>
406+
where
407+
T: Decryptable + Identifiable,
408+
{
409+
// TODO: Don't unwrap
410+
let scoped_cipher = ScopedZeroKmsCipher::init(self.cipher.clone(), Some(dataset_id)).await.unwrap();
411+
self.get_inner(k, scoped_cipher).await
412+
}
412413

414+
async fn get_inner<T>(&self, k: impl Into<T::PrimaryKey>, cipher: ScopedZeroKmsCipher) -> Result<Option<T>, GetError>
415+
where
416+
T: Decryptable + Identifiable,
417+
{
418+
let PrimaryKeyParts { pk, sk } =
419+
encrypt_primary_key_parts(&cipher, PreparedPrimaryKey::new::<T>(k))?;
413420

414421
let result = self
415422
.db
@@ -421,10 +428,8 @@ impl EncryptedTable<Dynamo> {
421428
.await
422429
.map_err(|e| GetError::Aws(format!("{e:?}")))?;
423430

424-
println!("RESULT {:?}", result);
425-
426431
if let Some(item) = result.item {
427-
Ok(Some(decrypt(&scoped_cipher, item).await?))
432+
Ok(Some(decrypt(&self.cipher, item).await?))
428433
} else {
429434
Ok(None)
430435
}
@@ -433,9 +438,25 @@ impl EncryptedTable<Dynamo> {
433438
pub async fn delete<E: Searchable + Identifiable>(
434439
&self,
435440
k: impl Into<E::PrimaryKey>,
441+
) -> Result<(), DeleteError> {
442+
self.delete_inner::<E>(k.into(), None).await
443+
}
444+
445+
pub async fn delete_via<E: Searchable + Identifiable>(
446+
&self,
447+
k: impl Into<E::PrimaryKey>,
448+
dataset_id: Uuid,
449+
) -> Result<(), DeleteError> {
450+
self.delete_inner::<E>(k.into(), Some(dataset_id)).await
451+
}
452+
453+
async fn delete_inner<E: Searchable + Identifiable>(
454+
&self,
455+
k: E::PrimaryKey,
456+
dataset_id: Option<Uuid>,
436457
) -> Result<(), DeleteError> {
437458
let transact_items = self
438-
.create_delete_patch(PreparedDelete::new::<E>(k))
459+
.create_delete_patch(PreparedDelete::new::<E>(k), dataset_id)
439460
.await?
440461
.into_transact_write_items(&self.db.table_name)?;
441462

@@ -453,6 +474,20 @@ impl EncryptedTable<Dynamo> {
453474
}
454475

455476
pub async fn put<T>(&self, record: T) -> Result<(), PutError>
477+
where
478+
T: Searchable + Identifiable,
479+
{
480+
self.put_inner(record, None).await
481+
}
482+
483+
pub async fn put_via<T>(&self, record: T, dataset_id: Uuid) -> Result<(), PutError>
484+
where
485+
T: Searchable + Identifiable,
486+
{
487+
self.put_inner(record, Some(dataset_id)).await
488+
}
489+
490+
async fn put_inner<T>(&self, record: T, dataset_id: Option<Uuid>) -> Result<(), PutError>
456491
where
457492
T: Searchable + Identifiable,
458493
{
@@ -461,6 +496,7 @@ impl EncryptedTable<Dynamo> {
461496
let transact_items = self
462497
.create_put_patch(
463498
record,
499+
dataset_id,
464500
// include all records in the indexes
465501
|_, _| true,
466502
)
@@ -484,7 +520,7 @@ impl EncryptedTable<Dynamo> {
484520
/// Take a prepared primary key and encrypt it to get the [`PrimaryKeyParts`] which can be used
485521
/// for retrieval.
486522
fn encrypt_primary_key_parts(
487-
scoped_cipher: &ScopedCipherWithCreds,
523+
scoped_cipher: &ScopedZeroKmsCipher,
488524
prepared_primary_key: PreparedPrimaryKey,
489525
) -> Result<PrimaryKeyParts, PrimaryKeyError> {
490526
let PrimaryKeyParts { mut pk, mut sk } = prepared_primary_key.primary_key_parts;
@@ -500,7 +536,7 @@ fn encrypt_primary_key_parts(
500536
Ok(PrimaryKeyParts { pk, sk })
501537
}
502538

503-
async fn decrypt<T>(scoped_cipher: &ScopedCipherWithCreds, item: HashMap<String, AttributeValue>) -> Result<T, DecryptError>
539+
async fn decrypt<T>(scoped_cipher: &ZeroKmsCipher, item: HashMap<String, AttributeValue>) -> Result<T, DecryptError>
504540
where
505541
T: Decryptable + Identifiable,
506542
{
@@ -512,7 +548,7 @@ where
512548
}
513549

514550
async fn decrypt_all<T>(
515-
scoped_cipher: &ScopedCipherWithCreds,
551+
scoped_cipher: &ZeroKmsCipher,
516552
items: impl IntoIterator<Item = HashMap<String, AttributeValue>>,
517553
) -> Result<Vec<T>, DecryptError>
518554
where

src/encrypted_table/query.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use cipherstash_client::{
66
},
77
};
88
use itertools::Itertools;
9-
use uuid::Uuid;
109
use std::{borrow::Cow, collections::HashMap, marker::PhantomData};
1110

1211
use crate::{
@@ -15,7 +14,7 @@ use crate::{
1514
};
1615
use cipherstash_client::encryption::IndexTerm;
1716

18-
use super::{Dynamo, EncryptedTable, ScopedCipherWithCreds, QueryError, SealError};
17+
use super::{Dynamo, EncryptedTable, ScopedZeroKmsCipher, QueryError, SealError};
1918

2019
/// A builder for a query operation which returns records of type `S`.
2120
/// `B` is the storage backend used to store the data.
@@ -35,7 +34,7 @@ pub struct PreparedQuery {
3534
impl PreparedQuery {
3635
pub async fn encrypt(
3736
self,
38-
scoped_cipher: &ScopedCipherWithCreds,
37+
scoped_cipher: &ScopedZeroKmsCipher,
3938
) -> Result<AttributeValue, QueryError> {
4039
let PreparedQuery {
4140
index_name,
@@ -62,7 +61,7 @@ impl PreparedQuery {
6261
pub async fn send(
6362
self,
6463
table: &EncryptedTable<Dynamo>,
65-
scoped_cipher: &ScopedCipherWithCreds,
64+
scoped_cipher: &ScopedZeroKmsCipher,
6665
) -> Result<Vec<HashMap<String, AttributeValue>>, QueryError> {
6766
let term = self.encrypt(scoped_cipher).await?;
6867

@@ -128,19 +127,18 @@ impl<S> QueryBuilder<S, &EncryptedTable<Dynamo>>
128127
where
129128
S: Searchable + Identifiable,
130129
{
130+
// TODO: Add load_via
131131
pub async fn load<T>(self) -> Result<Vec<T>, QueryError>
132132
where
133133
T: Decryptable + Identifiable,
134134
{
135-
// TODO: Temporary obvs
136-
let dataset_id = Uuid::parse_str("93e10481-2692-4d65-a619-37e36a496e64").unwrap();
137-
let scoped_cipher = ScopedCipherWithCreds::init(self.storage.cipher.clone(), dataset_id).await.unwrap();
135+
let scoped_cipher = ScopedZeroKmsCipher::init(self.storage.cipher.clone(), None).await.unwrap();
138136

139137
let storage = self.storage;
140138
let query = self.build()?;
141139

142140
let items = query.send(storage, &scoped_cipher).await?;
143-
let results = super::decrypt_all(&scoped_cipher, items).await?;
141+
let results = super::decrypt_all(&storage.cipher, items).await?;
144142

145143
Ok(results)
146144
}

0 commit comments

Comments
 (0)