/// <summary> /// Initializes a new instance of the <see cref="KeyWrapper"/> class. /// </summary> /// <param name="key"></param> /// <param name="encryptionAlgorithm"></param> /// <param name="algorithm"></param> protected KeyWrapper(Jwk key, EncryptionAlgorithm encryptionAlgorithm, KeyManagementAlgorithm algorithm) { if (key is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); } if (!key.SupportKeyManagement(algorithm)) { ThrowHelper.ThrowNotSupportedException_AlgorithmForKeyWrap(algorithm); } if (algorithm is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.algorithm); } if (encryptionAlgorithm is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.encryptionAlgorithm); } Algorithm = algorithm; EncryptionAlgorithm = encryptionAlgorithm; Key = key; }
/// <summary>Encrypt the token.</summary> protected void EncryptToken(ReadOnlySpan <byte> payload, EncodingContext context) { var output = context.BufferWriter; EncryptionAlgorithm enc = _enc; var key = _encryptionKey; if (key is null) { ThrowHelper.ThrowKeyNotFoundException(); return; } KeyManagementAlgorithm alg = _alg; if (key.TryGetKeyWrapper(enc, alg, out var keyWrapper)) { var header = Header; byte[]? wrappedKeyToReturnToPool = null; byte[]? buffer64HeaderToReturnToPool = null; byte[]? arrayCiphertextToReturnToPool = null; int keyWrapSize = keyWrapper.GetKeyWrapSize(); Span <byte> wrappedKey = keyWrapSize <= Constants.MaxStackallocBytes ? stackalloc byte[keyWrapSize] : new Span <byte>(wrappedKeyToReturnToPool = ArrayPool <byte> .Shared.Rent(keyWrapSize), 0, keyWrapSize); var cek = keyWrapper.WrapKey(null, header, wrappedKey); try { using var bufferWriter = new PooledByteBufferWriter(); var writer = new Utf8JsonWriter(bufferWriter, JsonSerializationBehavior.NoJsonValidation); int base64EncodedHeaderLength = 0; ReadOnlySpan <byte> headerJson = default; var headerCache = context.HeaderCache; if (headerCache.TryGetHeader(header, alg, enc, _kid, _typ, _cty, out byte[]? cachedHeader))
public bool TryGetHeader(JwtHeader header, KeyManagementAlgorithm alg, EncryptionAlgorithm enc, JsonEncodedText kid, string?typ, string?cty, [NotNullWhen(true)] out byte[]?base64UrlHeader) { #if NET5_0_OR_GREATER Unsafe.SkipInit(out base64UrlHeader); #else base64UrlHeader = default; #endif return(false); }
/// <summary>Returns a new instance of <see cref="PasswordBasedJwk"/>.</summary> /// <remarks>The passphrase should not be longer that 128 bytes, and at least 16 bytes for "PBES2-HS256+A128KW", /// 24 bytes for "PBES2-HS384+A192KW" and 32 bytes for "PBES2-HS512+A256KW"</remarks> /// <param name="passphrase">The passphrase used for the key derivation. /// This should not be longer that 128 bytes, and at least 16 bytes for "PBES2-HS256+A128KW", /// 24 bytes for "PBES2-HS384+A192KW" and 32 bytes for "PBES2-HS512+A256KW"</param> /// <param name="algorithm">The key encryption algorithm. It must be a PBES2 algorithm.</param> /// <param name="iterationCount">The number of iterations. Should be at least 1000.</param> /// <param name="saltSizeInBytes">The salt size, in bytes. Should be at least 8 bytes. Value greater than 256 bytes is not supported.</param> /// <param name="computeThumbprint">Defines whether the thubpring should be computed.</param> public static PasswordBasedJwk FromPassphrase(string passphrase, KeyManagementAlgorithm algorithm, uint iterationCount = 1000, uint saltSizeInBytes = 8, bool computeThumbprint = true) { if (passphrase is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.bytes); } var innerKey = SymmetricJwk.FromByteArray(Utf8.GetBytes(passphrase), algorithm, computeThumbprint); return(new PasswordBasedJwk(innerKey, iterationCount, saltSizeInBytes, algorithm)); }
/// <inheritdoc/> public bool TryGetHeader(JwtHeader header, KeyManagementAlgorithm alg, EncryptionAlgorithm enc, JsonEncodedText kid, string?typ, string?cty, [NotNullWhen(true)] out byte[]?base64UrlHeader) { if (ReferenceEquals(_firstHeader.Header, header)) { base64UrlHeader = _firstHeader.BinaryHeader; goto Found; } if (IsEligibleHeaderForJwe(header.Count, kid, typ, cty)) { int algorithmId = enc.ComputeKey(alg); var node = _head; while (node != null) { if (algorithmId == node.AlgorithmId) { if (node.TryGetEntry(kid, out var entry)) { if (cty != entry.Cty) { goto NotFound; } if (typ != entry.Typ) { goto NotFound; } base64UrlHeader = entry.Data; if (node != _head) { MoveToHead(node); } goto Found; } } node = node.Next; } } NotFound: #if NET5_0_OR_GREATER Unsafe.SkipInit(out base64UrlHeader); #else base64UrlHeader = default; #endif return(false); Found: return(true); }
internal static void ThrowCryptographicException_CreateSymmetricAlgorithmFailed(Jwk key, KeyManagementAlgorithm algorithm, Exception innerException) => throw CreateCryptographicException_CreateSymmetricAlgorithmFailed(key, algorithm, innerException);
/// <inheritsdoc /> public override bool SupportKeyManagement(KeyManagementAlgorithm algorithm) => algorithm.Category == AlgorithmCategory.Pbkdf2;
/// <inheritsdoc /> protected override KeyUnwrapper CreateKeyUnwrapper(EncryptionAlgorithm encryptionAlgorithm, KeyManagementAlgorithm algorithm) => new Pbes2KeyUnwrapper(this, encryptionAlgorithm, algorithm);
private PasswordBasedJwk(SymmetricJwk key, uint iterationCount, uint saltSizeInBytes, KeyManagementAlgorithm algorithm) : base(algorithm) { Debug.Assert(key != null); Debug.Assert(algorithm != null); _inner = key; _iterationCount = iterationCount; _saltSizeInBytes = saltSizeInBytes; Kid = key.Kid; }
/// <summary>Initializes a new instance of the <see cref="JweDescriptor"/> class.</summary> public JweDescriptor(Jwk encryptionKey, KeyManagementAlgorithm alg, EncryptionAlgorithm enc, CompressionAlgorithm?zip = null, string?typ = null, string?cty = Constants.Jwt) : base(encryptionKey, alg, enc, zip, typ, cty) { }
/// <summary>Initializes a new instance of the <see cref="BinaryJweDescriptor"/> class.</summary> public BinaryJweDescriptor(Jwk encryptionKey, KeyManagementAlgorithm alg, EncryptionAlgorithm enc, CompressionAlgorithm?zip = null, string?typ = JwtMediaTypeValues.OctetStream, string?cty = null) : base(encryptionKey, alg, enc, zip, typ, cty) { _payload = Array.Empty <byte>(); }
/// <summary>Initializes a new instance of <see cref="PlaintextJweDescriptor"/>.</summary> public PlaintextJweDescriptor(Jwk encryptionKey, KeyManagementAlgorithm alg, EncryptionAlgorithm enc, CompressionAlgorithm?zip = null, string?typ = JwtMediaTypeValues.Plain, string?cty = null) : base(encryptionKey, alg, enc, zip, typ, cty) { }
public void AddHeader(JwtHeader header, KeyManagementAlgorithm alg, EncryptionAlgorithm enc, JsonEncodedText kid, string?typ, string?cty, ReadOnlySpan <byte> base64UrlHeader) { _jweCache.AddHeader(header, alg, enc, kid, typ, cty, base64UrlHeader); }
/// <summary>Initializes a new instance of the <see cref="JwksJweDescriptor"/> class.</summary> public JwksJweDescriptor(Jwk encryptionKey, KeyManagementAlgorithm alg, EncryptionAlgorithm enc, CompressionAlgorithm?zip = null, string?typ = null, string?cty = JwtContentTypeValues.Jwks) : base(encryptionKey, alg, enc, zip, typ, cty) { _payload = new Jwks(); }
private static Exception CreateCryptographicException_CreateSymmetricAlgorithmFailed(Jwk key, KeyManagementAlgorithm algorithm, Exception innerException) => new CryptographicException($"Failed to create symmetric algorithm for key wrap with key: '{key.Kid}', algorithm: '{algorithm}'.", innerException);
private static Exception CreateArgumentOutOfRangeException_KeyWrapKeySizeIncorrect(KeyManagementAlgorithm algorithm, int requiredValue, Jwk key, int currentKeySize) => new ArgumentOutOfRangeException(nameof(key), $"The key '{key.Kid}' for key wrapping with algorithm '{algorithm}' must be of '{requiredValue}' bits. Key size: '{currentKeySize}'.");
internal static void ThrowArgumentOutOfRangeException_KeyWrapKeySizeIncorrect(KeyManagementAlgorithm algorithm, int requiredValue, Jwk key, int currentKeySize) => throw CreateArgumentOutOfRangeException_KeyWrapKeySizeIncorrect(algorithm, requiredValue, key, currentKeySize);
/// <summary> /// Initializes a new instance of the <see cref="Jwk"/> class. /// </summary> /// <param name="alg"></param> protected Jwk(KeyManagementAlgorithm alg) { Alg = alg.Utf8Name; _keyManagementAlgorithm = alg; }
/// <inheritdoc/> public void AddHeader(JwtHeader header, KeyManagementAlgorithm alg, EncryptionAlgorithm enc, JsonEncodedText kid, string?typ, string?cty, ReadOnlySpan <byte> base6UrlHeader) { _firstHeader = new WrappedHeader(header, base6UrlHeader.ToArray()); if (IsEligibleHeaderForJwe(header.Count, kid, typ, cty)) { int algorithmId = enc.ComputeKey(alg); bool lockTaken = false; try { _spinLock.Enter(ref lockTaken); if (_count >= MaxSize) { _head = null; _tail = null; _count = 0; } var node = _head; while (node != null) { if (algorithmId == node.AlgorithmId) { break; } node = node.Next; } var key = alg.Id; if (node is null) { _count++; node = new Bucket(algorithmId, kid, new CacheEntry(base6UrlHeader.ToArray(), typ, cty)) { Next = _head }; } else { if (!node.Entries.ContainsKey(kid !)) { _count++; node.Entries[kid] = new CacheEntry(base6UrlHeader.ToArray(), typ, cty); } } if (!ReferenceEquals(_head, node)) { if (_head != null) { _head.Previous = node; } _head = node; } if (_tail is null) { _tail = node; } } finally { if (lockTaken) { _spinLock.Exit(); } } } }
private static Exception CreateNotSupportedException_Algorithm(KeyManagementAlgorithm algorithm) => new NotSupportedException($"The algorithm '{algorithm}' is not supported for this kind of JWK.");
public bool TryGetHeader(JwtHeader header, KeyManagementAlgorithm alg, EncryptionAlgorithm enc, JsonEncodedText kid, string?typ, string?cty, [NotNullWhen(true)] out byte[]?base64UrlHeader) { return(_jweCache.TryGetHeader(header, alg, enc, kid, typ, cty, out base64UrlHeader)); }
/// <inheritsdoc /> protected override KeyWrapper CreateKeyWrapper(EncryptionAlgorithm encryptionAlgorithm, KeyManagementAlgorithm algorithm) => throw new NotImplementedException();
public void AddHeader(JwtHeader header, KeyManagementAlgorithm alg, EncryptionAlgorithm enc, JsonEncodedText kid, string?typ, string?cty, ReadOnlySpan <byte> base6UrlHeader) { }
/// <summary>Initializes a new instance of the <see cref="JweDescriptor{TPayload}"/> class.</summary> protected JweDescriptor(Jwk encryptionKey, KeyManagementAlgorithm alg, EncryptionAlgorithm enc, CompressionAlgorithm?zip = null, string?typ = null, string?cty = null) { _encryptionKey = encryptionKey ?? throw new ArgumentNullException(nameof(encryptionKey)); _alg = alg ?? throw new ArgumentNullException(nameof(alg)); _enc = enc ?? throw new ArgumentNullException(nameof(enc)); _zip = zip ?? CompressionAlgorithm.NoCompression; var kid = encryptionKey.Kid; if (!kid.EncodedUtf8Bytes.IsEmpty) { _kid = kid; if (zip != null) { if (cty != null) { _cty = cty; Header.FastAdd( new JwtMember(JwtHeaderParameterNames.Alg, alg.Name), new JwtMember(JwtHeaderParameterNames.Enc, enc.Name), new JwtMember(JwtHeaderParameterNames.Kid, kid), new JwtMember(JwtHeaderParameterNames.Zip, zip.Name), new JwtMember(JwtHeaderParameterNames.Cty, cty)); } else { Header.FastAdd( new JwtMember(JwtHeaderParameterNames.Alg, alg.Name), new JwtMember(JwtHeaderParameterNames.Enc, enc.Name), new JwtMember(JwtHeaderParameterNames.Kid, kid), new JwtMember(JwtHeaderParameterNames.Zip, zip.Name)); } } else { if (cty != null) { _cty = cty; Header.FastAdd( new JwtMember(JwtHeaderParameterNames.Alg, alg.Name), new JwtMember(JwtHeaderParameterNames.Enc, enc.Name), new JwtMember(JwtHeaderParameterNames.Kid, kid), new JwtMember(JwtHeaderParameterNames.Cty, cty)); } else { Header.FastAdd( new JwtMember(JwtHeaderParameterNames.Alg, alg.Name), new JwtMember(JwtHeaderParameterNames.Enc, enc.Name), new JwtMember(JwtHeaderParameterNames.Kid, kid)); } } } else { if (zip != null) { if (cty != null) { _cty = cty; Header.FastAdd( new JwtMember(JwtHeaderParameterNames.Alg, alg.Name), new JwtMember(JwtHeaderParameterNames.Enc, enc.Name), new JwtMember(JwtHeaderParameterNames.Zip, zip.Name), new JwtMember(JwtHeaderParameterNames.Cty, cty)); } else { Header.FastAdd( new JwtMember(JwtHeaderParameterNames.Alg, alg.Name), new JwtMember(JwtHeaderParameterNames.Enc, enc.Name), new JwtMember(JwtHeaderParameterNames.Zip, zip.Name)); } } else { if (cty != null) { _cty = cty; Header.FastAdd( new JwtMember(JwtHeaderParameterNames.Alg, alg.Name), new JwtMember(JwtHeaderParameterNames.Enc, enc.Name), new JwtMember(JwtHeaderParameterNames.Cty, cty)); } else { Header.FastAdd( new JwtMember(JwtHeaderParameterNames.Alg, alg.Name), new JwtMember(JwtHeaderParameterNames.Enc, enc.Name)); } } } if (typ != null) { _typ = typ; Header.Add(JwtHeaderParameterNames.Typ, typ); } }
internal static void ThrowNotSupportedException_Algorithm(KeyManagementAlgorithm algorithm) => throw CreateNotSupportedException_Algorithm(algorithm);
public bool TryGetHeader(JwtHeader header, KeyManagementAlgorithm alg, EncryptionAlgorithm enc, JsonEncodedText kid, string?typ, string?cty, [NotNullWhen(true)] out byte[]?base64UrlHeader) { base64UrlHeader = null; return(false); }
/// <inheritsdoc /> public override bool SupportKeyManagement(KeyManagementAlgorithm algorithm) => throw new NotImplementedException();
/// <summary> /// Computes a unique key for the combinaison of the <see cref="EncryptionAlgorithm"/> and the <see cref="KeyManagementAlgorithm"/>. /// </summary> /// <param name="algorithm"></param> /// <returns></returns> public int ComputeKey(KeyManagementAlgorithm algorithm) { return((_id << 8) | (byte)algorithm.Id); }
/// <summary> /// Initializes a new instance of the <see cref="AsymmetricJwk"/> class. /// </summary> protected AsymmetricJwk(KeyManagementAlgorithm alg) : base(alg) { }
/// <inheritsdoc /> protected override KeyWrapper CreateKeyWrapper(EncryptionAlgorithm encryptionAlgorithm, KeyManagementAlgorithm algorithm) => new Pbes2KeyWrapper(this, encryptionAlgorithm, algorithm, _iterationCount, _saltSizeInBytes, _saltGenerator);