/// <summary>Returns a new instance of <see cref="Jwks"/>.</summary> /// <param name="issuer">The issuer of the keys.</param> /// <param name="json">A string that contains JSON Web Key parameters in JSON format.</param> public static Jwks FromJson(string issuer, string json) { if (json is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.json); } byte[]? jsonToReturn = null; try { int length = Utf8.GetMaxByteCount(json.Length); Span <byte> jsonSpan = length <= Constants.MaxStackallocBytes ? stackalloc byte[length] : (jsonToReturn = ArrayPool <byte> .Shared.Rent(length)); length = Utf8.GetBytes(json, jsonSpan); return(FromJson(issuer, jsonSpan.Slice(0, length))); } finally { if (jsonToReturn != null) { ArrayPool <byte> .Shared.Return(jsonToReturn); } } }
/// <summary>Decodes a string of UTF-8 base64url-encoded text.</summary> /// <remarks>This method allocate an array of bytes. Use <see cref="Decode(ReadOnlySpan{byte}, Span{byte})"/> when possible.</remarks> public static byte[] Decode(string data) { if (data is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.data); } int length = Utf8.GetMaxByteCount(data.Length); byte[]? utf8ArrayToReturn = null; try { Span <byte> tmp = length > Constants.MaxStackallocBytes ? (utf8ArrayToReturn = ArrayPool <byte> .Shared.Rent(length)) : stackalloc byte[Constants.MaxStackallocBytes]; int written = Utf8.GetBytes(data, tmp); return(Decode(tmp.Slice(0, written))); } finally { if (utf8ArrayToReturn != null) { ArrayPool <byte> .Shared.Return(utf8ArrayToReturn); } } }
/// <inheritsdoc /> public override void Encode(EncodingContext context) { if (Payload != null) { int payloadLength = Utf8.GetMaxByteCount(Payload.Length); byte[]? payloadToReturnToPool = null; Span <byte> encodedPayload = payloadLength > Constants.MaxStackallocBytes ? (payloadToReturnToPool = ArrayPool <byte> .Shared.Rent(payloadLength)) : stackalloc byte[payloadLength]; try { int bytesWritten = Utf8.GetBytes(Payload, encodedPayload); EncryptToken(encodedPayload.Slice(0, bytesWritten), context); } finally { if (payloadToReturnToPool != null) { ArrayPool <byte> .Shared.Return(payloadToReturnToPool); } } } else { ThrowHelper.ThrowInvalidOperationException_UndefinedPayload(); } }
internal bool TryGetNamedPropertyValue(ReadOnlySpan <char> propertyName, out JwtElement value) { JsonRow row; int maxBytes = Utf8.GetMaxByteCount(propertyName.Length); int endIndex = _parsedData.Length; if (maxBytes < JsonConstants.StackallocThreshold) { Span <byte> utf8Name = stackalloc byte[JsonConstants.StackallocThreshold]; int len = JsonReaderHelper.GetUtf8FromText(propertyName, utf8Name); utf8Name = utf8Name.Slice(0, len); return(TryGetNamedPropertyValue( endIndex, utf8Name, out value)); } // Unescaping the property name will make the string shorter (or the same) // So the first viable candidate is one whose length in bytes matches, or // exceeds, our length in chars. // // The maximal escaping seems to be 6 -> 1 ("\u0030" => "0"), but just transcode // and switch once one viable long property is found. int minBytes = propertyName.Length; for (int candidateIndex = 0; candidateIndex <= endIndex; candidateIndex += JsonRow.Size * 2) { row = _parsedData.Get(candidateIndex); Debug.Assert(row.TokenType == JsonTokenType.PropertyName); if (row.Length >= minBytes) { byte[] tmpUtf8 = ArrayPool <byte> .Shared.Rent(maxBytes); Span <byte> utf8Name = default; try { int len = JsonReaderHelper.GetUtf8FromText(propertyName, tmpUtf8); utf8Name = tmpUtf8.AsSpan(0, len); return(TryGetNamedPropertyValue( candidateIndex, utf8Name, out value)); } finally { ArrayPool <byte> .Shared.Return(tmpUtf8); } } } // None of the property names were within the range that the UTF-8 encoding would have been. value = default; return(false); }
/// <summary>Parses and validates a JWT encoded as a JWS or JWE in compact serialized format.</summary> /// <param name="token">The JWT encoded as JWE or JWS</param> /// <param name="policy">The validation policy.</param> /// <param name="jwt">The resulting <see cref="Jwt"/>.</param> public static bool TryParse(string token, TokenValidationPolicy policy, out Jwt jwt) { if (token is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.token); } if (policy is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.policy); } if (token.Length == 0) { jwt = new Jwt(TokenValidationError.MalformedToken()); return(false); } int length = Utf8.GetMaxByteCount(token.Length); if (length > policy.MaximumTokenSizeInBytes) { jwt = new Jwt(TokenValidationError.MalformedToken()); return(false); } byte[]? utf8ArrayToReturnToPool = null; var utf8Token = length <= Constants.MaxStackallocBytes ? stackalloc byte[length] : (utf8ArrayToReturnToPool = ArrayPool <byte> .Shared.Rent(length)); try { int bytesWritten = Utf8.GetBytes(token, utf8Token); return(TryParse(utf8Token.Slice(0, bytesWritten), policy, out jwt)); } finally { if (utf8ArrayToReturnToPool != null) { ArrayPool <byte> .Shared.Return(utf8ArrayToReturnToPool); } } }
/// <summary>Encodes a string of UTF-8 text.</summary> /// <returns>The base64-url encoded string.</returns> /// <remarks>This method allocate an array of bytes. Use <see cref="Encode(ReadOnlySpan{byte}, Span{byte})"/> when possible.</remarks> public static byte[] Encode(ReadOnlySpan <char> data) { byte[]? utf8ArrayToReturn = null; try { int length = Utf8.GetMaxByteCount(data.Length); var utf8Data = length > Constants.MaxStackallocBytes ? (utf8ArrayToReturn = ArrayPool <byte> .Shared.Rent(length)) : stackalloc byte[Constants.MaxStackallocBytes]; int written = Utf8.GetBytes(data, utf8Data); return(Encode(utf8Data.Slice(0, written))); } finally { if (utf8ArrayToReturn != null) { ArrayPool <byte> .Shared.Return(utf8ArrayToReturn); } } }
/// <inheritsdoc /> public override void Encode(EncodingContext context, IBufferWriter <byte> output) { int payloadLength = Utf8.GetMaxByteCount(Payload.Length); byte[]? payloadToReturnToPool = null; Span <byte> encodedPayload = payloadLength > Constants.MaxStackallocBytes ? (payloadToReturnToPool = ArrayPool <byte> .Shared.Rent(payloadLength)) : stackalloc byte[payloadLength]; try { int bytesWritten = Utf8.GetBytes(Payload, encodedPayload); EncryptToken(context, encodedPayload.Slice(0, bytesWritten), output); } finally { if (payloadToReturnToPool != null) { ArrayPool <byte> .Shared.Return(payloadToReturnToPool); } } }