Reworked encryption to use less heap allocated buffers for secrets.
Also some work on plugin system.
This commit is contained in:
parent
8782ef39c6
commit
054754f553
42 changed files with 1452 additions and 242 deletions
|
|
@ -2,6 +2,7 @@ using System.Buffers.Text;
|
|||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using IdentityShroud.Core.Model;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
|
||||
namespace IdentityShroud.Core;
|
||||
|
|
@ -40,49 +41,48 @@ public static class JwtSignatureGenerator
|
|||
|
||||
}
|
||||
|
||||
public static class JwtCreator
|
||||
public class JwtService(IJwtSignerFactory signerFactory)
|
||||
{
|
||||
|
||||
public static byte[] CreateEncodedJwt(ReadOnlySpan<byte> payloadUtf8, IJwtSignatureProvider signatureProvider)
|
||||
public byte[] CreateEncodedJwt(ReadOnlySpan<byte> payloadUtf8, JwtSigAlgName algName, DecryptedSigningKey key)
|
||||
{
|
||||
MemoryStream memStream = new();
|
||||
Utf8JsonWriter writer = new(memStream);
|
||||
WriteJwtHeader(writer, signatureProvider);
|
||||
writer.Flush();
|
||||
memStream.Seek(0, SeekOrigin.Begin);
|
||||
// LATER might be able to improve performance using ArrayPool
|
||||
|
||||
IJwtSigner signer = signerFactory.Create(algName);
|
||||
MemoryStream headerMemStream = new();
|
||||
Utf8JsonWriter headerWriter = new(headerMemStream);
|
||||
WriteJwtHeader(headerWriter, algName, key.Id.ToString());
|
||||
headerWriter.Flush();
|
||||
headerMemStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
int headerBase64Length = Base64Url.GetEncodedLength((int)memStream.Length);
|
||||
int headerBase64Length = Base64Url.GetEncodedLength((int)headerMemStream.Length);
|
||||
int payloadBase64Length = Base64Url.GetEncodedLength(payloadUtf8.Length);
|
||||
int signatureBase64Length = Base64Url.GetEncodedLength(signatureProvider.GetSignatureLength());
|
||||
int totalLength = headerBase64Length + 1 + payloadBase64Length + 1 + signatureBase64Length;
|
||||
|
||||
var completeJwt = new byte[totalLength];
|
||||
var jwtData = new byte[headerBase64Length + payloadBase64Length + 1];
|
||||
|
||||
//
|
||||
var byteArray = new byte[memStream.Length];
|
||||
memStream.ReadExactly(byteArray, 0, (int)memStream.Length);
|
||||
int written = Base64Url.EncodeToUtf8(byteArray, completeJwt);
|
||||
var byteArray = new byte[headerMemStream.Length];
|
||||
headerMemStream.ReadExactly(byteArray, 0, (int)headerMemStream.Length);
|
||||
int written = Base64Url.EncodeToUtf8(byteArray, jwtData);
|
||||
|
||||
if (written != headerBase64Length)
|
||||
throw new Exception("expected header length did not match bytes written");
|
||||
|
||||
completeJwt[headerBase64Length] = (byte)'.';
|
||||
jwtData[headerBase64Length] = (byte)'.';
|
||||
|
||||
written = Base64Url.EncodeToUtf8(payloadUtf8, completeJwt.AsSpan().Slice(headerBase64Length + 1, payloadBase64Length));
|
||||
written = Base64Url.EncodeToUtf8(payloadUtf8, jwtData.AsSpan().Slice(headerBase64Length + 1, payloadBase64Length));
|
||||
|
||||
if (written != payloadBase64Length)
|
||||
throw new Exception("expected payload length did not match bytes written");
|
||||
|
||||
completeJwt[headerBase64Length + 1 + payloadBase64Length] = (byte)'.';
|
||||
byte[] signature = signer.CalculateSignature(algName, key, jwtData.AsSpan());
|
||||
|
||||
int signatureBase64Length = Base64Url.GetEncodedLength(signature.Length);
|
||||
|
||||
Span<byte> signature = stackalloc byte[signatureProvider.GetSignatureLength()];
|
||||
signatureProvider.CalculateSignature(
|
||||
completeJwt.AsSpan().Slice(0, headerBase64Length + 1 + payloadBase64Length),
|
||||
signature);
|
||||
|
||||
written = Base64Url.EncodeToUtf8(signature, completeJwt.AsSpan()
|
||||
.Slice(headerBase64Length + 1 + payloadBase64Length + 1));
|
||||
var completeJwt = new byte[jwtData.Length + 1 + signatureBase64Length];
|
||||
Array.Copy(jwtData, completeJwt, jwtData.Length);
|
||||
completeJwt[jwtData.Length] = (byte)'.';
|
||||
|
||||
written = Base64Url.EncodeToUtf8(signature, completeJwt.AsSpan().Slice(jwtData.Length + 1, signatureBase64Length));
|
||||
|
||||
if (written != signatureBase64Length)
|
||||
throw new Exception("expected signature length did not match bytes written");
|
||||
|
|
@ -90,11 +90,12 @@ public static class JwtCreator
|
|||
return completeJwt;
|
||||
}
|
||||
|
||||
private static void WriteJwtHeader(Utf8JsonWriter writer, IJwtSignatureProvider signatureProvider)
|
||||
private static void WriteJwtHeader(Utf8JsonWriter writer, JwtSigAlgName algName, string keyId)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WriteString("typ"u8, "JWT"u8);
|
||||
signatureProvider.WriteJwtHeaderFields(writer);
|
||||
writer.WriteString("alg"u8, algName.ToString());
|
||||
writer.WriteString("kid"u8, keyId);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue