Skip to content

Commit d766093

Browse files
authored
Merge pull request #86 from cipherstash/feat/per-dataset-ops
Feat/per dataset ops
2 parents ef3aa7d + fdad621 commit d766093

20 files changed

+1832
-1267
lines changed

Cargo.lock

Lines changed: 537 additions & 320 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ keywords = ["cryptography", "security", "databases", "encryption", "dynamodb"]
1313
categories = ["cryptography", "database"]
1414

1515
[dependencies]
16-
cipherstash-client = { version = "0.12.5" }
16+
cipherstash-client = { version = "0.13.0-pre.1" }
1717
cipherstash-dynamodb-derive = { version = "0.8", path = "cipherstash-dynamodb-derive" }
1818

1919
aws-sdk-dynamodb = "1.3.0"
@@ -26,6 +26,7 @@ hex = "0.4.3"
2626
tracing = { version = "0.1", features = ["log"] }
2727
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"]}
2828
miette = "7.2.0"
29+
uuid = "1.10.0"
2930

3031
[dev-dependencies]
3132
tokio = { version = "1", features = ["full"] }

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: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
use crate::{
22
crypto::{attrs::flattened_protected_attributes::FlattenedAttrName, SealError},
3-
encrypted_table::TableAttributes,
3+
encrypted_table::{TableAttributes, ZeroKmsCipher},
44
traits::TableAttribute,
55
};
6-
use cipherstash_client::{
7-
credentials::{service_credentials::ServiceToken, Credentials},
8-
encryption::Encryption,
9-
zerokms::EncryptedRecord,
10-
};
6+
use cipherstash_client::{encryption::Plaintext, zerokms::EncryptedRecord};
117
use itertools::Itertools;
128

139
use super::FlattenedProtectedAttributes;
@@ -36,7 +32,7 @@ impl FlattenedEncryptedAttributes {
3632
/// Decrypt self, returning a [FlattenedProtectedAttributes].
3733
pub(crate) async fn decrypt_all(
3834
self,
39-
cipher: &Encryption<impl Credentials<Token = ServiceToken>>,
35+
cipher: &ZeroKmsCipher,
4036
) -> Result<FlattenedProtectedAttributes, SealError> {
4137
let descriptors = self
4238
.attrs
@@ -47,8 +43,16 @@ impl FlattenedEncryptedAttributes {
4743
cipher
4844
.decrypt(self.attrs.into_iter())
4945
.await
50-
.map(|records| records.into_iter().zip(descriptors.into_iter()).collect())
51-
.map_err(SealError::from)
46+
.map(|records| {
47+
records
48+
.into_iter()
49+
// FIXME: We should change the decrypt method to return a plaintext and/or make a Plaintext::from_bytes method which consumes the bytes
50+
.map(|bytes| Plaintext::from_slice(&bytes).unwrap())
51+
.zip(descriptors.into_iter())
52+
.collect()
53+
})
54+
// FIXME: EncryptedRecord should return an error exposed in cipherstash_client
55+
.map_err(|_| SealError::AssertionFailed("FIXME".to_string()))
5256
}
5357

5458
/// Denormalize the encrypted records into a TableAttributes.
@@ -59,7 +63,7 @@ impl FlattenedEncryptedAttributes {
5963
.into_iter()
6064
.map(|record| {
6165
record
62-
.to_vec()
66+
.to_mp_bytes()
6367
.map(|data| (FlattenedAttrName::parse(&record.descriptor), data))
6468
.map_err(|_| SealError::AssertionFailed("Decryption failed".to_string()))
6569
})

src/crypto/attrs/flattened_protected_attributes.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ use super::{
22
flattened_encrypted_attributes::FlattenedEncryptedAttributes,
33
normalized_protected_attributes::NormalizedKey,
44
};
5-
use crate::{crypto::SealError, encrypted_table::AttributeName};
5+
use crate::{
6+
crypto::SealError,
7+
encrypted_table::{AttributeName, ScopedZeroKmsCipher},
8+
};
69
use cipherstash_client::{
7-
credentials::{service_credentials::ServiceToken, Credentials},
8-
encryption::{BytesWithDescriptor, Encryption, Plaintext},
10+
encryption::{BytesWithDescriptor, Plaintext},
11+
zerokms::EncryptPayload,
912
};
1013
use itertools::Itertools;
1114

@@ -32,13 +35,14 @@ impl FlattenedProtectedAttributes {
3235
/// The output is a vec of `chunk_into` [FlattenedEncryptedAttributes] objects.
3336
pub(crate) async fn encrypt_all(
3437
self,
35-
cipher: &Encryption<impl Credentials<Token = ServiceToken>>,
38+
cipher: &ScopedZeroKmsCipher,
3639
chunk_into: usize,
3740
) -> Result<Vec<FlattenedEncryptedAttributes>, SealError> {
3841
let chunk_size = self.0.len() / chunk_into;
42+
let payloads: Vec<BytesWithDescriptor> = self.0.into_iter().map(Into::into).collect();
3943

4044
cipher
41-
.encrypt(self.0.into_iter())
45+
.encrypt(payloads.iter().map(EncryptPayload::from))
4246
.await?
4347
.into_iter()
4448
.chunks(chunk_size)

src/crypto/mod.rs

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,8 @@ use crate::{
88
Identifiable, IndexType, PrimaryKey,
99
};
1010
use cipherstash_client::{
11-
credentials::{service_credentials::ServiceToken, Credentials},
12-
encryption::{
13-
compound_indexer::{CompoundIndex, ExactIndex},
14-
Encryption, EncryptionError, Plaintext, TypeParseError,
15-
},
16-
zerokms::Error as ZeroKmsError,
11+
encryption::{EncryptionError, TypeParseError},
12+
zerokms,
1713
};
1814
use miette::Diagnostic;
1915
use std::borrow::Cow;
@@ -47,15 +43,15 @@ pub enum SealError {
4743
#[error("Assertion failed: {0}")]
4844
AssertionFailed(String),
4945

50-
// Note that we don't expose the specific error type here
51-
// so as to avoid leaking any information
5246
#[error(transparent)]
53-
EncryptionError(#[from] EncryptionError),
47+
CryptoError(#[from] zerokms::Error),
5448

49+
/// Error resulting from Indexing in `cipherstash_client::encryption::compound_indexer`
5550
#[error(transparent)]
56-
ZeroKmsError(#[from] ZeroKmsError),
51+
IndexError(#[from] EncryptionError),
5752
}
5853

54+
// TODO: Possibly remove this
5955
#[derive(Error, Debug)]
6056
pub enum CryptoError {
6157
#[error("EncryptionError: {0}")]
@@ -94,32 +90,6 @@ pub(crate) fn all_index_keys<'a>(
9490
.collect()
9591
}
9692

97-
/// Use a CipherStash [`ExactIndex`] to take the HMAC of a string with a provided salt
98-
///
99-
/// This value is used for term index keys and "encrypted" partition / sort keys
100-
pub fn hmac(
101-
value: &str,
102-
salt: Option<&str>,
103-
cipher: &Encryption<impl Credentials<Token = ServiceToken>>,
104-
) -> Result<Vec<u8>, EncryptionError> {
105-
let plaintext = Plaintext::Utf8Str(Some(value.to_string()));
106-
let index = CompoundIndex::new(ExactIndex::new(vec![]));
107-
108-
cipher
109-
.compound_index(
110-
&index,
111-
plaintext,
112-
// passing None here results in no terms so pass an empty string
113-
Some(salt.unwrap_or("")),
114-
32,
115-
)?
116-
.as_binary()
117-
.ok_or(EncryptionError::IndexingError(
118-
"Invalid term type".to_string(),
119-
))
120-
}
121-
122-
// Contains all the necessary information to encrypt the primary key pair
12393
#[derive(Clone)]
12494
pub struct PreparedPrimaryKey {
12595
pub primary_key_parts: PrimaryKeyParts,

src/crypto/sealed.rs

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
use crate::{
22
crypto::attrs::FlattenedEncryptedAttributes,
3-
encrypted_table::TableEntry,
3+
encrypted_table::{TableEntry, ZeroKmsCipher},
44
traits::{ReadConversionError, WriteConversionError},
55
Decryptable, Identifiable,
66
};
77
use aws_sdk_dynamodb::{primitives::Blob, types::AttributeValue};
8-
use cipherstash_client::{
9-
credentials::{service_credentials::ServiceToken, Credentials},
10-
encryption::Encryption,
11-
};
128
use itertools::Itertools;
139
use std::{borrow::Cow, collections::HashMap};
1410

@@ -72,7 +68,7 @@ impl SealedTableEntry {
7268
pub(crate) async fn unseal_all(
7369
items: Vec<Self>,
7470
spec: UnsealSpec<'_>,
75-
cipher: &Encryption<impl Credentials<Token = ServiceToken>>,
71+
cipher: &ZeroKmsCipher,
7672
) -> Result<Vec<Unsealed>, SealError> {
7773
let UnsealSpec {
7874
protected_attributes,
@@ -134,7 +130,7 @@ impl SealedTableEntry {
134130
pub(crate) async fn unseal(
135131
self,
136132
spec: UnsealSpec<'_>,
137-
cipher: &Encryption<impl Credentials<Token = ServiceToken>>,
133+
cipher: &ZeroKmsCipher,
138134
) -> Result<Unsealed, SealError> {
139135
let mut vec = Self::unseal_all(vec![self], spec, cipher).await?;
140136

@@ -207,35 +203,36 @@ impl TryFrom<SealedTableEntry> for HashMap<String, AttributeValue> {
207203

208204
#[cfg(test)]
209205
mod tests {
206+
use crate::encrypted_table::ZeroKmsCipher;
207+
210208
use super::SealedTableEntry;
211209
use cipherstash_client::{
212-
credentials::{auto_refresh::AutoRefresh, service_credentials::ServiceCredentials},
213-
encryption::Encryption,
214-
ConsoleConfig, ZeroKMS, ZeroKMSConfig,
210+
credentials::auto_refresh::AutoRefresh, ConsoleConfig, ZeroKMS, ZeroKMSConfig,
215211
};
216212
use miette::IntoDiagnostic;
217-
use std::borrow::Cow;
218-
219-
type Cipher = Encryption<AutoRefresh<ServiceCredentials>>;
213+
use std::{borrow::Cow, sync::Arc};
220214

221215
// FIXME: Use the test cipher from CipherStash Client when that's ready
222-
async fn get_cipher() -> Result<Cipher, Box<dyn std::error::Error>> {
223-
let console_config = ConsoleConfig::builder().with_env().build()?;
216+
async fn get_cipher() -> Result<Arc<ZeroKmsCipher>, Box<dyn std::error::Error>> {
217+
let console_config = ConsoleConfig::builder()
218+
.with_env()
219+
.build()
220+
.into_diagnostic()?;
224221
let zero_kms_config = ZeroKMSConfig::builder()
225222
.decryption_log(true)
226223
.with_env()
227224
.console_config(&console_config)
228-
.build_with_client_key()?;
225+
.build_with_client_key()
226+
.into_diagnostic()?;
229227

230-
let zero_kms_client = ZeroKMS::new_with_client_key(
228+
let cipher = ZeroKMS::new_with_client_key(
231229
&zero_kms_config.base_url(),
232230
AutoRefresh::new(zero_kms_config.credentials()),
233231
zero_kms_config.decryption_log_path().as_deref(),
234232
zero_kms_config.client_key(),
235233
);
236234

237-
let config = zero_kms_client.load_dataset_config().await?;
238-
Ok(Encryption::new(config.index_root_key, zero_kms_client))
235+
Ok(Arc::new(cipher))
239236
}
240237

241238
#[tokio::test]
@@ -248,6 +245,7 @@ mod tests {
248245
let results = SealedTableEntry::unseal_all(vec![], spec, &cipher)
249246
.await
250247
.into_diagnostic()?;
248+
251249
assert!(results.is_empty());
252250

253251
Ok(())

0 commit comments

Comments
 (0)