mirror of https://github.com/dapr/quickstarts.git
Added application - building out readme
Signed-off-by: Whit Waldo <whit.waldo@innovian.net>
This commit is contained in:
parent
0727d1d041
commit
800db8452c
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Dapr cryptography
|
||||||
|
|
||||||
|
In this quickstart, you'll create a service that demonstrates
|
||||||
|
|
@ -1,2 +1,106 @@
|
||||||
// See https://aka.ms/new-console-template for more information
|
using System.Security.Cryptography;
|
||||||
Console.WriteLine("Hello, World!");
|
using cryptography;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
builder.Services.AddDaprClient();
|
||||||
|
builder.Services.TryAddSingleton<StringCryptographyOperations>();
|
||||||
|
builder.Services.TryAddSingleton<StreamCryptographyOperations>();
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));
|
||||||
|
var logger = app.Services.GetRequiredService<ILogger<Program>>();
|
||||||
|
|
||||||
|
//Encrypt a string value
|
||||||
|
var stringOps = app.Services.GetRequiredService<StringCryptographyOperations>();
|
||||||
|
const string plaintextValue = "P@assw0rd";
|
||||||
|
var encryptedBase64String = await stringOps.EncryptAsync(plaintextValue, cancellationTokenSource.Token);
|
||||||
|
var decryptedBase64String = await stringOps.DecryptAsync(encryptedBase64String, cancellationTokenSource.Token);
|
||||||
|
Log.LogStringEncryption(logger, plaintextValue, decryptedBase64String);
|
||||||
|
|
||||||
|
//Encrypt a file
|
||||||
|
var testFilePath = await FileGenerator.GenerateSmallTestFileAsync(cancellationTokenSource.Token);
|
||||||
|
var streamOps = app.Services.GetRequiredService<StreamCryptographyOperations>();
|
||||||
|
var encryptedFileBytes = await streamOps.EncryptAsync(testFilePath, cancellationTokenSource.Token);
|
||||||
|
|
||||||
|
using var encryptedMs = new MemoryStream(Convert.FromBase64String(encryptedFileBytes));
|
||||||
|
var decryptedFilePath = Path.GetTempFileName();
|
||||||
|
await streamOps.DecryptAsync(encryptedMs, decryptedFilePath, cancellationTokenSource.Token);
|
||||||
|
var areIdentical = await FileValidator.AreIdentical(testFilePath, decryptedFilePath);
|
||||||
|
Log.LogStreamEncryption(logger, testFilePath, decryptedFilePath, areIdentical);
|
||||||
|
|
||||||
|
//Clean up the created files
|
||||||
|
File.Delete(testFilePath);
|
||||||
|
File.Delete(decryptedFilePath);
|
||||||
|
|
||||||
|
static partial class Log
|
||||||
|
{
|
||||||
|
//It should go without saying that you should not log your plaintext values in production - this is for
|
||||||
|
//demonstration purposes only.
|
||||||
|
[LoggerMessage(LogLevel.Information, "Encrypted string from plaintext value '{plaintextValue}' and decrypted to '{decryptedValue}'")]
|
||||||
|
internal static partial void LogStringEncryption(ILogger logger, string plaintextValue, string decryptedValue);
|
||||||
|
|
||||||
|
[LoggerMessage(LogLevel.Information, "Encrypted from file stream '{plaintextFilePath}' and decrypted back from an in-memory stream to a file '{decryptedFilePath}' and the validation check returns '{areIdentical}'")]
|
||||||
|
internal static partial void LogStreamEncryption(ILogger logger, string plaintextFilePath, string decryptedFilePath, bool areIdentical);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Constants
|
||||||
|
{
|
||||||
|
public const string ComponentName = "localstorage";
|
||||||
|
public const string KeyName = "rsa-private-key.pem";
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FileGenerator
|
||||||
|
{
|
||||||
|
public static async Task<string> GenerateSmallTestFileAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var tempFilePath = Path.GetTempFileName();
|
||||||
|
await File.WriteAllTextAsync(tempFilePath, """
|
||||||
|
# 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.
|
||||||
|
""", cancellationToken);
|
||||||
|
|
||||||
|
return tempFilePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FileValidator
|
||||||
|
{
|
||||||
|
public static async Task<bool> AreIdentical(string path1, string path2)
|
||||||
|
{
|
||||||
|
await using var path1Reader = new FileStream(path1, FileMode.Open);
|
||||||
|
await using var path2Reader = new FileStream(path2, FileMode.Open);
|
||||||
|
|
||||||
|
using var md5 = MD5.Create();
|
||||||
|
var file1Hash = await md5.ComputeHashAsync(path1Reader);
|
||||||
|
var file2Hash = await md5.ComputeHashAsync(path2Reader);
|
||||||
|
|
||||||
|
return file1Hash.SequenceEqual(file2Hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
using System.Buffers;
|
||||||
|
using Dapr.Client;
|
||||||
|
|
||||||
|
namespace cryptography;
|
||||||
|
|
||||||
|
internal sealed partial class StreamCryptographyOperations(DaprClient daprClient, ILogger<StreamCryptographyOperations> logger)
|
||||||
|
{
|
||||||
|
public async Task<string> EncryptAsync(
|
||||||
|
string filePath,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await using var sourceFile = new FileStream(filePath, FileMode.Open);
|
||||||
|
var bufferedEncryptedBytes = new ArrayBufferWriter<byte>();
|
||||||
|
await foreach (var bytes in (await daprClient.EncryptAsync(Constants.ComponentName, sourceFile,
|
||||||
|
Constants.KeyName, new EncryptionOptions(KeyWrapAlgorithm.Rsa), cancellationToken))
|
||||||
|
.WithCancellation(cancellationToken))
|
||||||
|
{
|
||||||
|
bufferedEncryptedBytes.Write(bytes.Span);
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceFile.Close();
|
||||||
|
|
||||||
|
LogEncryptFile(logger, filePath, bufferedEncryptedBytes.WrittenMemory.Span.Length);
|
||||||
|
|
||||||
|
var base64String = Convert.ToBase64String(bufferedEncryptedBytes.WrittenMemory.Span);
|
||||||
|
return base64String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DecryptAsync(MemoryStream encryptedBytes, string decryptedFilePath, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await using var decryptedFile = new FileStream(decryptedFilePath, FileMode.Create);
|
||||||
|
await foreach (var bytes in (await daprClient.DecryptAsync(Constants.ComponentName, encryptedBytes,
|
||||||
|
Constants.KeyName, cancellationToken))
|
||||||
|
.WithCancellation(cancellationToken))
|
||||||
|
{
|
||||||
|
await decryptedFile.WriteAsync(bytes, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogDecryptFile(logger, decryptedFilePath);
|
||||||
|
decryptedFile.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
[LoggerMessage(LogLevel.Information, "Encrypted file '{filePath}' spanning {encryptedByteCount} bytes")]
|
||||||
|
static partial void LogEncryptFile(ILogger logger, string filePath, int encryptedByteCount);
|
||||||
|
|
||||||
|
[LoggerMessage(LogLevel.Information, "Decrypting in-memory bytes to file '{filePath}'")]
|
||||||
|
static partial void LogDecryptFile(ILogger logger, string filePath);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System.Text;
|
||||||
|
using Dapr.Client;
|
||||||
|
|
||||||
|
namespace cryptography;
|
||||||
|
|
||||||
|
internal sealed partial class StringCryptographyOperations(DaprClient daprClient, ILogger<StringCryptographyOperations> logger)
|
||||||
|
{
|
||||||
|
public async Task<string> EncryptAsync(string plaintextValue, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var plaintextBytes = Encoding.UTF8.GetBytes(plaintextValue);
|
||||||
|
var encryptedBytes = await daprClient.EncryptAsync(Constants.ComponentName, plaintextBytes, Constants.KeyName, new EncryptionOptions(KeyWrapAlgorithm.Rsa), cancellationToken);
|
||||||
|
LogEncryptionOperation(logger, Constants.KeyName, plaintextValue);
|
||||||
|
return Convert.ToBase64String(encryptedBytes.Span);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> DecryptAsync(string base64EncryptedValue, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var ciphertextBytes = Convert.FromBase64String(base64EncryptedValue);
|
||||||
|
var decryptedBytes =
|
||||||
|
await daprClient.DecryptAsync(Constants.ComponentName, ciphertextBytes, Constants.KeyName, cancellationToken);
|
||||||
|
var plaintextValue = Encoding.UTF8.GetString(decryptedBytes.Span);
|
||||||
|
LogDecryptionOperation(logger, Constants.KeyName, plaintextValue);
|
||||||
|
return plaintextValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[LoggerMessage(LogLevel.Information, "Encrypting string with key {keyName} with plaintext value '{plaintextValue}'")]
|
||||||
|
static partial void LogEncryptionOperation(ILogger logger, string keyName, string plaintextValue);
|
||||||
|
|
||||||
|
[LoggerMessage(LogLevel.Information, "Decrypted string with key {keyName} with plaintext value '{plaintextValue}'")]
|
||||||
|
static partial void LogDecryptionOperation(ILogger logger, string keyName, string plaintextValue);
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
|
|
@ -7,4 +7,8 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Dapr.AspNetCore" Version="1.15.0-rc02" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
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
|
||||||
|
dV1dhNiQEnqs4vDBVn40dnTKSSG2
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
include ../../../docker.mk
|
||||||
|
include ../../../validate.mk
|
||||||
Loading…
Reference in New Issue