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
|
||||
Console.WriteLine("Hello, World!");
|
||||
using System.Security.Cryptography;
|
||||
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>
|
||||
<OutputType>Exe</OutputType>
|
||||
|
|
@ -7,4 +7,8 @@
|
|||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapr.AspNetCore" Version="1.15.0-rc02" />
|
||||
</ItemGroup>
|
||||
|
||||
</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