mirror of https://github.com/dapr/dotnet-sdk.git
Add Dapr.Cryptography package + fix for large files (#1527)
* Implementation of the new crypto client Signed-off-by: Whit Waldo <whit.waldo@innovian.net> Co-authored-by: Christopher Watford <83599748+watfordsuzy@users.noreply.github.com>
This commit is contained in:
parent
6d92113788
commit
49992f4a86
39
all.sln
39
all.sln
|
|
@ -111,8 +111,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapr.Actors.Generators.Test
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapr.E2E.Test.Actors.Generators", "test\Dapr.E2E.Test.Actors.Generators\Dapr.E2E.Test.Actors.Generators.csproj", "{B5CDB0DC-B26D-48F1-B934-FE5C1C991940}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cryptography", "examples\Client\Cryptography\Cryptography.csproj", "{C74FBA78-13E8-407F-A173-4555AEE41FF3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Protos", "src\Dapr.Protos\Dapr.Protos.csproj", "{DFBABB04-50E9-42F6-B470-310E1B545638}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Common", "src\Dapr.Common\Dapr.Common.csproj", "{B445B19C-A925-4873-8CB7-8317898B6970}"
|
||||
|
|
@ -143,8 +141,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Messaging.Test", "test
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Messaging", "src\Dapr.Messaging\Dapr.Messaging.csproj", "{0EAE36A1-B578-4F13-A113-7A477ECA1BDA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreamingSubscriptionExample", "examples\Client\PublishSubscribe\StreamingSubscriptionExample\StreamingSubscriptionExample.csproj", "{290D1278-F613-4DF3-9DF5-F37E38CDC363}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs", "src\Dapr.Jobs\Dapr.Jobs.csproj", "{C8BB6A85-A7EA-40C0-893D-F36F317829B3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Test", "test\Dapr.Jobs.Test\Dapr.Jobs.Test.csproj", "{BF9828E9-5597-4D42-AA6E-6E6C12214204}"
|
||||
|
|
@ -169,6 +165,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Actors.Analyzers.Test"
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Analyzers.Common", "test\Dapr.Analyzers.Common\Dapr.Analyzers.Common.csproj", "{7E23E229-6823-4D84-AF3A-AE14CEAEF52A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Cryptography", "src\Dapr.Cryptography\Dapr.Cryptography.csproj", "{160EFFA0-F6B9-49E4-B62B-68C0D53DB425}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Cryptography.Test", "test\Dapr.Cryptography.Test\Dapr.Cryptography.Test.csproj", "{B508EBD6-0F14-480C-A446-45A09052733B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreamingSubscriptionExample", "examples\Messaging\StreamingSubscriptionExample\StreamingSubscriptionExample.csproj", "{E070F694-335D-4D96-8951-F41D0A5F2A8B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cryptography", "Cryptography", "{6843B5B3-9E95-4022-B792-8A1DE6BFEFEC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cryptography", "examples\Cryptography\Cryptography.csproj", "{097D5F6F-D26F-4BFB-9074-FA52577EB442}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Messaging", "Messaging", "{442E80E5-8040-4123-B88A-26FD36BA95D9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -445,6 +453,22 @@ Global
|
|||
{7E23E229-6823-4D84-AF3A-AE14CEAEF52A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7E23E229-6823-4D84-AF3A-AE14CEAEF52A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7E23E229-6823-4D84-AF3A-AE14CEAEF52A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{160EFFA0-F6B9-49E4-B62B-68C0D53DB425}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{160EFFA0-F6B9-49E4-B62B-68C0D53DB425}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{160EFFA0-F6B9-49E4-B62B-68C0D53DB425}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{160EFFA0-F6B9-49E4-B62B-68C0D53DB425}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B508EBD6-0F14-480C-A446-45A09052733B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B508EBD6-0F14-480C-A446-45A09052733B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B508EBD6-0F14-480C-A446-45A09052733B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B508EBD6-0F14-480C-A446-45A09052733B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E070F694-335D-4D96-8951-F41D0A5F2A8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E070F694-335D-4D96-8951-F41D0A5F2A8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E070F694-335D-4D96-8951-F41D0A5F2A8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E070F694-335D-4D96-8951-F41D0A5F2A8B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{097D5F6F-D26F-4BFB-9074-FA52577EB442}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{097D5F6F-D26F-4BFB-9074-FA52577EB442}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{097D5F6F-D26F-4BFB-9074-FA52577EB442}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{097D5F6F-D26F-4BFB-9074-FA52577EB442}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -497,7 +521,6 @@ Global
|
|||
{7C06FE2D-6C62-48F5-A505-F0D715C554DE} = {7592AFA4-426B-42F3-AE82-957C86814482}
|
||||
{AF89083D-4715-42E6-93E9-38497D12A8A6} = {DD020B34-460F-455F-8D17-CF4A949F100B}
|
||||
{B5CDB0DC-B26D-48F1-B934-FE5C1C991940} = {DD020B34-460F-455F-8D17-CF4A949F100B}
|
||||
{C74FBA78-13E8-407F-A173-4555AEE41FF3} = {A7F41094-8648-446B-AECD-DCC2CC871F73}
|
||||
{DFBABB04-50E9-42F6-B470-310E1B545638} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
|
||||
{B445B19C-A925-4873-8CB7-8317898B6970} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
|
||||
{CDB47863-BEBD-4841-A807-46D868962521} = {DD020B34-460F-455F-8D17-CF4A949F100B}
|
||||
|
|
@ -525,6 +548,12 @@ Global
|
|||
{E49C822C-E921-48DF-897B-3E603CA596D2} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
|
||||
{A2C0F203-11FF-4B7F-A94F-B9FD873573FE} = {DD020B34-460F-455F-8D17-CF4A949F100B}
|
||||
{7E23E229-6823-4D84-AF3A-AE14CEAEF52A} = {DD020B34-460F-455F-8D17-CF4A949F100B}
|
||||
{160EFFA0-F6B9-49E4-B62B-68C0D53DB425} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
|
||||
{B508EBD6-0F14-480C-A446-45A09052733B} = {DD020B34-460F-455F-8D17-CF4A949F100B}
|
||||
{6843B5B3-9E95-4022-B792-8A1DE6BFEFEC} = {D687DDC4-66C5-4667-9E3A-FD8B78ECAA78}
|
||||
{097D5F6F-D26F-4BFB-9074-FA52577EB442} = {6843B5B3-9E95-4022-B792-8A1DE6BFEFEC}
|
||||
{442E80E5-8040-4123-B88A-26FD36BA95D9} = {D687DDC4-66C5-4667-9E3A-FD8B78ECAA78}
|
||||
{E070F694-335D-4D96-8951-F41D0A5F2A8B} = {442E80E5-8040-4123-B88A-26FD36BA95D9}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {65220BF2-EAE1-4CB2-AA58-EBE80768CB40}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,3 @@ Put the Dapr AI .NET SDK to the test. Walk through the samples to see Dapr in ac
|
|||
|
||||
This part of the .NET SDK allows you to interface with the Conversations API to send and receive messages from
|
||||
large language models.
|
||||
|
||||
### Send messages
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ It maintains access to networking resources in the form of TCP sockets used to c
|
|||
For best performance, create a single long-lived instance of `DaprConversationClient` and provide access to that shared
|
||||
instance throughout your application. `DaprConversationClient` instances are thread-safe and intended to be shared.
|
||||
|
||||
This can be aided by utilizing the dependency injection functionality. The registration method supports registration using
|
||||
This can be aided by utilizing the dependency injection functionality. The registration method supports registration
|
||||
as a singleton, a scoped instance or as transient (meaning it's recreated every time it's injected), but also enables
|
||||
registration to utilize values from an `IConfiguration` or other injected service in a way that's impractical when
|
||||
creating the client from scratch in each of your classes.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
type: docs
|
||||
title: "Dapr Cryptography .NET SDK"
|
||||
linkTitle: "Cryptography"
|
||||
weight: 51000
|
||||
description: Get up and running with the Dapr Cryptography .NET SDK
|
||||
---
|
||||
|
||||
With the Dapr Cryptography package, you can perform high-performance encryption and decryption operations with Dapr.
|
||||
|
||||
To get started with this functionality, walk through the [Dapr Cryptography({{< ref dotnet-cryptography-howto.md >}})
|
||||
how-to guide.
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
type: docs
|
||||
title: "How to: Create an use Dapr Cryptography in the .NET SDK"
|
||||
linkTitle: "How to: Use the Cryptography client"
|
||||
weight: 510100
|
||||
description: Learn how to create and use the Dapr Cryptography client using the .NET SDK
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
- [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0), or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) installed
|
||||
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
|
||||
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost)
|
||||
|
||||
## Installation
|
||||
To get started with the Dapr Cryptography client, install the [Dapr.Cryptography package](https://www.nuget.org/packages/Dapr.Cryptography) from NuGet:
|
||||
```sh
|
||||
dotnet add package Dapr.Cryptography
|
||||
```
|
||||
|
||||
A `DaprEncryptionClient` maintains access to networking resources in the form of TCP sockets used to communicate with
|
||||
the Dapr sidecar.
|
||||
|
||||
### Dependency Injection
|
||||
|
||||
The `AddDaprEncryptionClient()` method will register the Dapr client with dependency injection and is the recommended approach
|
||||
for using this package. This method accepts an optional options delegate for configuring the `DaprEncryptionClient` and a
|
||||
`ServiceLifetime` argument, allowing you to specify a different lifetime for the registered services instead of the default `Singleton`
|
||||
value.
|
||||
|
||||
The following example assumes all default values are acceptable and is sufficient to register the `DaprEncryptionClient`:
|
||||
|
||||
```csharp
|
||||
services.AddDaprEncryptionClient();
|
||||
```
|
||||
|
||||
The optional configuration delegate is used to configure the `DaprEncryptionClient` by specifying options on the
|
||||
`DaprEncryptionClientBuilder` as in the following example:
|
||||
```csharp
|
||||
services.AddSingleton<DefaultOptionsProvider>();
|
||||
services.AddDaprEncryptionClient((serviceProvider, clientBuilder) => {
|
||||
//Inject a service to source a value from
|
||||
var optionsProvider = serviceProvider.GetRequiredService<DefaultOptionsProvider>();
|
||||
var standardTimeout = optionsProvider.GetStandardTimeout();
|
||||
|
||||
//Configure the value on the client builder
|
||||
clientBuilder.UseTimeout(standardTimeout);
|
||||
});
|
||||
```
|
||||
|
||||
### Manual Instantiation
|
||||
Rather than using dependency injection, a `DaprEncryptionClient` can also be built using the static client builder.
|
||||
|
||||
For best performance, create a single long-lived instance of `DaprEncryptionClient` and provide access to that shared instance throughout
|
||||
your application. `DaprEncryptionClient` instances are thread-safe and intended to be shared.
|
||||
|
||||
Avoid creating a `DaprEncryptionClient` per-operation.
|
||||
|
||||
A `DaprEncryptionClient` can be configured by invoking methods on the `DaprEncryptionClientBuilder` class before calling `.Build()`
|
||||
to create the client. The settings for each `DaprEncryptionClient` are separate and cannot be changed after calling `.Build()`.
|
||||
|
||||
```csharp
|
||||
var daprEncryptionClient = new DaprEncryptionClientBuilder()
|
||||
.UseJsonSerializerSettings( ... ) //Configure JSON serializer
|
||||
.Build();
|
||||
```
|
||||
|
||||
See the .NET [documentation here]({{< ref dotnet-client >}}) for more information about the options available when configuring the Dapr client via the builder.
|
||||
|
||||
## Try it out
|
||||
Put the Dapr AI .NET SDK to the test. Walk through the samples to see Dapr in action:
|
||||
|
||||
| SDK Samples | Description |
|
||||
|-------------------------------------------------------------------------------------| ----------- |
|
||||
| [SDK samples](https://github.com/dapr/dotnet-sdk/tree/master/examples/Cryptography) | Clone the SDK repo to try out some examples and get started. |
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
---
|
||||
type: docs
|
||||
title: "Dapr Cryptography Client"
|
||||
linkTitle: "Cryptography client"
|
||||
weight: 510005
|
||||
description: Learn how to create Dapr Crytography clients
|
||||
---
|
||||
|
||||
The Dapr Cryptography package allows you to perform encryption and decryption operations provided by the Dapr sidecar.
|
||||
|
||||
## Lifetime management
|
||||
A `DaprEncryptionClient` is a version of the Dapr client that is dedicated to interacting with the Dapr Cryptography API.
|
||||
It can be registered alongside a `DaprClient` and other Dapr clients without issue.
|
||||
|
||||
It maintains access to networking resources in the form of TCP sockets used to communicate with the Dapr sidecar.
|
||||
|
||||
For best performance, create a single long-lived instance of `DaprEncryptionClient` and provide access to that shared
|
||||
instance throughout your application. `DaprEncryptionClient` instances are thread-safe and intended to be shared.
|
||||
|
||||
This can be aided by utilizing the dependency injection functionality. The registration method supports registration
|
||||
as a singleton, a scoped instance, or as a transient (meaning it's recreated every time it's injected), but also enables
|
||||
registration to utilize values from an `IConfiguration` or other injected service in a way that's impractical when creating
|
||||
the client from scratch in each of your classes.
|
||||
|
||||
Avoid creating a `DaprEncryptionClient` for each operation.
|
||||
|
||||
## Configuring `DaprEncryptionClient` via `DaprEncryptionClientBuilder`
|
||||
A `DaprCryptographyClient` can be configured by invoking methods on the `DaprEncryptionClientBuilder` class before calling
|
||||
`.Build()` to create the client itself. The settings for each `DaprEncryptionClientBuilder` are separate can cannot be
|
||||
changed after calling `.Build()`.
|
||||
|
||||
```cs
|
||||
var daprEncryptionClient = new DaprEncryptionClientBuilder()
|
||||
.UseDaprApiToken("abc123") //Specify the API token used to authenticate to the Dapr sidecar
|
||||
.Build();
|
||||
```
|
||||
|
||||
The `DaprEncryptionClientBuilder` contains settings for:
|
||||
- The HTTP endpoint of the Dapr sidecar
|
||||
- The gRPC endpoint of the Dapr sidecar
|
||||
- The `JsonSerializerOptions` object used to configure JSON serialization
|
||||
- The `GrpcChannelOptions` object used to configure gRPC
|
||||
- The API token used to authenticate requests to the sidecar
|
||||
- The factory method used to create the `HttpClient` instance used by the SDK
|
||||
- The timeout used for the `HttpClient` instance when making requests to the sidecar
|
||||
|
||||
The SDK will read the following environment variables to configure the default values:
|
||||
|
||||
- `DAPR_HTTP_ENDPOINT`: used to find the HTTP endpoint of the Dapr sidecar, example: `https://dapr-api.mycompany.com`
|
||||
- `DAPR_GRPC_ENDPOINT`: used to find the gRPC endpoint of the Dapr sidecar, example: `https://dapr-grpc-api.mycompany.com`
|
||||
- `DAPR_HTTP_PORT`: if `DAPR_HTTP_ENDPOINT` is not set, this is used to find the HTTP local endpoint of the Dapr sidecar
|
||||
- `DAPR_GRPC_PORT`: if `DAPR_GRPC_ENDPOINT` is not set, this is used to find the gRPC local endpoint of the Dapr sidecar
|
||||
- `DAPR_API_TOKEN`: used to set the API token
|
||||
|
||||
### Configuring gRPC channel options
|
||||
|
||||
Dapr's use of `CancellationToken` for cancellation relies on the configuration of the gRPC channel options. If you need
|
||||
to configure these options yourself, make sure to enable the [ThrowOperationCanceledOnCancellation setting](https://grpc.github.io/grpc/csharp-dotnet/api/Grpc.Net.Client.GrpcChannelOptions.html#Grpc_Net_Client_GrpcChannelOptions_ThrowOperationCanceledOnCancellation).
|
||||
|
||||
```cs
|
||||
var daprEncryptionClient = new DaprEncryptionClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { .. ThrowOperationCanceledOnCancellation = true })
|
||||
.Build();
|
||||
```
|
||||
|
||||
## Using cancellation with `DaprEncryptionClient`
|
||||
The APIs on `DaprEncryptionClient` perform asynchronous operations and accept an optional `CancellationToken` parameter. This
|
||||
follows a standard .NET practice for cancellable operations. Note that when cancellation occurs, there is no guarantee that
|
||||
the remote endpoint stops processing the request, only that the client has stopped waiting for completion.
|
||||
|
||||
When an operation is cancelled, it will throw an `OperationCancelledException`.
|
||||
|
||||
## Configuring `DaprEncryptionClient` via dependency injection
|
||||
Using the built-in extension methods for registering the `DaprEncryptionClient` in a dependency injection container can
|
||||
provide the benefit of registering the long-lived service a single time, centralize complex configuration and improve
|
||||
performance by ensuring similarly long-lived resources are re-purposed when possible (e.g. `HttpClient` instances).
|
||||
|
||||
There are three overloads available to give the developer the greatest flexibility in configuring the client for their
|
||||
scenario. Each of these will register the `IHttpClientFactory` on your behalf if not already registered, and configure
|
||||
the `DaprEncryptionClientBuilder` to use it when creating the `HttpClient` instance in order to re-use the same instance as
|
||||
much as possible and avoid socket exhaustion and other issues.
|
||||
|
||||
In the first approach, there's no configuration done by the developer and the `DaprEncryptionClient` is configured with the
|
||||
default settings.
|
||||
|
||||
```cs
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddDaprEncryptionClent(); //Registers the `DaprEncryptionClient` to be injected as needed
|
||||
var app = builder.Build();
|
||||
```
|
||||
|
||||
Sometimes the developer will need to configure the created client using the various configuration options detailed
|
||||
above. This is done through an overload that passes in the `DaprEncryptionClientBuiler` and exposes methods for configuring
|
||||
the necessary options.
|
||||
|
||||
```cs
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddDaprEncryptionClient((_, daprEncrpyptionClientBuilder) => {
|
||||
//Set the API token
|
||||
daprEncryptionClientBuilder.UseDaprApiToken("abc123");
|
||||
//Specify a non-standard HTTP endpoint
|
||||
daprEncryptionClientBuilder.UseHttpEndpoint("http://dapr.my-company.com");
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
```
|
||||
|
||||
Finally, it's possible that the developer may need to retrieve information from another service in order to populate
|
||||
these configuration values. That value may be provided from a `DaprClient` instance, a vendor-specific SDK or some
|
||||
local service, but as long as it's also registered in DI, it can be injected into this configuration operation via the
|
||||
last overload:
|
||||
|
||||
```cs
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
//Register a fictional service that retrieves secrets from somewhere
|
||||
builder.Services.AddSingleton<SecretService>();
|
||||
|
||||
builder.Services.AddDaprEncryptionClient((serviceProvider, daprEncryptionClientBuilder) => {
|
||||
//Retrieve an instance of the `SecretService` from the service provider
|
||||
var secretService = serviceProvider.GetRequiredService<SecretService>();
|
||||
var daprApiToken = secretService.GetSecret("DaprApiToken").Value;
|
||||
|
||||
//Configure the `DaprEncryptionClientBuilder`
|
||||
daprEncryptionClientBuilder.UseDaprApiToken(daprApiToken);
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
```
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2023 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using Cryptography.Examples;
|
||||
|
||||
namespace Cryptography;
|
||||
|
||||
class Program
|
||||
{
|
||||
private const string ComponentName = "localstorage";
|
||||
private const string KeyName = "rsa-private-key.pem"; //This should match the name of your generated key - this sample expects an RSA symmetrical key.
|
||||
|
||||
private static readonly Example[] Examples = new Example[]
|
||||
{
|
||||
new EncryptDecryptStringExample(ComponentName, KeyName),
|
||||
new EncryptDecryptFileStreamExample(ComponentName, KeyName)
|
||||
};
|
||||
|
||||
static async Task<int> Main(string[] args)
|
||||
{
|
||||
if (args.Length > 0 && int.TryParse(args[0], out var index) && index >= 0 && index < Examples.Length)
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
Console.CancelKeyPress += (object? sender, ConsoleCancelEventArgs e) => cts.Cancel();
|
||||
|
||||
await Examples[index].RunAsync(cts.Token);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Console.WriteLine("Hello, please choose a sample to run by passing your selection's number into the arguments, e.g. 'dotnet run 0':");
|
||||
for (var i = 0; i < Examples.Length; i++)
|
||||
{
|
||||
Console.WriteLine($"{i}: {Examples[i].DisplayName}");
|
||||
}
|
||||
Console.WriteLine();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
|
|
@ -7,18 +7,15 @@
|
|||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="C:\Users\whit_\source\repos\dapr-dotnet-sdk\properties\\IsExternalInit.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Dapr.Client\Dapr.Client.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="file.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Dapr.Common\Dapr.Common.csproj" />
|
||||
<ProjectReference Include="..\..\src\Dapr.Cryptography\Dapr.Cryptography.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -12,18 +12,20 @@
|
|||
// ------------------------------------------------------------------------
|
||||
|
||||
using System.Buffers;
|
||||
using Dapr.Client;
|
||||
using System.Text;
|
||||
using Dapr.Cryptography.Encryption;
|
||||
using Dapr.Cryptography.Encryption.Models;
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
|
||||
namespace Cryptography.Examples;
|
||||
|
||||
internal class EncryptDecryptFileStreamExample(string componentName, string keyName) : Example
|
||||
internal sealed class EncryptDecryptFileStreamExample(DaprEncryptionClient daprClient) : IExample
|
||||
{
|
||||
public override string DisplayName => "Use Cryptography to encrypt and decrypt a file";
|
||||
public override async Task RunAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
using var client = new DaprClientBuilder().Build();
|
||||
public static string DisplayName => "Use Cryptography to encrypt and decrypt a file";
|
||||
|
||||
public async Task RunAsync(string componentName, string keyName, CancellationToken cancellationToken)
|
||||
{
|
||||
// The name of the file we're using as an example
|
||||
const string fileName = "file.txt";
|
||||
|
||||
|
|
@ -37,36 +39,35 @@ internal class EncryptDecryptFileStreamExample(string componentName, string keyN
|
|||
await using var encryptFs = new FileStream(fileName, FileMode.Open);
|
||||
|
||||
var bufferedEncryptedBytes = new ArrayBufferWriter<byte>();
|
||||
await foreach (var bytes in (await client.EncryptAsync(componentName, encryptFs, keyName,
|
||||
new EncryptionOptions(KeyWrapAlgorithm.Rsa), cancellationToken))
|
||||
.WithCancellation(cancellationToken))
|
||||
await foreach (var bytes in ((daprClient.EncryptAsync(componentName, encryptFs, keyName,
|
||||
new EncryptionOptions(KeyWrapAlgorithm.Rsa), cancellationToken))))
|
||||
{
|
||||
bufferedEncryptedBytes.Write(bytes.Span);
|
||||
}
|
||||
|
||||
Console.WriteLine("Encrypted bytes:");
|
||||
Console.WriteLine($"Encrypted bytes ({bufferedEncryptedBytes.WrittenMemory.Length} bytes):");
|
||||
Console.WriteLine(Convert.ToBase64String(bufferedEncryptedBytes.WrittenMemory.ToArray()));
|
||||
|
||||
|
||||
//We'll write to a temporary file via a FileStream
|
||||
var tempDecryptedFile = Path.GetTempFileName();
|
||||
await using var decryptFs = new FileStream(tempDecryptedFile, FileMode.Create);
|
||||
|
||||
|
||||
//We'll stream the decrypted bytes from a MemoryStream into the above temporary file
|
||||
await using var encryptedMs = new MemoryStream(bufferedEncryptedBytes.WrittenMemory.ToArray());
|
||||
await foreach (var result in (await client.DecryptAsync(componentName, encryptedMs, keyName,
|
||||
cancellationToken)).WithCancellation(cancellationToken))
|
||||
await foreach (var result in ((daprClient.DecryptAsync(componentName, encryptedMs, keyName,
|
||||
cancellationToken: cancellationToken))))
|
||||
{
|
||||
decryptFs.Write(result.Span);
|
||||
}
|
||||
|
||||
decryptFs.Close();
|
||||
|
||||
|
||||
//Let's confirm the value as written to the file
|
||||
var decryptedValue = await File.ReadAllTextAsync(tempDecryptedFile, cancellationToken);
|
||||
Console.WriteLine("Decrypted value: ");
|
||||
Console.WriteLine($"Decrypted value ({Encoding.UTF8.GetByteCount(decryptedValue)} bytes): ");
|
||||
Console.WriteLine(decryptedValue);
|
||||
|
||||
|
||||
//And some cleanup to delete our temp file
|
||||
File.Delete(tempDecryptedFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using System.Security.Cryptography;using Dapr.Cryptography.Encryption;
|
||||
using Dapr.Cryptography.Encryption.Models;
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
|
||||
namespace Cryptography.Examples;
|
||||
|
||||
internal sealed class EncryptDecryptLargeFileExample(DaprEncryptionClient daprClient) : IExample
|
||||
{
|
||||
public static string DisplayName => "Use Cryptography to encrypt and decrypt a large file";
|
||||
|
||||
public async Task RunAsync(string componentName, string keyName, CancellationToken cancellationToken)
|
||||
{
|
||||
//Create our large file locally and fill with random bytes
|
||||
const string fileName = "templargefile.txt";
|
||||
const long sizeLimitInBytes = 1L * 1024 * 1024 * 1024; //1 GB
|
||||
await WriteLargeFileAsync(fileName, sizeLimitInBytes);
|
||||
|
||||
//Get the starting hash of the file for comparison reasons
|
||||
var startingFileHash = await GetFileHashAsync(fileName);
|
||||
var startingFileLength = new FileInfo(fileName).Length;
|
||||
Console.WriteLine($"Starting with a file spanning {startingFileLength} bytes called '{fileName}' filled with random bytes with MD5 hash of: '{startingFileHash}'");
|
||||
|
||||
//Encrypt from the file stream and write the result to another file
|
||||
const string encryptedFileName = "enc_templargefile.txt";
|
||||
await using (var encryptFs = new FileStream(fileName, FileMode.Open))
|
||||
{
|
||||
await using (var encryptedFs = new FileStream(encryptedFileName, FileMode.Create))
|
||||
{
|
||||
await foreach (var encryptedBytes in ((daprClient.EncryptAsync(componentName, encryptFs, keyName,
|
||||
new EncryptionOptions(KeyWrapAlgorithm.Rsa), cancellationToken))))
|
||||
{
|
||||
await encryptedFs.WriteAsync(encryptedBytes, cancellationToken);
|
||||
}
|
||||
|
||||
encryptedFs.Close();
|
||||
}
|
||||
}
|
||||
|
||||
//Get a hash and length of our newly encrypted file
|
||||
var encryptedFileHash = await GetFileHashAsync(encryptedFileName);
|
||||
var encryptedFileLength = new FileInfo(encryptedFileName).Length;
|
||||
Console.WriteLine($"Encrypted file spanning {encryptedFileLength} bytes called '{encryptedFileName}' with MD5 hash of: '{encryptedFileHash}'");
|
||||
|
||||
//Now we'll decrypt the file back into another file
|
||||
const string decryptedFileName = "dec_templargefile.txt";
|
||||
await using (var decryptFs = new FileStream(encryptedFileName, FileMode.Open))
|
||||
{
|
||||
await using (var decryptedFs = new FileStream(decryptedFileName, FileMode.Create))
|
||||
{
|
||||
await foreach (var decryptedBytes in ((daprClient.DecryptAsync(componentName, decryptFs, keyName,
|
||||
cancellationToken: cancellationToken))))
|
||||
{
|
||||
await decryptedFs.WriteAsync(decryptedBytes, cancellationToken);
|
||||
}
|
||||
|
||||
decryptedFs.Close();
|
||||
}
|
||||
}
|
||||
|
||||
//Get the hash and length of the decrypted file
|
||||
var decryptedFileHash = await GetFileHashAsync(decryptedFileName);
|
||||
var decryptedFileLength = new FileInfo(decryptedFileName).Length;
|
||||
Console.WriteLine($"Decrypted file spanning {decryptedFileLength} bytes called '{decryptedFileName}' with MD5 hash of: '{decryptedFileHash}'");
|
||||
|
||||
var match = string.Equals(startingFileHash, decryptedFileHash);
|
||||
Console.WriteLine($"The hash of the original and decrypted file are {(match ? "": "NOT ")}the same!");
|
||||
|
||||
//Clean up our large files
|
||||
File.Delete(fileName);
|
||||
File.Delete(encryptedFileName);
|
||||
File.Delete(decryptedFileName);
|
||||
}
|
||||
|
||||
private static async Task WriteLargeFileAsync(string fileName, long sizeLimit)
|
||||
{
|
||||
var buffer = new byte[5 * 1024 * 1024]; // 5 MB buffer
|
||||
await using var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||
for (var written = 0; written < sizeLimit; written += buffer.Length)
|
||||
{
|
||||
Random.Shared.NextBytes(buffer);
|
||||
await fs.WriteAsync(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<string> GetFileHashAsync(string fileName)
|
||||
{
|
||||
using var md5 = MD5.Create();
|
||||
await using var stream = File.OpenRead(fileName);
|
||||
return Convert.ToBase64String(await md5.ComputeHashAsync(stream));
|
||||
}
|
||||
}
|
||||
|
|
@ -12,31 +12,29 @@
|
|||
// ------------------------------------------------------------------------
|
||||
|
||||
using System.Text;
|
||||
using Dapr.Client;
|
||||
using Dapr.Cryptography.Encryption;
|
||||
using Dapr.Cryptography.Encryption.Models;
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
|
||||
namespace Cryptography.Examples;
|
||||
|
||||
internal class EncryptDecryptStringExample(string componentName, string keyName) : Example
|
||||
internal sealed class EncryptDecryptStringExample(DaprEncryptionClient daprClient) : IExample
|
||||
{
|
||||
public override string DisplayName => "Using Cryptography to encrypt and decrypt a string";
|
||||
|
||||
public override async Task RunAsync(CancellationToken cancellationToken)
|
||||
public static string DisplayName => "Using Cryptography to encrypt and decrypt a string";
|
||||
public async Task RunAsync(string componentName, string keyName, CancellationToken cancellationToken)
|
||||
{
|
||||
using var client = new DaprClientBuilder().Build();
|
||||
|
||||
const string plaintextStr = "This is the value we're going to encrypt today";
|
||||
Console.WriteLine($"Original string value: '{plaintextStr}'");
|
||||
|
||||
//Encrypt the string
|
||||
var plaintextBytes = Encoding.UTF8.GetBytes(plaintextStr);
|
||||
var encryptedBytesResult = await client.EncryptAsync(componentName, plaintextBytes, keyName, new EncryptionOptions(KeyWrapAlgorithm.Rsa),
|
||||
cancellationToken);
|
||||
var encryptedBytesResult = await daprClient.EncryptAsync(componentName, plaintextBytes, keyName, new EncryptionOptions(KeyWrapAlgorithm.Rsa), cancellationToken);
|
||||
|
||||
Console.WriteLine($"Encrypted bytes: '{Convert.ToBase64String(encryptedBytesResult.Span)}'");
|
||||
Console.WriteLine($"Encrypted bytes ({encryptedBytesResult.Length} bytes): '{Convert.ToBase64String(encryptedBytesResult.Span)}'");
|
||||
|
||||
//Decrypt the string
|
||||
var decryptedBytes = await client.DecryptAsync(componentName, encryptedBytesResult, keyName, cancellationToken);
|
||||
Console.WriteLine($"Decrypted string: '{Encoding.UTF8.GetString(decryptedBytes.ToArray())}'");
|
||||
var decryptedBytes = await daprClient.DecryptAsync(componentName, encryptedBytesResult, keyName, cancellationToken: cancellationToken);
|
||||
Console.WriteLine($"Decrypted string ({decryptedBytes.Length} bytes): '{Encoding.UTF8.GetString(decryptedBytes.ToArray())}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,9 +13,7 @@
|
|||
|
||||
namespace Cryptography;
|
||||
|
||||
internal abstract class Example
|
||||
internal interface IExample
|
||||
{
|
||||
public abstract string DisplayName { get; }
|
||||
|
||||
public abstract Task RunAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
public Task RunAsync(string componentName, string keyName, CancellationToken cancellationToken);
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2023 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using Cryptography.Examples;
|
||||
using Dapr.Cryptography.Encryption.Extensions;
|
||||
|
||||
const string ComponentName = "localstorage";
|
||||
const string KeyName = "rsa-private-key.pem"; //This should match the name of your generated key - this sample expects an RSA symmetrical key.
|
||||
|
||||
if (int.TryParse(args[0], out var exampleId))
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Services.AddDaprEncryptionClient((sp, opt) =>
|
||||
{
|
||||
opt.UseHttpEndpoint("http://localhost:6552");
|
||||
opt.UseGrpcEndpoint("http://localhost:6551");
|
||||
});
|
||||
builder.Services.AddTransient<EncryptDecryptStringExample>();
|
||||
builder.Services.AddTransient<EncryptDecryptFileStreamExample>();
|
||||
builder.Services.AddTransient<EncryptDecryptLargeFileExample>();
|
||||
var app = builder.Build();
|
||||
|
||||
var ctx = new CancellationTokenSource();
|
||||
Console.CancelKeyPress += (object? sender, ConsoleCancelEventArgs e) => ctx.Cancel();
|
||||
|
||||
switch (exampleId)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
var ex0 = app.Services.GetRequiredService<EncryptDecryptStringExample>();
|
||||
await ex0.RunAsync(ComponentName, KeyName, ctx.Token);
|
||||
return 0;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
var ex1 = app.Services.GetRequiredService<EncryptDecryptFileStreamExample>();
|
||||
await ex1.RunAsync(ComponentName, KeyName, ctx.Token);
|
||||
return 0;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
var ex2 = app.Services.GetRequiredService<EncryptDecryptLargeFileExample>();
|
||||
await ex2.RunAsync(ComponentName, KeyName, ctx.Token);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Please choose a sample to run by passing your selection's number into the arguments, e.g. 'dotnet run 0':");
|
||||
Console.WriteLine($"0: {EncryptDecryptStringExample.DisplayName}");
|
||||
Console.WriteLine($"1: {EncryptDecryptFileStreamExample.DisplayName}");
|
||||
Console.WriteLine($"2: {EncryptDecryptLargeFileExample.DisplayName}");
|
||||
Console.WriteLine();
|
||||
return 1;
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
using System.Text;
|
||||
|
||||
|
||||
using System.Text;
|
||||
using Dapr.Messaging.PublishSubscribe;
|
||||
using Dapr.Messaging.PublishSubscribe.Extensions;
|
||||
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\src\Dapr.Messaging\Dapr.Messaging.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Dapr.Messaging\Dapr.Messaging.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -8,3 +8,4 @@ This repository contains a samples that highlight the Dapr .NET SDK capabilities
|
|||
| [2. Actor](./Actor) | Demonstrates creating virtual actors that encapsulate code and state. |
|
||||
| [3. ASP.NET Core](./AspNetCore) | Demonstrates ASP.NET Core integration with Dapr by creating Controllers and Routes. |
|
||||
| [4. Workflow](./Workflow) | Demonstrates creating durable, long-running Dapr workflows using code. |
|
||||
| [5. Cryptography](./Cryptography) | Demonstrates encryption and decryption operations using Dapr. |
|
||||
|
|
@ -19,6 +19,7 @@ using System.Runtime.CompilerServices;
|
|||
[assembly: InternalsVisibleTo("Dapr.AI, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: InternalsVisibleTo("Dapr.AspNetCore, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: InternalsVisibleTo("Dapr.Client, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: InternalsVisibleTo("Dapr.Cryptography, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: InternalsVisibleTo("Dapr.Jobs, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: InternalsVisibleTo("Dapr.Messaging, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: InternalsVisibleTo("Dapr.Extensions.Configuration, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
|
|
@ -34,6 +35,7 @@ using System.Runtime.CompilerServices;
|
|||
[assembly: InternalsVisibleTo("Dapr.AspNetCore.IntegrationTest.App, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: InternalsVisibleTo("Dapr.AspNetCore.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: InternalsVisibleTo("Dapr.Client.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: InternalsVisibleTo("Dapr.Cryptography.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: InternalsVisibleTo("Dapr.Common.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: InternalsVisibleTo("Dapr.E2E.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: InternalsVisibleTo("Dapr.E2E.Test.Actors, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ public abstract class DaprGenericClientBuilder<TClientBuilder> where TClientBuil
|
|||
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
|
||||
}
|
||||
|
||||
var httpEndpoint = new Uri(this.HttpEndpoint);
|
||||
var httpEndpoint = new Uri(this.HttpEndpoint);
|
||||
if (httpEndpoint.Scheme != "http" && httpEndpoint.Scheme != "https")
|
||||
{
|
||||
throw new InvalidOperationException("The HTTP endpoint must use http or https.");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PackageId>Dapr.Cryptography</PackageId>
|
||||
<Title>Dapr Cryptography SDK</Title>
|
||||
<Description>Dapr Cryptography SDK for performing encryption and decryption operations with Dapr</Description>
|
||||
<VersionSuffix>alpha</VersionSuffix>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" />
|
||||
<PackageReference Include="Grpc.Net.Client" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="$(AssemblyName).Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Dapr.Common\Dapr.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using Dapr.Cryptography.Encryption.Models;
|
||||
using Autogenerated = Dapr.Client.Autogen.Grpc.v1.Dapr;
|
||||
|
||||
namespace Dapr.Cryptography.Encryption;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Defines client operations for performing cryptography operations with Dapr..
|
||||
/// Use <see cref="DaprEncryptionClientBuilder"/> to create a <see cref="DaprEncryptionClient"/> or register
|
||||
/// for use with dependency injection via
|
||||
/// <see><cref>DaprJobsServiceCollectionExtensions.AddDaprJobsClient</cref></see>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Implementations of <see cref="DaprEncryptionClient"/> implement <see cref="IDisposable"/> because the
|
||||
/// client accesses network resources. For best performance, create a single long-lived client instance
|
||||
/// and share it for the lifetime of the application. This is done for you if created via the DI extensions. Avoid
|
||||
/// creating a disposing a client instance for each operation that the application performs - this can lead to socket
|
||||
/// exhaustion and other problems.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract class DaprEncryptionClient(Autogenerated.DaprClient client, HttpClient httpClient, string? daprApiToken = null) : IDaprEncryptionClient
|
||||
{
|
||||
private bool disposed;
|
||||
|
||||
/// <summary>
|
||||
/// The HTTP client used by the client for calling the Dapr runtime.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Property exposed for testing purposes.
|
||||
/// </remarks>
|
||||
internal readonly HttpClient HttpClient = httpClient;
|
||||
|
||||
/// <summary>
|
||||
/// The Dapr API token value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Property exposed for testing purposes.
|
||||
/// </remarks>
|
||||
internal readonly string? DaprApiToken = daprApiToken;
|
||||
|
||||
/// <summary>
|
||||
/// The autogenerated Dapr client.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Property exposed for testing purposes.
|
||||
/// </remarks>
|
||||
internal Autogenerated.DaprClient Client { get; } = client;
|
||||
|
||||
/// <summary>
|
||||
/// Encrypts an array of bytes using the Dapr Cryptography encryption functionality.
|
||||
/// </summary>
|
||||
/// <param name="vaultResourceName">The name of the vault resource used by the operation.</param>
|
||||
/// <param name="plaintextBytes">The bytes of the plaintext value to encrypt.</param>
|
||||
/// <param name="keyName">The name of the key to use from the Vault for the encryption operation.</param>
|
||||
/// <param name="encryptionOptions">Options informing how the encryption operation should be configured.</param>
|
||||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
|
||||
/// <returns>An array of encrypted bytes.</returns>
|
||||
[Obsolete("The API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")]
|
||||
public abstract Task<ReadOnlyMemory<byte>> EncryptAsync(string vaultResourceName,
|
||||
ReadOnlyMemory<byte> plaintextBytes, string keyName, EncryptionOptions encryptionOptions,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Encrypts a stream using the Dapr Cryptography encryption functionality.
|
||||
/// </summary>
|
||||
/// <param name="vaultResourceName">The name of the vault resource used by the operation.</param>
|
||||
/// <param name="plaintextStream">The stream containing the bytes of the plaintext value to encrypt.</param>
|
||||
/// <param name="keyName">The name of the key to use from the Vault for the encryption operation.</param>
|
||||
/// <param name="encryptionOptions">Options informing how the encryption operation should be configured.</param>
|
||||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
|
||||
/// <returns>An array of encrypted bytes.</returns>
|
||||
[Obsolete("The API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")]
|
||||
public abstract IAsyncEnumerable<ReadOnlyMemory<byte>> EncryptAsync(string vaultResourceName, Stream plaintextStream, string keyName,
|
||||
EncryptionOptions encryptionOptions, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Decrypts the specified ciphertext bytes using the Dapr Cryptography encryption functionality.
|
||||
/// </summary>
|
||||
/// <param name="vaultResourceName">The name of the vault resource used by the operation.</param>
|
||||
/// <param name="ciphertextBytes">The bytes of the ciphertext value to decrypt.</param>
|
||||
/// <param name="keyName">The name of the key to use from the Vault for the decryption operation.</param>
|
||||
/// <param name="options">Options informing how the decryption operation should be configured.</param>
|
||||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
|
||||
/// <returns>An array of decrypted bytes.</returns>
|
||||
[Obsolete("The API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")]
|
||||
public abstract Task<ReadOnlyMemory<byte>> DecryptAsync(string vaultResourceName, ReadOnlyMemory<byte> ciphertextBytes, string keyName, DecryptionOptions? options = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Decrypts the specified stream of ciphertext using the Dapr Cryptography encryption functionality.
|
||||
/// </summary>
|
||||
/// <param name="vaultResourceName">The name of the vault resource used by the operation.</param>
|
||||
/// <param name="ciphertextStream">The stream containing the bytes of the ciphertext value to decrypt.</param>
|
||||
/// <param name="keyName">The name of the key to use from the Vault for the decryption operation.</param>
|
||||
/// <param name="options">Options informing how the decryption operation should be configured.</param>
|
||||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
|
||||
/// <returns>An asynchronously enumerable array of decrypted bytes.</returns>
|
||||
[Obsolete(
|
||||
"The API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")]
|
||||
public abstract IAsyncEnumerable<ReadOnlyMemory<byte>> DecryptAsync(string vaultResourceName, Stream ciphertextStream,
|
||||
string keyName, DecryptionOptions? options = null, CancellationToken cancellationToken = default);
|
||||
|
||||
internal static KeyValuePair<string, string>? GetDaprApiTokenHeader(string apiToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(apiToken))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new KeyValuePair<string, string>("dapr-api-token", apiToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (!this.disposed)
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
this.disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the resources associated with the object.
|
||||
/// </summary>
|
||||
/// <param name="disposing"><c>true</c> if called by a call to the <c>Dispose</c> method; otherwise false.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using Dapr.Common;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Autogenerated = Dapr.Client.Autogen.Grpc.v1;
|
||||
|
||||
namespace Dapr.Cryptography.Encryption;
|
||||
|
||||
/// <summary>
|
||||
/// Builds a <see cref="DaprEncryptionClient"/>.
|
||||
/// </summary>
|
||||
/// <param name="configuration">An optional instance of <see cref="IConfiguration"/>.</param>
|
||||
public sealed class DaprEncryptionClientBuilder(IConfiguration? configuration = null) : DaprGenericClientBuilder<DaprEncryptionClient>(configuration)
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds the client instance from the properties of the builder.
|
||||
/// </summary>
|
||||
/// <returns>The Dapr client instance.</returns>
|
||||
public override DaprEncryptionClient Build()
|
||||
{
|
||||
var daprClientDependencies = this.BuildDaprClientDependencies(typeof(DaprEncryptionClient).Assembly);
|
||||
var client = new Autogenerated.Dapr.DaprClient(daprClientDependencies.channel);
|
||||
return new DaprEncryptionGrpcClient(client, daprClientDependencies.httpClient, daprClientDependencies.daprApiToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using System.Buffers;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Dapr.Common;
|
||||
using Dapr.Cryptography.Extensions;
|
||||
using Dapr.Common.Extensions;
|
||||
using Dapr.Cryptography.Encryption.Models;
|
||||
using Autogenerated = Dapr.Client.Autogen.Grpc.v1;
|
||||
|
||||
namespace Dapr.Cryptography.Encryption;
|
||||
|
||||
/// <summary>
|
||||
/// A client for performing cryptography operations with Dapr.
|
||||
/// </summary>
|
||||
internal sealed class DaprEncryptionGrpcClient(Autogenerated.Dapr.DaprClient client, HttpClient httpClient, string? daprApiToken = null) : DaprEncryptionClient(client, httpClient, daprApiToken: daprApiToken)
|
||||
{
|
||||
/// <summary>
|
||||
/// Encrypts an array of bytes using the Dapr Cryptography encryption functionality.
|
||||
/// </summary>
|
||||
/// <param name="vaultResourceName">The name of the vault resource used by the operation.</param>
|
||||
/// <param name="plaintextBytes">The bytes of the plaintext value to encrypt.</param>
|
||||
/// <param name="keyName">The name of the key to use from the Vault for the encryption operation.</param>
|
||||
/// <param name="encryptionOptions">Options informing how the encryption operation should be configured.</param>
|
||||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
|
||||
/// <returns>An array of encrypted bytes.</returns>
|
||||
[Obsolete("The API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")]
|
||||
public override async Task<ReadOnlyMemory<byte>> EncryptAsync(
|
||||
string vaultResourceName,
|
||||
ReadOnlyMemory<byte> plaintextBytes,
|
||||
string keyName,
|
||||
EncryptionOptions encryptionOptions,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var memoryStream = plaintextBytes.CreateMemoryStream(true);
|
||||
var encryptionResult = EncryptAsync(vaultResourceName, memoryStream, keyName, encryptionOptions, cancellationToken);
|
||||
|
||||
var bufferedResult = new ArrayBufferWriter<byte>();
|
||||
await foreach (var item in encryptionResult)
|
||||
{
|
||||
bufferedResult.Write(item.Span);
|
||||
}
|
||||
|
||||
return bufferedResult.WrittenMemory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encrypts a stream using the Dapr Cryptography encryption functionality.
|
||||
/// </summary>
|
||||
/// <param name="vaultResourceName">The name of the vault resource used by the operation.</param>
|
||||
/// <param name="plaintextStream">The stream containing the bytes of the plaintext value to encrypt.</param>
|
||||
/// <param name="keyName">The name of the key to use from the Vault for the encryption operation.</param>
|
||||
/// <param name="encryptionOptions">Options informing how the encryption operation should be configured.</param>
|
||||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
|
||||
/// <returns>An array of encrypted bytes.</returns>
|
||||
[Obsolete(
|
||||
"The API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")]
|
||||
public override async IAsyncEnumerable<ReadOnlyMemory<byte>> EncryptAsync(
|
||||
string vaultResourceName,
|
||||
Stream plaintextStream,
|
||||
string keyName,
|
||||
EncryptionOptions encryptionOptions,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentVerifier.ThrowIfNullOrEmpty(vaultResourceName, nameof(vaultResourceName));
|
||||
ArgumentVerifier.ThrowIfNullOrEmpty(keyName, nameof(keyName));
|
||||
ArgumentVerifier.ThrowIfNull(plaintextStream, nameof(plaintextStream));
|
||||
ArgumentVerifier.ThrowIfNull(encryptionOptions, nameof(encryptionOptions));
|
||||
|
||||
EventHandler<Exception> exceptionHandler = (_, ex) => throw ex;
|
||||
|
||||
var shouldOmitDecryptionKeyName =
|
||||
string.IsNullOrWhiteSpace(encryptionOptions
|
||||
.DecryptionKeyName); //Whitespace isn't likely a valid key name either
|
||||
|
||||
var encryptRequestOptions = new Autogenerated.EncryptRequestOptions
|
||||
{
|
||||
ComponentName = vaultResourceName,
|
||||
DataEncryptionCipher = encryptionOptions.EncryptionCipher.GetValueFromEnumMember(),
|
||||
KeyName = keyName,
|
||||
KeyWrapAlgorithm = encryptionOptions.KeyWrapAlgorithm.GetValueFromEnumMember(),
|
||||
OmitDecryptionKeyName = shouldOmitDecryptionKeyName
|
||||
};
|
||||
|
||||
if (!shouldOmitDecryptionKeyName)
|
||||
{
|
||||
ArgumentVerifier.ThrowIfNullOrEmpty(encryptionOptions.DecryptionKeyName,
|
||||
nameof(encryptionOptions.DecryptionKeyName));
|
||||
encryptRequestOptions.DecryptionKeyName = encryptRequestOptions.DecryptionKeyName;
|
||||
}
|
||||
|
||||
var grpcCallOptions = DaprClientUtilities.ConfigureGrpcCallOptions(typeof(DaprEncryptionClient).Assembly,
|
||||
this.DaprApiToken, cancellationToken);
|
||||
var duplexStream = Client.EncryptAlpha1(grpcCallOptions);
|
||||
|
||||
using var streamProcessor = new EncryptionStreamProcessor();
|
||||
try
|
||||
{
|
||||
streamProcessor.OnException += exceptionHandler;
|
||||
await streamProcessor.ProcessStreamAsync(plaintextStream, duplexStream, encryptRequestOptions,
|
||||
encryptionOptions.StreamingBlockSizeInBytes,
|
||||
cancellationToken);
|
||||
|
||||
await foreach (var value in streamProcessor.GetProcessedDataAsync(cancellationToken))
|
||||
{
|
||||
yield return value;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
streamProcessor.OnException -= exceptionHandler;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrypts the specified ciphertext bytes using the Dapr Cryptography encryption functionality.
|
||||
/// </summary>
|
||||
/// <param name="vaultResourceName">The name of the vault resource used by the operation.</param>
|
||||
/// <param name="ciphertextBytes">The bytes of the ciphertext value to decrypt.</param>
|
||||
/// <param name="keyName">The name of the key to use from the Vault for the decryption operation.</param>
|
||||
/// <param name="options">Options informing how the decryption operation should be configured.</param>
|
||||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
|
||||
/// <returns>An array of decrypted bytes.</returns>
|
||||
[Obsolete("The API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")]
|
||||
public override async Task<ReadOnlyMemory<byte>> DecryptAsync(
|
||||
string vaultResourceName,
|
||||
ReadOnlyMemory<byte> ciphertextBytes,
|
||||
string keyName,
|
||||
DecryptionOptions? options = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var memoryStream = ciphertextBytes.CreateMemoryStream(true);
|
||||
var decryptionResult = DecryptAsync(vaultResourceName, memoryStream, keyName, options, cancellationToken);
|
||||
|
||||
var bufferedResult = new ArrayBufferWriter<byte>();
|
||||
await foreach (var item in decryptionResult)
|
||||
{
|
||||
bufferedResult.Write(item.Span);
|
||||
}
|
||||
|
||||
return bufferedResult.WrittenMemory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrypts the specified stream of ciphertext using the Dapr Cryptography encryption functionality.
|
||||
/// </summary>
|
||||
/// <param name="vaultResourceName">The name of the vault resource used by the operation.</param>
|
||||
/// <param name="ciphertextStream">The stream containing the bytes of the ciphertext value to decrypt.</param>
|
||||
/// <param name="keyName">The name of the key to use from the Vault for the decryption operation.</param>
|
||||
/// <param name="options">Options informing how the decryption operation should be configured.</param>
|
||||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
|
||||
/// <returns>An asynchronously enumerable array of decrypted bytes.</returns>
|
||||
[Obsolete(
|
||||
"The API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")]
|
||||
public override async IAsyncEnumerable<ReadOnlyMemory<byte>> DecryptAsync(
|
||||
string vaultResourceName,
|
||||
Stream ciphertextStream,
|
||||
string keyName,
|
||||
DecryptionOptions? options = null,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentVerifier.ThrowIfNullOrEmpty(vaultResourceName, nameof(vaultResourceName));
|
||||
ArgumentVerifier.ThrowIfNullOrEmpty(keyName, nameof(keyName));
|
||||
ArgumentVerifier.ThrowIfNull(ciphertextStream, nameof(ciphertextStream));
|
||||
options = options ?? new DecryptionOptions();
|
||||
|
||||
EventHandler<Exception> exceptionHandler = (_, ex) => throw ex;
|
||||
|
||||
var decryptRequestOptions = new Autogenerated.DecryptRequestOptions
|
||||
{
|
||||
ComponentName = vaultResourceName,
|
||||
KeyName = keyName
|
||||
};
|
||||
|
||||
var grpcCallOptions = DaprClientUtilities.ConfigureGrpcCallOptions(typeof(DaprEncryptionClient).Assembly,
|
||||
this.DaprApiToken, cancellationToken);
|
||||
var duplexStream = Client.DecryptAlpha1(grpcCallOptions);
|
||||
|
||||
using var streamProcessor = new DecryptionStreamProcessor();
|
||||
try
|
||||
{
|
||||
streamProcessor.OnException += exceptionHandler;
|
||||
await streamProcessor.ProcessStreamAsync(ciphertextStream, duplexStream, options.StreamingBlockSizeInBytes,
|
||||
decryptRequestOptions,
|
||||
cancellationToken);
|
||||
|
||||
await foreach (var value in streamProcessor.GetProcessedDataAsync(cancellationToken))
|
||||
{
|
||||
yield return value;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
streamProcessor.OnException -= exceptionHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Channels;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Autogenerated = Dapr.Client.Autogen.Grpc.v1;
|
||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
|
||||
namespace Dapr.Cryptography.Encryption;
|
||||
|
||||
/// <summary>
|
||||
/// Provides the implementation to decrypt a stream of plaintext data with the Dapr runtime.
|
||||
/// </summary>
|
||||
internal sealed class DecryptionStreamProcessor : IDecryptionStreamProcessor, IDisposable
|
||||
{
|
||||
private bool disposed;
|
||||
private readonly Channel<ReadOnlyMemory<byte>> outputChannel = Channel.CreateUnbounded<ReadOnlyMemory<byte>>();
|
||||
|
||||
/// <summary>
|
||||
/// Surfaces any exceptions encountered while asynchronously processing the inbound and outbound streams.
|
||||
/// </summary>
|
||||
internal event EventHandler<Exception>? OnException;
|
||||
|
||||
/// <summary>
|
||||
/// Sends the provided bytes in chunks to the sidecar for the encryption operation.
|
||||
/// </summary>
|
||||
/// <param name="inputStream">The stream containing the bytes to decrypt.</param>
|
||||
/// <param name="call">The call to make to the sidecar to process the encryption operation.</param>
|
||||
/// <param name="streamingBlockSizeInBytes">The size, in bytes, of the streaming blocks.</param>
|
||||
/// <param name="options">The decryption options.</param>
|
||||
/// <param name="cancellationToken">Token used to cancel the ongoing request.</param>
|
||||
public async Task ProcessStreamAsync(
|
||||
Stream inputStream,
|
||||
AsyncDuplexStreamingCall<Autogenerated.DecryptRequest, Autogenerated.DecryptResponse> call,
|
||||
int streamingBlockSizeInBytes,
|
||||
Autogenerated.DecryptRequestOptions options,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
//Read from the input stream and write to the gRPC call
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var bufferedStream = new BufferedStream(inputStream, streamingBlockSizeInBytes);
|
||||
var buffer = new byte[streamingBlockSizeInBytes];
|
||||
int bytesRead;
|
||||
ulong sequenceNumber = 0;
|
||||
|
||||
while ((bytesRead = await bufferedStream.ReadAsync(buffer, cancellationToken)) > 0)
|
||||
{
|
||||
var request = new Autogenerated.DecryptRequest
|
||||
{
|
||||
Payload = new Autogenerated.StreamPayload
|
||||
{
|
||||
Data = ByteString.CopyFrom(buffer, 0, bytesRead), Seq = sequenceNumber
|
||||
}
|
||||
};
|
||||
|
||||
//Only include the options in the first message
|
||||
if (sequenceNumber == 0)
|
||||
{
|
||||
request.Options = options;
|
||||
}
|
||||
|
||||
await call.RequestStream.WriteAsync(request, cancellationToken);
|
||||
|
||||
//Increment the sequence number
|
||||
sequenceNumber++;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
// Expected cancellation exception
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnException?.Invoke(this, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await call.RequestStream.CompleteAsync();
|
||||
}
|
||||
}, cancellationToken);
|
||||
|
||||
//Start reading from the gRPC call and writing to the output channel
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await foreach (var response in call.ResponseStream.ReadAllAsync(cancellationToken))
|
||||
{
|
||||
await outputChannel.Writer.WriteAsync(response.Payload.Data.Memory, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnException?.Invoke(this, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
outputChannel.Writer.Complete();
|
||||
}
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the processed bytes from the operation from the sidecar and
|
||||
/// returns as an enumerable stream.
|
||||
/// </summary>
|
||||
public async IAsyncEnumerable<ReadOnlyMemory<byte>> GetProcessedDataAsync([EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
await foreach (var data in outputChannel.Reader.ReadAllAsync(cancellationToken))
|
||||
{
|
||||
yield return data;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
outputChannel.Writer.TryComplete();
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Channels;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Autogenerated = Dapr.Client.Autogen.Grpc.v1;
|
||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
|
||||
namespace Dapr.Cryptography.Encryption;
|
||||
|
||||
/// <summary>
|
||||
/// Provides the implementation to encrypt a stream of plaintext data with the Dapr runtime.
|
||||
/// </summary>
|
||||
internal sealed class EncryptionStreamProcessor : IEncryptionStreamProcessor, IDisposable
|
||||
{
|
||||
private bool disposed;
|
||||
private readonly Channel<ReadOnlyMemory<byte>> outputChannel = Channel.CreateUnbounded<ReadOnlyMemory<byte>>();
|
||||
|
||||
/// <summary>
|
||||
/// Surfaces any exceptions encountered while asynchronously processing the inbound and outbound streams.
|
||||
/// </summary>
|
||||
internal event EventHandler<Exception>? OnException;
|
||||
|
||||
/// <summary>
|
||||
/// Sends the provided bytes in chunks to the sidecar for the encryption operation.
|
||||
/// </summary>
|
||||
/// <param name="inputStream">The stream containing the bytes to encrypt.</param>
|
||||
/// <param name="call">The call to make to the sidecar to process the encryption operation.</param>
|
||||
/// <param name="options">The encryption options.</param>
|
||||
/// <param name="streamingBlockSizeInBytes">The size, in bytes, of the streaming blocks.</param>
|
||||
/// <param name="cancellationToken">Token used to cancel the ongoing request.</param>
|
||||
public async Task ProcessStreamAsync(
|
||||
Stream inputStream,
|
||||
AsyncDuplexStreamingCall<Autogenerated.EncryptRequest, Autogenerated.EncryptResponse> call,
|
||||
Autogenerated.EncryptRequestOptions options,
|
||||
int streamingBlockSizeInBytes,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
//Read from the input stream and write to the gRPC call
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var bufferedStream = new BufferedStream(inputStream, streamingBlockSizeInBytes);
|
||||
var buffer = new byte[streamingBlockSizeInBytes];
|
||||
int bytesRead;
|
||||
ulong sequenceNumber = 0;
|
||||
|
||||
while ((bytesRead = await bufferedStream.ReadAsync(buffer, cancellationToken)) > 0)
|
||||
{
|
||||
var request = new Autogenerated.EncryptRequest
|
||||
{
|
||||
Payload = new Autogenerated.StreamPayload
|
||||
{
|
||||
Data = ByteString.CopyFrom(buffer, 0, bytesRead), Seq = sequenceNumber
|
||||
}
|
||||
};
|
||||
|
||||
//Only include the options in the first message
|
||||
if (sequenceNumber == 0)
|
||||
{
|
||||
request.Options = options;
|
||||
}
|
||||
|
||||
await call.RequestStream.WriteAsync(request, cancellationToken);
|
||||
|
||||
//Increment the sequence number
|
||||
sequenceNumber++;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
// Expected cancellation exception
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnException?.Invoke(this, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await call.RequestStream.CompleteAsync();
|
||||
}
|
||||
}, cancellationToken);
|
||||
|
||||
//Start reading from the gRPC call and writing to the output channel
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await foreach (var response in call.ResponseStream.ReadAllAsync(cancellationToken))
|
||||
{
|
||||
await outputChannel.Writer.WriteAsync(response.Payload.Data.Memory, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnException?.Invoke(this, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
outputChannel.Writer.Complete();
|
||||
}
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the processed bytes from the operation from the sidecar and
|
||||
/// returns as an enumerable stream.
|
||||
/// </summary>
|
||||
public async IAsyncEnumerable<ReadOnlyMemory<byte>> GetProcessedDataAsync([EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
await foreach (var data in outputChannel.Reader.ReadAllAsync(cancellationToken))
|
||||
{
|
||||
yield return data;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
outputChannel.Writer.TryComplete();
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Dapr.Cryptography.Encryption.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Used by the fluent registration builder to configure a Dapr crypto client.
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
public sealed class DaprCryptographyBuilder(IServiceCollection services) : IDaprCryptographyBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// The registered services on the builder.
|
||||
/// </summary>
|
||||
public IServiceCollection Services { get; } = services;
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using Dapr.Common.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Dapr.Cryptography.Encryption.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Contains extension methods for using Dapr cryptography with dependency injection.
|
||||
/// </summary>
|
||||
public static class DaprCryptographyServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds Dapr encryption/decryption support to the service collection.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
|
||||
/// <param name="configure">Optionally allows greater configuration of the <see cref="DaprEncryptionClient"/> using injected services.</param>
|
||||
/// <param name="lifetime">The lifetime of the registered services.</param>
|
||||
/// <returns></returns>
|
||||
public static IDaprCryptographyBuilder AddDaprEncryptionClient(
|
||||
this IServiceCollection services,
|
||||
Action<IServiceProvider, DaprEncryptionClientBuilder>? configure = null,
|
||||
ServiceLifetime lifetime = ServiceLifetime.Singleton)
|
||||
{
|
||||
services.AddTransient<IDecryptionStreamProcessor, DecryptionStreamProcessor>();
|
||||
services.AddTransient<IEncryptionStreamProcessor, EncryptionStreamProcessor>();
|
||||
return services
|
||||
.AddDaprClient<DaprEncryptionClient, DaprEncryptionGrpcClient, DaprCryptographyBuilder,
|
||||
DaprEncryptionClientBuilder>(configure, lifetime);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
namespace Dapr.Cryptography.Encryption;
|
||||
|
||||
/// <summary>
|
||||
/// Provides a Dapr client specifically for encryption and decryption operations using Dapr.
|
||||
/// </summary>
|
||||
public interface IDaprEncryptionBuilder : IDaprCryptographyBuilder;
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using Dapr.Common;
|
||||
using Dapr.Cryptography.Encryption.Models;
|
||||
|
||||
namespace Dapr.Cryptography.Encryption;
|
||||
|
||||
/// <summary>
|
||||
/// Provides the implementation shape for the Dapr encryption client.
|
||||
/// </summary>
|
||||
public interface IDaprEncryptionClient : IDaprClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Encrypts an array of bytes using the Dapr Cryptography encryption functionality.
|
||||
/// </summary>
|
||||
/// <param name="vaultResourceName">The name of the vault resource used by the operation.</param>
|
||||
/// <param name="plaintextBytes">The bytes of the plaintext value to encrypt.</param>
|
||||
/// <param name="keyName">The name of the key to use from the Vault for the encryption operation.</param>
|
||||
/// <param name="encryptionOptions">Options informing how the encryption operation should be configured.</param>
|
||||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
|
||||
/// <returns>An array of encrypted bytes.</returns>
|
||||
[Obsolete("The API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")]
|
||||
public Task<ReadOnlyMemory<byte>> EncryptAsync(string vaultResourceName,
|
||||
ReadOnlyMemory<byte> plaintextBytes, string keyName, EncryptionOptions encryptionOptions,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Encrypts a stream using the Dapr Cryptography encryption functionality.
|
||||
/// </summary>
|
||||
/// <param name="vaultResourceName">The name of the vault resource used by the operation.</param>
|
||||
/// <param name="plaintextStream">The stream containing the bytes of the plaintext value to encrypt.</param>
|
||||
/// <param name="keyName">The name of the key to use from the Vault for the encryption operation.</param>
|
||||
/// <param name="encryptionOptions">Options informing how the encryption operation should be configured.</param>
|
||||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
|
||||
/// <returns>An array of encrypted bytes.</returns>
|
||||
[Obsolete("The API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")]
|
||||
public IAsyncEnumerable<ReadOnlyMemory<byte>> EncryptAsync(string vaultResourceName, Stream plaintextStream, string keyName,
|
||||
EncryptionOptions encryptionOptions, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Decrypts the specified ciphertext bytes using the Dapr Cryptography encryption functionality.
|
||||
/// </summary>
|
||||
/// <param name="vaultResourceName">The name of the vault resource used by the operation.</param>
|
||||
/// <param name="ciphertextBytes">The bytes of the ciphertext value to decrypt.</param>
|
||||
/// <param name="keyName">The name of the key to use from the Vault for the decryption operation.</param>
|
||||
/// <param name="options">Options informing how the decryption operation should be configured.</param>
|
||||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
|
||||
/// <returns>An array of decrypted bytes.</returns>
|
||||
[Obsolete("The API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")]
|
||||
public Task<ReadOnlyMemory<byte>> DecryptAsync(string vaultResourceName, ReadOnlyMemory<byte> ciphertextBytes, string keyName, DecryptionOptions? options = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Decrypts the specified stream of ciphertext using the Dapr Cryptography encryption functionality.
|
||||
/// </summary>
|
||||
/// <param name="vaultResourceName">The name of the vault resource used by the operation.</param>
|
||||
/// <param name="ciphertextStream">The stream containing the bytes of the ciphertext value to decrypt.</param>
|
||||
/// <param name="keyName">The name of the key to use from the Vault for the decryption operation.</param>
|
||||
/// <param name="options">Options informing how the decryption operation should be configured.</param>
|
||||
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
|
||||
/// <returns>An asynchronously enumerable array of decrypted bytes.</returns>
|
||||
[Obsolete(
|
||||
"The API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")]
|
||||
public IAsyncEnumerable<ReadOnlyMemory<byte>> DecryptAsync(string vaultResourceName, Stream ciphertextStream,
|
||||
string keyName, DecryptionOptions? options = null, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using Grpc.Core;
|
||||
|
||||
namespace Dapr.Cryptography.Encryption;
|
||||
|
||||
internal interface IDecryptionStreamProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// Sends the provided bytes in chunks to the sidecar for the encryption operation.
|
||||
/// </summary>
|
||||
/// <param name="inputStream">The stream containing the bytes to decrypt.</param>
|
||||
/// <param name="call">The call to make to the sidecar to process the encryption operation.</param>
|
||||
/// <param name="streamingBlockSizeInBytes">The size, in bytes, of the streaming blocks.</param>
|
||||
/// <param name="options">The decryption options.</param>
|
||||
/// <param name="cancellationToken">Token used to cancel the ongoing request.</param>
|
||||
Task ProcessStreamAsync(
|
||||
Stream inputStream,
|
||||
AsyncDuplexStreamingCall<Client.Autogen.Grpc.v1.DecryptRequest, Client.Autogen.Grpc.v1.DecryptResponse> call,
|
||||
int streamingBlockSizeInBytes,
|
||||
Client.Autogen.Grpc.v1.DecryptRequestOptions options,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the processed bytes from the operation from the sidecar and
|
||||
/// returns as an enumerable stream.
|
||||
/// </summary>
|
||||
IAsyncEnumerable<ReadOnlyMemory<byte>> GetProcessedDataAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using Grpc.Core;
|
||||
|
||||
namespace Dapr.Cryptography.Encryption;
|
||||
|
||||
internal interface IEncryptionStreamProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// Sends the provided bytes in chunks to the sidecar for the encryption operation.
|
||||
/// </summary>
|
||||
/// <param name="inputStream">The stream containing the bytes to encrypt.</param>
|
||||
/// <param name="call">The call to make to the sidecar to process the encryption operation.</param>
|
||||
/// <param name="options">The encryption options.</param>
|
||||
/// <param name="streamingBlockSizeInBytes">The size, in bytes, of the streaming blocks.</param>
|
||||
/// <param name="cancellationToken">Token used to cancel the ongoing request.</param>
|
||||
Task ProcessStreamAsync(
|
||||
Stream inputStream,
|
||||
AsyncDuplexStreamingCall<Client.Autogen.Grpc.v1.EncryptRequest, Client.Autogen.Grpc.v1.EncryptResponse> call,
|
||||
Client.Autogen.Grpc.v1.EncryptRequestOptions options,
|
||||
int streamingBlockSizeInBytes,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the processed bytes from the operation from the sidecar and
|
||||
/// returns as an enumerable stream.
|
||||
/// </summary>
|
||||
IAsyncEnumerable<ReadOnlyMemory<byte>> GetProcessedDataAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Dapr.Cryptography.Encryption.Models;
|
||||
|
||||
/// <summary>
|
||||
/// The cipher used for data encryption operations.
|
||||
/// </summary>
|
||||
public enum DataEncryptionCipher
|
||||
{
|
||||
/// <summary>
|
||||
/// The default data encryption cipher used, this represents AES GCM.
|
||||
/// </summary>
|
||||
[EnumMember(Value = "aes-gcm")]
|
||||
AesGcm,
|
||||
/// <summary>
|
||||
/// Represents the ChaCha20-Poly1305 data encryption cipher.
|
||||
/// </summary>
|
||||
[EnumMember(Value = "chacha20-poly1305")]
|
||||
ChaCha20Poly1305
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
namespace Dapr.Cryptography.Encryption.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A collection of options used to configure how decryption cryptographic operations are performed.
|
||||
/// </summary>
|
||||
public sealed class DecryptionOptions
|
||||
{
|
||||
private int streamingBlockSizeInBytes = 4 * 1024; // 4KB
|
||||
/// <summary>
|
||||
/// The size of the block in bytes used to send data to the sidecar for cryptography operations.
|
||||
/// </summary>
|
||||
public int StreamingBlockSizeInBytes
|
||||
{
|
||||
get => streamingBlockSizeInBytes;
|
||||
set
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(value);
|
||||
streamingBlockSizeInBytes = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
namespace Dapr.Cryptography.Encryption.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A collection of options used to configure how encryption cryptographic operations are performed.
|
||||
/// </summary>
|
||||
public sealed class EncryptionOptions(KeyWrapAlgorithm keyWrapAlgorithm)
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the algorithm used to wrap the encryption key.
|
||||
/// </summary>
|
||||
public KeyWrapAlgorithm KeyWrapAlgorithm { get; set; } = keyWrapAlgorithm;
|
||||
|
||||
private int streamingBlockSizeInBytes = 4 * 1024; // 4 KB
|
||||
/// <summary>
|
||||
/// The size of the block in bytes used to send data to the sidecar for cryptography operations.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This defaults to 4KB and generally should not exceed 64KB.
|
||||
/// </remarks>
|
||||
public int StreamingBlockSizeInBytes
|
||||
{
|
||||
get => streamingBlockSizeInBytes;
|
||||
set
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(value);
|
||||
streamingBlockSizeInBytes = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The optional name (and optionally a version) of the key specified to use during decryption.
|
||||
/// </summary>
|
||||
public string? DecryptionKeyName { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the cipher to use for the encryption operation.
|
||||
/// </summary>
|
||||
public DataEncryptionCipher EncryptionCipher { get; set; } = DataEncryptionCipher.AesGcm;
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Dapr.Cryptography.Encryption.Models;
|
||||
|
||||
/// <summary>
|
||||
/// The algorithm used for key wrapping cryptographic operations.
|
||||
/// </summary>
|
||||
public enum KeyWrapAlgorithm
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the AES key wrap algorithm.
|
||||
/// </summary>
|
||||
[EnumMember(Value="A256KW")]
|
||||
Aes,
|
||||
/// <summary>
|
||||
/// An alias for the AES key wrap algorithm.
|
||||
/// </summary>
|
||||
[EnumMember(Value="A256KW")]
|
||||
A256kw,
|
||||
/// <summary>
|
||||
/// Represents the AES 128 CBC key wrap algorithm.
|
||||
/// </summary>
|
||||
[EnumMember(Value="A128CBC")]
|
||||
A128cbc,
|
||||
/// <summary>
|
||||
/// Represents the AES 192 CBC key wrap algorithm.
|
||||
/// </summary>
|
||||
[EnumMember(Value="A192CBC")]
|
||||
A192cbc,
|
||||
/// <summary>
|
||||
/// Represents the AES 256 CBC key wrap algorithm.
|
||||
/// </summary>
|
||||
[EnumMember(Value="A256CBC")]
|
||||
A256cbc,
|
||||
/// <summary>
|
||||
/// Represents the RSA key wrap algorithm.
|
||||
/// </summary>
|
||||
[EnumMember(Value= "RSA-OAEP-256")]
|
||||
Rsa,
|
||||
/// <summary>
|
||||
/// An alias for the RSA key wrap algorithm.
|
||||
/// </summary>
|
||||
[EnumMember(Value= "RSA-OAEP-256")]
|
||||
RsaOaep256 //Alias for RSA
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Dapr.Cryptography.Extensions;
|
||||
|
||||
internal static class ReadOnlyMemoryExtensions
|
||||
{
|
||||
public static MemoryStream CreateMemoryStream(this ReadOnlyMemory<byte> memory, bool isReadOnly)
|
||||
{
|
||||
if (memory.IsEmpty)
|
||||
{
|
||||
return new MemoryStream([], !isReadOnly);
|
||||
}
|
||||
|
||||
if (MemoryMarshal.TryGetArray(memory, out ArraySegment<byte> segment) && segment.Array is not null)
|
||||
{
|
||||
return new MemoryStream(segment.Array, segment.Offset, segment.Count, !isReadOnly);
|
||||
}
|
||||
|
||||
throw new ArgumentException("Unable to create MemoryStream from provided memory value", nameof(memory));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using Dapr.Common;
|
||||
|
||||
namespace Dapr.Cryptography;
|
||||
|
||||
/// <summary>
|
||||
/// Provides a root builder for the Dapr cryptography operations facilitating a new fluent-style registration that looks
|
||||
/// ahead to additional Dapr capabilities in this space.
|
||||
/// </summary>
|
||||
public interface IDaprCryptographyBuilder : IDaprServiceBuilder;
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.msbuild">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk"/>
|
||||
<PackageReference Include="moq" />
|
||||
<PackageReference Include="xunit"/>
|
||||
<PackageReference Include="xunit.extensibility.core" />
|
||||
<PackageReference Include="xunit.runner.visualstudio">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Dapr.Cryptography\Dapr.Cryptography.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
using Dapr.Cryptography.Encryption.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Dapr.Cryptography.Test.Encryption.Extensions;
|
||||
|
||||
public class DaprCryptographyBuilderTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_InitializesServiceProperty()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
var builder = new DaprCryptographyBuilder(services);
|
||||
|
||||
Assert.NotNull(builder.Services);
|
||||
Assert.Equal(services, builder.Services);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServicesProperty_ReturnsRegisteredServices()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton<object>();
|
||||
|
||||
var builder = new DaprCryptographyBuilder(services);
|
||||
|
||||
Assert.NotNull(builder.Services);
|
||||
Assert.Single(builder.Services);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Dapr.Cryptography.Encryption;
|
||||
using Dapr.Cryptography.Encryption.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Dapr.Cryptography.Test.Encryption.Extensions;
|
||||
|
||||
public class DaprCryptographyServiceCollectionExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void AddDaprEncryptionClient_RegistersServicesWithSingletonLifetime()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
var builder = services.AddDaprEncryptionClient();
|
||||
var servicesProvider = services.BuildServiceProvider();
|
||||
var daprClient = servicesProvider.GetService<DaprEncryptionClient>();
|
||||
|
||||
Assert.NotNull(builder);
|
||||
Assert.NotNull(daprClient);
|
||||
Assert.Equal(ServiceLifetime.Singleton, services.First(sd => sd.ServiceType == typeof(DaprEncryptionClient)).Lifetime);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddDaprEncryptionClient_RegistersServicesWithScopedLifetime()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
var builder = services.AddDaprEncryptionClient(lifetime: ServiceLifetime.Scoped);
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
var daprClient = serviceProvider.GetService<DaprEncryptionClient>();
|
||||
|
||||
Assert.NotNull(builder);
|
||||
Assert.NotNull(daprClient);
|
||||
Assert.Equal(ServiceLifetime.Scoped, services.First(sd => sd.ServiceType == typeof(DaprEncryptionClient)).Lifetime);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddDaprEncryptionClient_RegistersServicesWithTransientLifetime()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
var builder = services.AddDaprEncryptionClient(lifetime: ServiceLifetime.Transient);
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
var daprClient = serviceProvider.GetService<DaprEncryptionClient>();
|
||||
|
||||
Assert.NotNull(builder);
|
||||
Assert.NotNull(daprClient);
|
||||
Assert.Equal(ServiceLifetime.Transient, services.First(sd => sd.ServiceType == typeof(DaprEncryptionClient)).Lifetime);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddDaprEncryptionClient_WithConfigureAction_ExecutesConfiguation()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
var configureCalled = false;
|
||||
|
||||
Action<IServiceProvider, DaprEncryptionClientBuilder> configure = (sp, builder) => configureCalled = true;
|
||||
|
||||
var builder = services.AddDaprEncryptionClient(configure);
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
var daprClient = serviceProvider.GetService<DaprEncryptionClient>();
|
||||
|
||||
Assert.NotNull(builder);
|
||||
Assert.NotNull(daprClient);
|
||||
Assert.True(configureCalled);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using Dapr.Cryptography.Encryption.Models;
|
||||
|
||||
namespace Dapr.Cryptography.Test.Encryption.Models;
|
||||
|
||||
public class DecryptionOptionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void DefaultStreamingBlockSizeInBytes_Is4KB()
|
||||
{
|
||||
var options = new DecryptionOptions();
|
||||
var defaultBlockSize = options.StreamingBlockSizeInBytes;
|
||||
Assert.Equal(4 * 1024, defaultBlockSize);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1024)]
|
||||
[InlineData(2048)]
|
||||
[InlineData(8192)]
|
||||
public void StreamingBlockSizeInBytes_SetValidValue_UpdatesBlockSize(int newBlockSize)
|
||||
{
|
||||
var options = new DecryptionOptions();
|
||||
options.StreamingBlockSizeInBytes = newBlockSize;
|
||||
Assert.Equal(newBlockSize, options.StreamingBlockSizeInBytes);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(-1024)]
|
||||
public void StreamingBlockSizeInBytes_SetInvalidValue_ThrowsArgumentOutOfRangeException(int invalidBlockSize)
|
||||
{
|
||||
var options = new DecryptionOptions();
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => options.StreamingBlockSizeInBytes = invalidBlockSize);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using Dapr.Cryptography.Encryption.Models;
|
||||
|
||||
namespace Dapr.Cryptography.Test.Encryption.Models;
|
||||
|
||||
public class EncryptionOptionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_InitializesKeyWrapAlgorithm()
|
||||
{
|
||||
var keyWrapAlgorithm = KeyWrapAlgorithm.RsaOaep256;
|
||||
var options = new EncryptionOptions(keyWrapAlgorithm);
|
||||
Assert.Equal(keyWrapAlgorithm, options.KeyWrapAlgorithm);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DefaultStreamingBlockSizeInBytes_Is4Kb()
|
||||
{
|
||||
var options = new EncryptionOptions(KeyWrapAlgorithm.A256kw);
|
||||
var defaultBlockSize = options.StreamingBlockSizeInBytes;
|
||||
Assert.Equal(4 * 1024, defaultBlockSize);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1024)]
|
||||
[InlineData(2048)]
|
||||
[InlineData(4092)]
|
||||
public void StreamingBlockSizeInBytes_SetValidValue_UpdatesBlockSize(int newBlockSize)
|
||||
{
|
||||
var options = new EncryptionOptions(KeyWrapAlgorithm.A192cbc);
|
||||
options.StreamingBlockSizeInBytes = newBlockSize;
|
||||
Assert.Equal(newBlockSize, options.StreamingBlockSizeInBytes);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(-1024)]
|
||||
public void StreamingBlockSizeInBytes_SetInvalidValue_ThrowsArgumentOutOfRangeException(int invalidBlockSize)
|
||||
{
|
||||
var options = new EncryptionOptions(KeyWrapAlgorithm.Rsa);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => options.StreamingBlockSizeInBytes = invalidBlockSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DefaultDecryptionKeyName_IsNull()
|
||||
{
|
||||
var options = new EncryptionOptions(KeyWrapAlgorithm.A256cbc);
|
||||
string? defaultKeyName = options.DecryptionKeyName;
|
||||
Assert.Null(defaultKeyName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DefaultEncryptionCipher_IsAes()
|
||||
{
|
||||
var options = new EncryptionOptions(KeyWrapAlgorithm.Aes);
|
||||
var defaultCipher = options.EncryptionCipher;
|
||||
Assert.Equal(DataEncryptionCipher.AesGcm, defaultCipher);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2025 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using Dapr.Cryptography.Extensions;
|
||||
|
||||
namespace Dapr.Cryptography.Test.Extensions;
|
||||
|
||||
public class ReadOnlyMemoryExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void CreateMemoryStream_EmptyMemory_ReturnsEmptyMemoryStream()
|
||||
{
|
||||
var emptyMemory = ReadOnlyMemory<byte>.Empty;
|
||||
var result = emptyMemory.CreateMemoryStream(isReadOnly: true);
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(0, result.Length);
|
||||
Assert.True(result.CanRead);
|
||||
Assert.False(result.CanWrite);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateMemoryStream_NonEmptyMemory_ReturnsMemoryStream()
|
||||
{
|
||||
byte[] data = { 1, 2, 3, 4, 5 };
|
||||
var memory = new ReadOnlyMemory<byte>(data);
|
||||
|
||||
var result = memory.CreateMemoryStream(isReadOnly: true);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(data.Length, result.Length);
|
||||
Assert.True(result.CanRead);
|
||||
Assert.False(result.CanWrite);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateMemoryStream_NonEmptyMemory_ReturnsWriteableMemoryStream()
|
||||
{
|
||||
byte[] data = { 1, 2, 3, 4, 5 };
|
||||
var memory = new ReadOnlyMemory<byte>(data);
|
||||
|
||||
var result = memory.CreateMemoryStream(isReadOnly: false);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(data.Length, result.Length);
|
||||
Assert.True(result.CanRead);
|
||||
Assert.True(result.CanWrite);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Dapr.Actors\Dapr.Actors.csproj" />
|
||||
<ProjectReference Include="..\..\src\Dapr.Cryptography\Dapr.Cryptography.csproj" />
|
||||
<ProjectReference Include="..\..\src\Dapr.Workflow\Dapr.Workflow.csproj" />
|
||||
<ProjectReference Include="..\..\src\Dapr.Extensions.Configuration\Dapr.Extensions.Configuration.csproj" />
|
||||
<ProjectReference Include="..\Dapr.E2E.Test.Actors\Dapr.E2E.Test.Actors.csproj" />
|
||||
|
|
@ -24,4 +25,10 @@
|
|||
<ItemGroup>
|
||||
<Protobuf Include="../Dapr.E2E.Test.App.Grpc/Proto/message.proto" GrpcServices="Client" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="keys\rsa-private-key.pem" />
|
||||
<Content Include="keys\rsa-private-key.pem">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQC0URLpxZCqDv7S
|
||||
WfROh2Kei4VCEayNu/TK3NaD/QlIpip1rrsPKgTfTOZoRmkmG0Qj59srEJi2GEhL
|
||||
xpjvRQpA/C/OS+KELU8AeGrqHw7uN/a99NkoAr+zYDCyY9yckPeC5wGxc0/Q6HQT
|
||||
mWp+YcpR9wFO0PmTVlObssibagjjRNX7z/ZosecOOqjnAqlnYoHMavvoCD5fxM7y
|
||||
cm7so0JWooXwVaZKgehBEBg1W5F0q5e9ssAQk3lY6IUd5sOskiylTNf/+3r1JU0j
|
||||
YM8ik3a1/dyDALVXpLSfz7FM9VEj4QjiPF4UuXeBHPDFFiKWbiKfbjqvZ2Sz7Gl7
|
||||
c5rTk1Fozpr70E/wihrrv22Mxs0sEPdtemQgHXroQfRW8K4FhI0WHs7tR2gVxLHu
|
||||
OAU9LzCngz4yITh1eixVDmm/B5ZtNVrTQmaY84vGqhrFp+asyFNiXbhUAcT7D/q6
|
||||
w/c4aQ635ntCFSPYpWvhKqrqVDsoanD/5AWfc3+6Ek2/GVMyEQq+9tnCMM10EVSX
|
||||
8PsoAWHESDFude5zkHzn7IKy8mh6lfheEbBI5zN9z7WGexyiBgljmyUHXx6Pd8Uc
|
||||
yxpLRm94kynkDXD9SapQLzXmz+D+X/OYeADMIDWlbdXiIb1+2Q62H1lo6n10KVP7
|
||||
oEr8BHvcMFY89kwK4lKscUupn8xkzwIDAQABAoICACDuu78Rc8Hzeivt/PZIuMTP
|
||||
I5f1BWhffy571fwGP2dS3edfcc+rs3cbIuvBjFvG2BOcuYUsg0+isLWSQIVWvTAw
|
||||
PwT1DBpq8gZad+Bpqr7sXrbD3NN3aQ64TzyNi5HW0jXIviDsOBQmGGkp+G67qol8
|
||||
zPLZrPNxbVS++u+Tlqr3fAOBMHZfo50QLp/+dvUoYx90HKz8sHOqTMewCb1Tdf6/
|
||||
sSm7YuMxxbr4VwuLvU2rN0wQtQ5x+NQ5p3JWHr/KdLf+CGc6xXK3jNaczEf62dAU
|
||||
XO1aOESZEtorQy0Ukuy0IXy8XMx5MS/WGs1MJSYHWHB43+QARL6tu3guHYVt3wyv
|
||||
W6YTglQsSKc6uuK4JTZOx1VYZjjnSdeY/xiUmZGYp4ZiC9p8b9NvXmZT2EwqhCVt
|
||||
4OTcX4lkwGAsKcoEdLHi0K5CbBfYJsRgVVheDjP0xUFjCJCYqfqo2rE5YMXMTeY7
|
||||
clYEOXKGxwuy1Iu8nKqtWAV5r/eSmXBdxBqEBW9oxJfnnwNPG+yOk0Qkd1vaRj00
|
||||
mdKCOjgB2fOuPX2JRZ2z41Cem3gqhH0NQGrx3APV4egGrYAMClasgtZkUeUOIgK5
|
||||
xLlC/6svuHNyKXAKFpOubEy1FM8jz7111eNHxHRDP3+vH3u4CfAD2Sl+VDZdg51i
|
||||
WmVpT+B/DrnlHVSP2/XNAoIBAQD7F49oSdveKuO/lAyqkE9iF61i09G0b0ouDGUI
|
||||
qx+pd5/8vUcqi4upCxz+3AqMPWZRIqOyo8EUP7f4rSJrXn8U2SwnFfi4k2jiqmEA
|
||||
Wr0b8z5P1q5MH6BtVDa0Sr1R8xI9s3UgIs4pUKgBoQu9+U4Du4NSucQFcea8nIVY
|
||||
lLCqQcRhz8bCJPCNuHay5c77kK3Te197KPMasNurTNMOJcPMG95CZLB8Clf4A+pw
|
||||
fixvA1/fE4mFo1L7Ymxoz5lFYVWOTY9hh50Kqz57wxw4laU4ii+MaJj+YHuNR83N
|
||||
cO6FztUYKMR8BPgtl3/POTHTofSg7eIOiUYwcfRr6jbMWlsDAoIBAQC311xiMpho
|
||||
Hvdcvp3/urrIp2QhdD05n6TnZOPkpnd9kwGku2RA+occDQOg/BzADVwJaR/aE97F
|
||||
jbfRlfBesTZlUec0EwjKIFbeYh+QS/RmjQe9zpPQWMo1M7y0fMWU+yXRUcNBpcuy
|
||||
R6KlphK0k4xFkIAdC3QHmJQ0XvOpqvrhFy3i/Prc5Wlg29FYBBTAF0WZCZ4uCG34
|
||||
D0eG0CNaf8w9g9ClbU6nGLBCMcgjEOPYfyrJaedM+jXennLDPG6ySytrGwnwLAQc
|
||||
Okx+SrIiNHUpQGKteT88Kdpgo3F4KUX/pm84uGdxrOpDS7L0T9/G4CbjzCe1nHeS
|
||||
fJJsw5JN+Z9FAoIBAGn5S6FsasudtnnI9n+WYKq564fmdn986QX+XTYHY1mXD4MQ
|
||||
L9UZCFzUP+yg2iLOVzyvLf/bdUYijnb6O6itPV2DO0tTzqG4NXBVEJOhuGbvhsET
|
||||
joS6ZG9AN8ZoNPc9a9l2wFxL1E9Dp2Ton5gSfIa+wXJMzRqvM/8u4Gi+eMGi+Et/
|
||||
8hdGl/B4hkCDFZS/P14el/HXGqONOWlXB0zVS4n9yRSkgogXpYEbxfqshfxkpDX2
|
||||
fPhWMlO++ppR5BKQPhfNTFKRdgpms/xwIJ0RK6ZtTBwqmUfjWMIMKCQpIcJ/xRhp
|
||||
PGRLhKNZaawAK7Nyi1jQjbQs497WeZ6CP5aIHBkCggEALHyl83FQ5ilQLJZH/6E9
|
||||
H9854MqTIkWajxAgAa2yzqVrSWS7XuoBFe2kSimX/3V8Jx7UQV57kwy3RbVl5FQ3
|
||||
2I7YRwawItFulAPkpXNr4gEQtYKuzEUgMX2ilX54BZQ804lYmaM4Rp0FI9arQh1O
|
||||
XWsZRW4HFut6Oa4cgptIeH22ce5L+nZdaL3oy8a5Cr7W7bChIXySt+tioKHvXC/+
|
||||
yYgDTnTECrVzuaD4UFv+9t3XCcRh34PQ010+YjZWhzifehyh7AeKuxX0er8ymgpd
|
||||
q6zT9CyZ+8IZATer9qruMG4jDfO5vI1eZwiDdpF5klOdtZQqq80ANmeEu2McHVhh
|
||||
jQKCAQBbohPxMb3QYdukGp8IsIF04GfnTgaDbRgl4KeUyzdBN3nzvCKK0HDluptR
|
||||
4Ua64JksGG24gsTBy6yuQoGRCG0LJe0Ty3TRRnvZ8MpADoNMObspMSC8n8kk6ps+
|
||||
SoG1U9t6HYlIgQagvTc7mTmCmwYX1zlCoZp24yz5pDkKxqoPFDtrGlXxeUgOhpDT
|
||||
Mzi+DNTz9sH9vod4ibQiOseUxITwQpXHTJVrtNfvva6xjlhq+GGCuKIUwkUKOvBC
|
||||
ds7SR9demn69aWCyzXqD1cTnmxtn6bNPukwowg7a07ieUyKftcJ1icOWQ/bdQkEf
|
||||
dV1dhNiQEnqs4vDBVn40dnTKSSG2
|
||||
-----END PRIVATE KEY-----
|
||||
Loading…
Reference in New Issue