Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Cryptography API #144

Merged
merged 19 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
zedgell marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,7 @@ path = "examples/pubsub/subscriber.rs"
[[example]]
name = "secrets-bulk"
path = "examples/secrets-bulk/app.rs"

[[example]]
name = "crypto"
path = "examples/crypto/main.rs"
40 changes: 40 additions & 0 deletions examples/crypto/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Crypto Example

This is a simple example that demonstrates Dapr's Cryptography capabilities.

> **Note:** Make sure to use latest version of proto bindings.

## Running

> Before you run the example make sure generate keys in examples/crypto/keys directory:
> ```
> mkdir -p keys
> # Generate a private RSA key, 4096-bit keys
> openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out keys/rsa-private-key.pem
> # Generate a 256-bit key for AES
> openssl rand -out keys/symmetric-key-256 32
> ```
mikeee marked this conversation as resolved.
Show resolved Hide resolved

To run this example:

1. Run the multi-app run template:

<!-- STEP
name: Run Subscriber
zedgell marked this conversation as resolved.
Show resolved Hide resolved
output_match_mode: substring
match_order: none
expected_stdout_lines:
- '== APP - crypto-example == Successfully Decrypted String'
- '== APP - crypto-example == Successfully Decrypted Image'
background: true
sleep: 30
timeout_seconds: 90
-->

```bash
dapr run -f .
```

<!-- END_STEP -->

2. Stop with `ctrl + c`
11 changes: 11 additions & 0 deletions examples/crypto/components/local-storage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: localstorage
spec:
type: crypto.dapr.localstorage
version: v1
metadata:
- name: path
# Path is relative to the folder where the example is located
value: ./keys
10 changes: 10 additions & 0 deletions examples/crypto/dapr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 1
common:
daprdLogDestination: console
apps:
- appID: crypto-example
appDirPath: ./
daprGRPCPort: 35002
logLevel: debug
command: [ "cargo", "run", "--example", "crypto" ]
resourcesPath: ./components
Binary file added examples/crypto/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 78 additions & 0 deletions examples/crypto/main.rs
zedgell marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use std::fs;

use tokio::time::sleep;

use dapr::dapr::dapr::proto::runtime::v1::{DecryptRequestOptions, EncryptRequestOptions};
zedgell marked this conversation as resolved.
Show resolved Hide resolved

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
sleep(std::time::Duration::new(2, 0)).await;
let port: u16 = std::env::var("DAPR_GRPC_PORT")?.parse()?;
let addr = format!("https://127.0.0.1:{}", port);

let mut client = dapr::Client::<dapr::client::TonicClient>::connect(addr).await?;

let encrypted = client
.encrypt(
&"Test".to_string(),
EncryptRequestOptions {
component_name: "localstorage".to_string(),
key_name: "rsa-private-key.pem".to_string(),
key_wrap_algorithm: "RSA".to_string(),
data_encryption_cipher: "aes-gcm".to_string(),
omit_decryption_key_name: false,
decryption_key_name: "rsa-private-key.pem".to_string(),
},
)
.await
.unwrap();

let decrypted = client
.decrypt(
encrypted,
DecryptRequestOptions {
zedgell marked this conversation as resolved.
Show resolved Hide resolved
component_name: "localstorage".to_string(),
key_name: "rsa-private-key.pem".to_string(),
},
)
.await
.unwrap();

assert_eq!(String::from_utf8(decrypted).unwrap().as_str(), "Test");

println!("Successfully Decrypted String");

let image = fs::read("./image.png").unwrap();

let encrypted = client
.encrypt(
&image,
EncryptRequestOptions {
zedgell marked this conversation as resolved.
Show resolved Hide resolved
component_name: "localstorage".to_string(),
key_name: "rsa-private-key.pem".to_string(),
key_wrap_algorithm: "RSA".to_string(),
data_encryption_cipher: "aes-gcm".to_string(),
omit_decryption_key_name: false,
decryption_key_name: "rsa-private-key.pem".to_string(),
},
)
.await
.unwrap();

let decrypted = client
.decrypt(
encrypted,
DecryptRequestOptions {
zedgell marked this conversation as resolved.
Show resolved Hide resolved
component_name: "localstorage".to_string(),
key_name: "rsa-private-key.pem".to_string(),
},
)
.await
.unwrap();

assert_eq!(decrypted, image);

println!("Successfully Decrypted Image");

Ok(())
}
11 changes: 6 additions & 5 deletions src/client.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use crate::dapr::dapr::proto::{common::v1 as common_v1, runtime::v1 as dapr_v1};
use prost_types::Any;
use std::collections::HashMap;

use async_trait::async_trait;
use prost_types::Any;
use serde::{Deserialize, Serialize};
use tonic::Streaming;
use tonic::{transport::Channel as TonicChannel, Request};

use crate::dapr::dapr::proto::{common::v1 as common_v1, runtime::v1 as dapr_v1};
use crate::error::Error;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};

#[derive(Clone)]
pub struct Client<T>(T);
pub struct Client<T>(pub(crate) T);

zedgell marked this conversation as resolved.
Show resolved Hide resolved
impl<T: DaprInterface> Client<T> {
/// Connect to a Dapr enabled app.
Expand Down
78 changes: 78 additions & 0 deletions src/crypto.rs
zedgell marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use futures::StreamExt;
use tonic::codegen::tokio_stream;
use tonic::{Request, Status};

use crate::client::TonicClient;
use crate::dapr::dapr::proto::common::v1::StreamPayload;
use crate::dapr::dapr::proto::runtime::v1::{
DecryptRequest, DecryptRequestOptions, EncryptRequest, EncryptRequestOptions,
};
use crate::Client;

impl Client<TonicClient> {
pub async fn encrypt<T>(
&mut self,
payload: &T,
request_options: EncryptRequestOptions,
) -> Result<Vec<StreamPayload>, Status>
where
T: Into<Vec<u8>> + Clone,
{
let stream_payload = StreamPayload {
data: payload.clone().into(),
seq: 0,
};
let request = EncryptRequest {
options: Some(request_options),
payload: Some(stream_payload),
};
let request = Request::new(tokio_stream::iter([request]));
let stream = self.0.encrypt_alpha1(request).await?;
let mut stream = stream.into_inner();
let mut return_data = vec![];
while let Some(resp) = stream.next().await {
if let Ok(resp) = resp {
if let Some(data) = resp.payload {
return_data.push(data)
}
}
}
Ok(return_data)
}

pub async fn decrypt(
&mut self,
encrypted: Vec<StreamPayload>,
options: DecryptRequestOptions,
) -> Result<Vec<u8>, Status> {
let requested_items: Vec<DecryptRequest> = encrypted
.iter()
.enumerate()
.map(|(i, item)| {
if i == 0 {
DecryptRequest {
options: Some(options.clone()),
payload: Some(item.clone()),
}
} else {
DecryptRequest {
options: None,
payload: Some(item.clone()),
}
}
})
.collect();
let request = Request::new(tokio_stream::iter(requested_items));
let stream = self.0.decrypt_alpha1(request).await?;
let mut stream = stream.into_inner();
let mut data = vec![];
while let Some(resp) = stream.next().await {
if let Ok(resp) = resp {
if let Some(mut payload) = resp.payload {
data.append(payload.data.as_mut())
}
}
}
Ok(data)
}
}
11 changes: 6 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
extern crate dapr_macros;

pub use client::Client;
pub use dapr_macros::actor;

pub mod appcallback;
pub mod client;
pub mod crypto;
pub mod dapr;
pub mod error;
pub mod server;

pub use client::Client;

extern crate dapr_macros;
pub use dapr_macros::actor;
Loading