Skip to content

Commit

Permalink
Added overloads for encrypting/decrypting streams instead of just fix…
Browse files Browse the repository at this point in the history
…ed byte arrays. Added example demonstrating the same encrypting a file via a FileStream and decrypting from a MemoryStream.

Signed-off-by: Whit Waldo <whit.waldo@innovian.net>
  • Loading branch information
WhitWaldo committed Dec 23, 2023
1 parent b343e54 commit 3fbecef
Show file tree
Hide file tree
Showing 8 changed files with 292 additions and 13 deletions.
6 changes: 6 additions & 0 deletions examples/Client/Cryptography/Cryptography.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@
<ProjectReference Include="..\..\..\src\Dapr.Client\Dapr.Client.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="file.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// ------------------------------------------------------------------------
// 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 Dapr.Client;

namespace Cryptography.Examples
{
internal class EncryptDecryptFileStreamExample : Example
{
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();

const string componentName = "azurekeyvault"; // Change this to match the name of the component containing your vault
const string keyName = "myKey";

// The name of the file we're using as an example
const string fileName = "file.txt";

Console.WriteLine("Original file contents:");
foreach (var line in await File.ReadAllLinesAsync(fileName, cancellationToken))
{
Console.WriteLine(line);
}
Console.WriteLine();

//Encrypt the file
await using var encryptFs = new FileStream(fileName, FileMode.Open);
#pragma warning disable CS0618 // Type or member is obsolete
var encryptedBytesResult = await client.EncryptAsync(componentName, encryptFs, KeyWrapAlgorithm.Rsa, keyName,
DataEncryptionCipher.AesGcm, cancellationToken);
#pragma warning restore CS0618 // Type or member is obsolete
Console.WriteLine($"Encrypted bytes: '{Convert.ToBase64String(encryptedBytesResult)}'");
Console.WriteLine();

//Decrypt the temp file from a memory stream this time instead of a file
await using var ms = new MemoryStream(encryptedBytesResult);
#pragma warning disable CS0618 // Type or member is obsolete
var decryptedBytes = await client.DecryptAsync(componentName, ms, keyName, cancellationToken);
#pragma warning restore CS0618 // Type or member is obsolete

Console.WriteLine("Decrypted value:");
await using var decryptedMs = new MemoryStream(decryptedBytes);
using var sr = new StreamReader(decryptedMs);
Console.WriteLine(await sr.ReadToEndAsync(cancellationToken));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

namespace Cryptography.Examples
{
internal class EncryptDecryptExample : Example
internal class EncryptDecryptStringExample : Example
{
public override string DisplayName => "Using Cryptography to encrypt and decrypt a string";

Expand Down
3 changes: 2 additions & 1 deletion examples/Client/Cryptography/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ class Program
{
private static readonly Example[] Examples = new Example[]
{
new EncryptDecryptExample()
new EncryptDecryptStringExample(),
new EncryptDecryptFileStreamExample()
};

static async Task<int> Main(string[] args)
Expand Down
4 changes: 2 additions & 2 deletions examples/Client/Cryptography/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ This example is implemented using the Azure Key Vault and will not work without
you have the `Key Vault Crypto Officer` role assigned to yourself as you'll need to in order to generate a new key in the instance. After selecting Keys
under the Objects header, click the `Generate/Import` button at the top of the instance panel.

Under options, select `Generate` and name your key. This example is pre-configured to assume a key name of 'mykey', but feel free to change this. The other default
options are fine for our purposes, so click Create at the bottom and if you've got the appropriate roles, it will show up in the list of Keys.
Under options, select `Generate` and name your key. This example is pre-configured to assume a key name of 'myKey', but feel free to change this (but also update the name in the example
you wish to run). The other default options are fine for our purposes, so click Create at the bottom and if you've got the appropriate roles, it will show up in the list of Keys.

Update your `./Components/azurekeyvault.yaml` file with the name of your Key Vault under `vaultName` where it currently reads "changeMe". This sample assumes authentication
via a service principal, so you might also need to set this up.
Expand Down
26 changes: 26 additions & 0 deletions examples/Client/Cryptography/file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# The Road Not Taken
## By Robert Lee Frost

Two roads diverged in a yellow wood,
And sorry I could not travel both
And be one traveler, long I stood
And looked down one as far as I could
To where it bent in the undergrowth;

Then took the other, as just as fair
And having perhaps the better claim,
Because it was grassy and wanted wear;
Though as for that, the passing there
Had worn them really about the same,

And both that morning equally lay
In leaves no step had trodden black
Oh, I kept the first for another day!
Yet knowing how way leads on to way,
I doubted if I should ever come back.

I shall be telling this with a sigh
Somewhere ages and ages hence:
Two roads diverged in a wood, and I,
I took the one less traveled by,
And that has made all the difference.
49 changes: 46 additions & 3 deletions src/Dapr.Client/DaprClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Dapr.Client.Autogen.Grpc.v1;
using Google.Protobuf;
using Grpc.Core;
using Grpc.Core.Interceptors;
Expand Down Expand Up @@ -973,18 +973,61 @@ public abstract Task<byte[]> EncryptAsync(string vaultResourceName, byte[] plain
KeyWrapAlgorithm algorithm, string keyName, string decryptionKeyName, DataEncryptionCipher dataEncryptionCipher = DataEncryptionCipher.AesGcm,
CancellationToken cancellationToken = default);

/// <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="plainTextStream">The stream containing the bytes of the plaintext value to encrypt.</param>
/// <param name="algorithm">The name of the algorithm used to wrap the encryption key.</param>
/// <param name="keyName">The name of the key to use from the Vault for the encryption operation.</param>
/// <param name="dataEncryptionCipher">The name of the cipher to use for the encryption operation.</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<byte[]> EncryptAsync(string vaultResourceName, Stream plainTextStream,
KeyWrapAlgorithm algorithm, string keyName, DataEncryptionCipher dataEncryptionCipher = DataEncryptionCipher.AesGcm,
CancellationToken cancellationToken = default);

/// <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="plainTextStream">The stream containing the bytes of the plaintext value to encrypt.</param>
/// <param name="algorithm">The name of the algorithm used to wrap the encryption key.</param>
/// <param name="keyName">The name of the key to use from the Vault for the encryption operation.</param>
/// <param name="decryptionKeyName">The name (and optionally version) of the decryption key to specify should be used.</param>
/// <param name="dataEncryptionCipher">The name of the cipher to use for the encryption operation.</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<byte[]> EncryptAsync(string vaultResourceName, Stream plainTextStream,
KeyWrapAlgorithm algorithm, string keyName, string decryptionKeyName, DataEncryptionCipher dataEncryptionCipher = DataEncryptionCipher.AesGcm,
CancellationToken cancellationToken = default);

/// <summary>
/// Decrypts the specified cipher text 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 byte of the cipher text value to decrypt.</param>
/// <param name="cipherTextBytes">The bytes of the cipher text value to decrypt.</param>
/// <param name="keyName">The name of the key to use from the Vault for the decryption operation.</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<byte[]> DecryptAsync(string vaultResourceName, byte[] cipherTextBytes, string keyName,
CancellationToken cancellationToken = default);


/// <summary>
/// Decrypts the specified cipher text bytes 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 cipher text value to decrypt.</param>
/// <param name="keyName">The name of the key to use from the Vault for the decryption operation.</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<byte[]> DecryptAsync(string vaultResourceName, Stream cipherTextStream, string keyName,
CancellationToken cancellationToken = default);

#endregion

#region Cryptography - Subtle API
Expand Down
Loading

0 comments on commit 3fbecef

Please sign in to comment.