< Summary - Jellyfin

Information
Class: Emby.Server.Implementations.Cryptography.CryptographyProvider
Assembly: Emby.Server.Implementations
File(s): /srv/git/jellyfin/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs
Line coverage
84%
Covered lines: 38
Uncovered lines: 7
Coverable lines: 45
Total lines: 101
Line coverage: 84.4%
Branch coverage
100%
Covered branches: 8
Total branches: 8
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 10/18/2025 - 12:10:13 AM Line coverage: 55.2% (21/38) Branch coverage: 0% (0/4) Total lines: 781/10/2026 - 12:12:36 AM Line coverage: 84.4% (38/45) Branch coverage: 100% (8/8) Total lines: 101 10/18/2025 - 12:10:13 AM Line coverage: 55.2% (21/38) Branch coverage: 0% (0/4) Total lines: 781/10/2026 - 12:12:36 AM Line coverage: 84.4% (38/45) Branch coverage: 100% (8/8) Total lines: 101

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_DefaultHashMethod()100%11100%
CreatePasswordHash(...)100%11100%
Verify(...)100%5463.15%
GetIterationsParameter(...)100%44100%
GenerateSalt()100%11100%
GenerateSalt(...)100%11100%

File(s)

/srv/git/jellyfin/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Globalization;
 4using System.Security.Cryptography;
 5using MediaBrowser.Model.Cryptography;
 6using static MediaBrowser.Model.Cryptography.Constants;
 7
 8namespace Emby.Server.Implementations.Cryptography
 9{
 10    /// <summary>
 11    /// Class providing abstractions over cryptographic functions.
 12    /// </summary>
 13    public class CryptographyProvider : ICryptoProvider
 14    {
 15        /// <inheritdoc />
 516        public string DefaultHashMethod => "PBKDF2-SHA512";
 17
 18        /// <inheritdoc />
 19        public PasswordHash CreatePasswordHash(ReadOnlySpan<char> password)
 20        {
 521            byte[] salt = GenerateSalt();
 522            return new PasswordHash(
 523                DefaultHashMethod,
 524                Rfc2898DeriveBytes.Pbkdf2(
 525                    password,
 526                    salt,
 527                    DefaultIterations,
 528                    HashAlgorithmName.SHA512,
 529                    DefaultOutputLength),
 530                salt,
 531                new Dictionary<string, string>
 532                {
 533                    { "iterations", DefaultIterations.ToString(CultureInfo.InvariantCulture) }
 534                });
 35        }
 36
 37        /// <inheritdoc />
 38        public bool Verify(PasswordHash hash, ReadOnlySpan<char> password)
 39        {
 740            if (string.Equals(hash.Id, "PBKDF2", StringComparison.Ordinal))
 41            {
 242                var iterations = GetIterationsParameter(hash);
 043                return hash.Hash.SequenceEqual(
 044                    Rfc2898DeriveBytes.Pbkdf2(
 045                        password,
 046                        hash.Salt,
 047                        iterations,
 048                        HashAlgorithmName.SHA1,
 049                        32));
 50            }
 51
 552            if (string.Equals(hash.Id, "PBKDF2-SHA512", StringComparison.Ordinal))
 53            {
 454                var iterations = GetIterationsParameter(hash);
 255                return hash.Hash.SequenceEqual(
 256                    Rfc2898DeriveBytes.Pbkdf2(
 257                        password,
 258                        hash.Salt,
 259                        iterations,
 260                        HashAlgorithmName.SHA512,
 261                        DefaultOutputLength));
 62            }
 63
 164            throw new NotSupportedException($"Can't verify hash with id: {hash.Id}");
 65        }
 66
 67        /// <summary>
 68        /// Extracts and validates the iterations parameter from a password hash.
 69        /// </summary>
 70        /// <param name="hash">The password hash containing parameters.</param>
 71        /// <returns>The number of iterations.</returns>
 72        /// <exception cref="FormatException">Thrown when iterations parameter is missing or invalid.</exception>
 73        private static int GetIterationsParameter(PasswordHash hash)
 74        {
 675            if (!hash.Parameters.TryGetValue("iterations", out var iterationsStr))
 76            {
 277                throw new FormatException($"Password hash with id '{hash.Id}' is missing required 'iterations' parameter
 78            }
 79
 480            if (!int.TryParse(iterationsStr, CultureInfo.InvariantCulture, out var iterations))
 81            {
 282                throw new FormatException($"Password hash with id '{hash.Id}' has invalid 'iterations' parameter: '{iter
 83            }
 84
 285            return iterations;
 86        }
 87
 88        /// <inheritdoc />
 89        public byte[] GenerateSalt()
 690            => GenerateSalt(DefaultSaltLength);
 91
 92        /// <inheritdoc />
 93        public byte[] GenerateSalt(int length)
 94        {
 995            var salt = new byte[length];
 996            using var rng = RandomNumberGenerator.Create();
 997            rng.GetNonZeroBytes(salt);
 998            return salt;
 999        }
 100    }
 101}