Search code examples
c#.nethashpbkdf2

ystem.FormatException: The input is not a valid Base-64 string as it contains a non-base 64 character


I'm trying to get a token by validating a user. The problem is my program is not generating the password properly and I'm getting this error:

System.FormatException: The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.
   at System.Convert.FromBase64CharPtr(Char* inputPtr, Int32 inputLength)
   at System.Convert.FromBase64String(String s)
   at Crijoya.Infrastructure.Services.PasswordService.Check(String hash, String password) in C:\Users\USER\source\repos\Api Crijoya\Crijoya.Data\Services\PasswordService.cs:line 28
   at Api_Crijoya.Controllers.TokenController.IsValidUser(UserLogin login) in C:\Users\USER\source\repos\Api Crijoya\Api Crijoya\Controllers\TokenController.cs:line 49
   at Api_Crijoya.Controllers.TokenController.Authentication(UserLogin login) in C:\Users\USER\source\repos\Api Crijoya\Api Crijoya\Controllers\TokenController.cs:line 37
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ExceptionContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

The password it's generating is missing an equal sign at the end:

10000.QWvtocb5NEfGRUAlMEJI7w==.uZOGTPHKR5RW5C5N6qO

I don't know why this is happening. Here is where the error is:

public class PasswordService : IPasswordService
{
    private readonly PasswordOptions _options;
    public PasswordService(IOptions<PasswordOptions> options)
    {
        _options = options.Value;
    }

    public bool Check(string hash, string password)
    {
        var parts = hash.Split('.');
        if (parts.Length != 3)
        {
            throw new FormatException("Unexpected hash format");
        }

        var iterations = Convert.ToInt32(parts[0]);
        var salt = Convert.FromBase64String(parts[1]);
        var key = Convert.FromBase64String(parts[2]);

        using (var algorithm = new Rfc2898DeriveBytes(
            password,
            salt,
            iterations
            ))
        {
            var keyToCheck = algorithm.GetBytes(_options.KeySize);
            return keyToCheck.SequenceEqual(key);
        }
    }

    public string Hash(string password)
    {
        //PBKDF2 implementation
        using (var algorithm = new Rfc2898DeriveBytes(
            password,
            _options.SaltSize,
            _options.Iterations
            ))
        {
            var key = Convert.ToBase64String(algorithm.GetBytes(_options.KeySize));
            var salt = Convert.ToBase64String(algorithm.Salt);

            return $"{_options.Iterations}.{salt}.{key}";
        }
    }
}

So the error is on the variable key, as I said it is generated without the "=" at the end and I think that's why is giving me that error


Solution

  • So the problem was just that the field in my database wasn't long enough. It was generating properly the hash.