diff --git a/LiftLog.Lib/Services/IEncryptionService.cs b/LiftLog.Lib/Services/IEncryptionService.cs
index 60471f07..7a1d0f8b 100644
--- a/LiftLog.Lib/Services/IEncryptionService.cs
+++ b/LiftLog.Lib/Services/IEncryptionService.cs
@@ -15,7 +15,7 @@ public interface IEncryptionService
///
///
///
- ValueTask DecryptAesCbcAndVerifyRsa256PssAsync(
+ Task DecryptAesCbcAndVerifyRsa256PssAsync(
AesEncryptedAndRsaSignedData data,
AesKey key,
RsaPublicKey publicKey
@@ -26,7 +26,7 @@ RsaPublicKey publicKey
/// CBC does not guarantee integrity, so we need to supply a signature with the data.
/// The signature is verified on decryption. Note the signature is also encrypted.
///
- public ValueTask SignRsa256PssAndEncryptAesCbcAsync(
+ public Task SignRsa256PssAndEncryptAesCbcAsync(
byte[] data,
AesKey key,
RsaPrivateKey rsaPrivateKey,
@@ -35,15 +35,9 @@ public ValueTask SignRsa256PssAndEncryptAesCbcAsyn
ValueTask GenerateAesKeyAsync();
- public ValueTask DecryptRsaOaepSha256Async(
- RsaEncryptedData data,
- RsaPrivateKey privateKey
- );
+ public Task DecryptRsaOaepSha256Async(RsaEncryptedData data, RsaPrivateKey privateKey);
- public ValueTask EncryptRsaOaepSha256Async(
- byte[] data,
- RsaPublicKey publicKey
- );
+ public Task EncryptRsaOaepSha256Async(byte[] data, RsaPublicKey publicKey);
public ValueTask GenerateRsaKeysAsync();
}
diff --git a/LiftLog.Lib/Services/OsEncryptionService.cs b/LiftLog.Lib/Services/OsEncryptionService.cs
index b705fca5..a915d69a 100644
--- a/LiftLog.Lib/Services/OsEncryptionService.cs
+++ b/LiftLog.Lib/Services/OsEncryptionService.cs
@@ -2,81 +2,100 @@
namespace LiftLog.Lib.Services;
+///
+/// This class provides encryption services using the OS's native crypto libraries.
+/// It will run all encryption operations on the thread pool.
+///
[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
public class OsEncryptionService : IEncryptionService
{
- public ValueTask DecryptAesCbcAndVerifyRsa256PssAsync(
+ public Task DecryptAesCbcAndVerifyRsa256PssAsync(
AesEncryptedAndRsaSignedData encryptedPayload,
AesKey key,
RsaPublicKey publicKey
)
{
- var aes = Aes.Create();
+ return Task.Run(() =>
+ {
+ var aes = Aes.Create();
- aes.IV = encryptedPayload.IV.Value;
- aes.Key = key.Value;
+ aes.IV = encryptedPayload.IV.Value;
+ aes.Key = key.Value;
- using var decryptor = aes.CreateDecryptor();
+ using var decryptor = aes.CreateDecryptor();
- var decrypted = decryptor.TransformFinalBlock(
- encryptedPayload.EncryptedPayload,
- 0,
- encryptedPayload.EncryptedPayload.Length
- );
+ var decrypted = decryptor.TransformFinalBlock(
+ encryptedPayload.EncryptedPayload,
+ 0,
+ encryptedPayload.EncryptedPayload.Length
+ );
- var data = decrypted[..^IEncryptionService.RsaHashLength];
- var signature = decrypted[^IEncryptionService.RsaHashLength..];
+ var data = decrypted[..^IEncryptionService.RsaHashLength];
+ var signature = decrypted[^IEncryptionService.RsaHashLength..];
- var rsa = RSA.Create();
- rsa.ImportSubjectPublicKeyInfo(publicKey.SpkiPublicKeyBytes, out _);
- var dataHash = SHA256.HashData(data);
+ var rsa = RSA.Create();
+ rsa.ImportSubjectPublicKeyInfo(publicKey.SpkiPublicKeyBytes, out _);
+ var dataHash = SHA256.HashData(data);
- if (!rsa.VerifyData(dataHash, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pss))
- {
- throw new SignatureMismatchException("Signature verification failed");
- }
+ if (
+ !rsa.VerifyData(
+ dataHash,
+ signature,
+ HashAlgorithmName.SHA256,
+ RSASignaturePadding.Pss
+ )
+ )
+ {
+ throw new SignatureMismatchException("Signature verification failed");
+ }
- return ValueTask.FromResult(data);
+ return data;
+ });
}
- public ValueTask SignRsa256PssAndEncryptAesCbcAsync(
+ public Task SignRsa256PssAndEncryptAesCbcAsync(
byte[] data,
AesKey key,
RsaPrivateKey rsaPrivateKey,
AesIV? iv = null
)
{
- var rsa = RSA.Create(2048);
+ return Task.Run(() =>
+ {
+ var rsa = RSA.Create(2048);
- rsa.ImportPkcs8PrivateKey(rsaPrivateKey.Pkcs8PrivateKeyBytes, out _);
+ rsa.ImportPkcs8PrivateKey(rsaPrivateKey.Pkcs8PrivateKeyBytes, out _);
- var dataHash = SHA256.HashData(data);
- var signature = rsa.SignData(dataHash, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
+ var dataHash = SHA256.HashData(data);
+ var signature = rsa.SignData(
+ dataHash,
+ HashAlgorithmName.SHA256,
+ RSASignaturePadding.Pss
+ );
- var dataAndSignature = new byte[data.Length + signature.Length];
- data.CopyTo(dataAndSignature, 0);
- signature.CopyTo(dataAndSignature, data.Length);
+ var dataAndSignature = new byte[data.Length + signature.Length];
+ data.CopyTo(dataAndSignature, 0);
+ signature.CopyTo(dataAndSignature, data.Length);
- var aes = Aes.Create();
+ var aes = Aes.Create();
- if (iv is not null)
- {
- aes.IV = iv.Value;
- }
- else
- {
- aes.GenerateIV();
- }
- aes.Key = key.Value;
+ if (iv is not null)
+ {
+ aes.IV = iv.Value;
+ }
+ else
+ {
+ aes.GenerateIV();
+ }
+ aes.Key = key.Value;
- using var encryptor = aes.CreateEncryptor();
+ using var encryptor = aes.CreateEncryptor();
- return ValueTask.FromResult(
- new AesEncryptedAndRsaSignedData(
+ return new AesEncryptedAndRsaSignedData(
encryptor.TransformFinalBlock(dataAndSignature, 0, dataAndSignature.Length),
new AesIV(iv?.Value ?? aes.IV)
- )
- );
+ );
+ });
}
public ValueTask GenerateAesKeyAsync()
@@ -88,46 +107,46 @@ public ValueTask GenerateAesKeyAsync()
return ValueTask.FromResult(new AesKey(aes.Key));
}
- public ValueTask EncryptRsaOaepSha256Async(
- byte[] data,
- RsaPublicKey publicKey
- )
+ public Task EncryptRsaOaepSha256Async(byte[] data, RsaPublicKey publicKey)
{
- var rsa = RSA.Create(2048);
-
- rsa.ImportSubjectPublicKeyInfo(publicKey.SpkiPublicKeyBytes, out _);
-
- // encrypt one chunk at a time, as RSA has a size limit of 122ish bytes
- var encryptedChunks = new byte[(data.Length / 122) + 1][];
- for (var i = 0; i < encryptedChunks.Length; i++)
+ return Task.Run(() =>
{
- encryptedChunks[i] = rsa.Encrypt(
- data[(i * 122)..Math.Min((i + 1) * 122, data.Length)],
- RSAEncryptionPadding.OaepSHA256
- );
- }
-
- return ValueTask.FromResult(new RsaEncryptedData(encryptedChunks));
+ var rsa = RSA.Create(2048);
+
+ rsa.ImportSubjectPublicKeyInfo(publicKey.SpkiPublicKeyBytes, out _);
+
+ // encrypt one chunk at a time, as RSA has a size limit of 122ish bytes
+ var encryptedChunks = new byte[(data.Length / 122) + 1][];
+ for (var i = 0; i < encryptedChunks.Length; i++)
+ {
+ encryptedChunks[i] = rsa.Encrypt(
+ data[(i * 122)..Math.Min((i + 1) * 122, data.Length)],
+ RSAEncryptionPadding.OaepSHA256
+ );
+ }
+
+ return new RsaEncryptedData(encryptedChunks);
+ });
}
- public ValueTask DecryptRsaOaepSha256Async(
- RsaEncryptedData data,
- RsaPrivateKey privateKey
- )
+ public Task DecryptRsaOaepSha256Async(RsaEncryptedData data, RsaPrivateKey privateKey)
{
- var rsa = RSA.Create();
+ return Task.Run(() =>
+ {
+ var rsa = RSA.Create();
- rsa.ImportPkcs8PrivateKey(privateKey.Pkcs8PrivateKeyBytes, out _);
+ rsa.ImportPkcs8PrivateKey(privateKey.Pkcs8PrivateKeyBytes, out _);
- // decrypt one chunk at a time
+ // decrypt one chunk at a time
- var decrypted = new byte[data.DataChunks.Length][];
- for (var i = 0; i < data.DataChunks.Length; i++)
- {
- decrypted[i] = rsa.Decrypt(data.DataChunks[i], RSAEncryptionPadding.OaepSHA256);
- }
+ var decrypted = new byte[data.DataChunks.Length][];
+ for (var i = 0; i < data.DataChunks.Length; i++)
+ {
+ decrypted[i] = rsa.Decrypt(data.DataChunks[i], RSAEncryptionPadding.OaepSHA256);
+ }
- return ValueTask.FromResult(decrypted.SelectMany(x => x).ToArray());
+ return decrypted.SelectMany(x => x).ToArray();
+ });
}
public ValueTask GenerateRsaKeysAsync()
diff --git a/LiftLog.Web/Services/JsEncryptionService.cs b/LiftLog.Web/Services/JsEncryptionService.cs
index c60badeb..1d9df8ea 100644
--- a/LiftLog.Web/Services/JsEncryptionService.cs
+++ b/LiftLog.Web/Services/JsEncryptionService.cs
@@ -7,34 +7,38 @@ namespace LiftLog.Web.Services;
// Dotnet AES-GCM implementation is not compatible with the JS implementation
public class JsEncryptionService(IJSRuntime jSRuntime) : IEncryptionService
{
- public ValueTask DecryptAesCbcAndVerifyRsa256PssAsync(
+ public Task DecryptAesCbcAndVerifyRsa256PssAsync(
AesEncryptedAndRsaSignedData data,
AesKey key,
RsaPublicKey publicKey
)
{
- return jSRuntime.InvokeAsync(
- "CryptoUtils.decryptAesCbcAndVerifyRsa256PssAsync",
- data,
- key,
- publicKey
- );
+ return jSRuntime
+ .InvokeAsync(
+ "CryptoUtils.decryptAesCbcAndVerifyRsa256PssAsync",
+ data,
+ key,
+ publicKey
+ )
+ .AsTask();
}
- public ValueTask SignRsa256PssAndEncryptAesCbcAsync(
+ public Task SignRsa256PssAndEncryptAesCbcAsync(
byte[] data,
AesKey key,
RsaPrivateKey rsaPrivateKey,
AesIV? iv = null
)
{
- return jSRuntime.InvokeAsync(
- "CryptoUtils.signRsa256PssAndEncryptAesCbcAsync",
- data,
- key,
- rsaPrivateKey,
- iv
- );
+ return jSRuntime
+ .InvokeAsync(
+ "CryptoUtils.signRsa256PssAndEncryptAesCbcAsync",
+ data,
+ key,
+ rsaPrivateKey,
+ iv
+ )
+ .AsTask();
}
public ValueTask GenerateAesKeyAsync()
@@ -42,28 +46,18 @@ public ValueTask GenerateAesKeyAsync()
return jSRuntime.InvokeAsync("CryptoUtils.generateAesKey");
}
- public ValueTask EncryptRsaOaepSha256Async(
- byte[] data,
- RsaPublicKey publicKey
- )
+ public Task EncryptRsaOaepSha256Async(byte[] data, RsaPublicKey publicKey)
{
- return jSRuntime.InvokeAsync(
- "CryptoUtils.encryptRsaOaepSha256Async",
- data,
- publicKey
- );
+ return jSRuntime
+ .InvokeAsync("CryptoUtils.encryptRsaOaepSha256Async", data, publicKey)
+ .AsTask();
}
- public ValueTask DecryptRsaOaepSha256Async(
- RsaEncryptedData data,
- RsaPrivateKey privateKey
- )
+ public Task DecryptRsaOaepSha256Async(RsaEncryptedData data, RsaPrivateKey privateKey)
{
- return jSRuntime.InvokeAsync(
- "CryptoUtils.decryptRsaOaepSha256Async",
- data,
- privateKey
- );
+ return jSRuntime
+ .InvokeAsync("CryptoUtils.decryptRsaOaepSha256Async", data, privateKey)
+ .AsTask();
}
public ValueTask GenerateRsaKeysAsync()