/// <inheritsdoc />
        public override bool TryUnwrapKey(ReadOnlySpan <byte> keyBytes, Span <byte> destination, JwtHeaderDocument header, out int bytesWritten)
        {
            if (!header.TryGetHeaderParameter(JwtHeaderParameterNames.P2c.EncodedUtf8Bytes, out JwtElement p2c))
            {
                ThrowHelper.ThrowJwtDescriptorException_HeaderIsRequired(JwtHeaderParameterNames.P2c);
            }

            if (!header.TryGetHeaderParameter(JwtHeaderParameterNames.P2s.EncodedUtf8Bytes, out JwtElement p2s))
            {
                ThrowHelper.ThrowJwtDescriptorException_HeaderIsRequired(JwtHeaderParameterNames.P2s);
            }

            int iterationCount = (int)p2c.GetInt64();
            var b64p2s         = p2s.GetRawValue();
            int p2sLength      = Base64Url.GetArraySizeRequiredToDecode(b64p2s.Length);


            Span <byte> salt = stackalloc byte[p2sLength + 1 + _algorithmNameLength];

            Base64Url.Decode(b64p2s.Span, salt.Slice(_algorithmNameLength + 1));
            salt[_algorithmNameLength] = 0x00;
            _algorithm.EncodedUtf8Bytes.CopyTo(salt);

            Span <byte> derivedKey = stackalloc byte[_keySizeInBytes];

            Pbkdf2.DeriveKey(_password, salt, _hashAlgorithm, (uint)iterationCount, derivedKey);

            using var keyUnwrapper = new AesKeyUnwrapper(derivedKey, EncryptionAlgorithm, _keyManagementAlgorithm);
            return(keyUnwrapper.TryUnwrapKey(keyBytes, destination, header, out bytesWritten));
        }
Example #2
0
        /// <inheritsdoc />
        public override bool TryUnwrapKey(ReadOnlySpan <byte> keyBytes, Span <byte> destination, JwtHeaderDocument header, out int bytesWritten)
        {
            if (!header.TryGetHeaderParameter(JwtHeaderParameterNames.IV.EncodedUtf8Bytes, out var encodedIV))
            {
                ThrowHelper.ThrowJwtDescriptorException_HeaderIsRequired(JwtHeaderParameterNames.IV);
            }

            if (!header.TryGetHeaderParameter(JwtHeaderParameterNames.Tag.EncodedUtf8Bytes, out var encodedTag))
            {
                ThrowHelper.ThrowJwtDescriptorException_HeaderIsRequired(JwtHeaderParameterNames.Tag);
            }

            var         rawIV  = encodedIV.GetRawValue();
            Span <byte> nonce  = stackalloc byte[IVSize];
            var         rawTag = encodedTag.GetRawValue();
            Span <byte> tag    = stackalloc byte[TagSize];

            try
            {
                Base64Url.Decode(rawIV.Span, nonce);
                Base64Url.Decode(rawTag.Span, tag);
                using var aesGcm = new AesGcm(_key.K);
                if (destination.Length > keyBytes.Length)
                {
                    destination = destination.Slice(0, keyBytes.Length);
                }

                aesGcm.Decrypt(nonce, keyBytes, tag, destination);
                bytesWritten = destination.Length;

                return(true);
            }
            catch (CryptographicException)
            {
                return(ThrowHelper.TryWriteError(out bytesWritten));
            }
        }
Example #3
0
        /// <inheritsdoc />
        public override bool TryUnwrapKey(ReadOnlySpan <byte> keyBytes, Span <byte> destination, JwtHeaderDocument header, out int bytesWritten)
        {
            if (!header.TryGetHeaderParameter(JwtHeaderParameterNames.Epk.EncodedUtf8Bytes, out var epk))
            {
                ThrowHelper.ThrowJwtDescriptorException_HeaderIsRequired(JwtHeaderParameterNames.Epk);
            }

            header.TryGetHeaderParameter(JwtHeaderParameterNames.Apu.EncodedUtf8Bytes, out JwtElement apu);
            header.TryGetHeaderParameter(JwtHeaderParameterNames.Apv.EncodedUtf8Bytes, out JwtElement apv);
            byte[] secretAppend = BuildSecretAppend(apu, apv);

            ReadOnlySpan <byte> exchangeHash;

            using (var ephemeralKey = ECDiffieHellman.Create(ECJwk.FromJwtElement(epk).ExportParameters()))
            {
                var privateKey = _key.CreateEcdhKey();
                if (ephemeralKey.KeySize != privateKey.KeySize)
                {
                    return(ThrowHelper.TryWriteError(out bytesWritten));
                }

                exchangeHash = new ReadOnlySpan <byte>(privateKey.DeriveKeyFromHash(ephemeralKey.PublicKey, _hashAlgorithm, _secretPreprend, secretAppend), 0, _keySizeInBytes);
            }

            if (Algorithm.ProduceEncryptionKey)
            {
                using var keyUnwrapper = new AesKeyUnwrapper(exchangeHash, EncryptionAlgorithm, _keyManagementAlgorithm !);
                return(keyUnwrapper.TryUnwrapKey(keyBytes, destination, header, out bytesWritten));
            }
            else
            {
                exchangeHash.CopyTo(destination);
                bytesWritten = destination.Length;
                return(true);
            }
        }