gofiber/fiber · error

decode SHA512 password

Error message

decode SHA512 password: %w

What it means

Returned by parseHashedPassword in the basicauth middleware when a password string prefixed with '{SHA512}' cannot be base64-decoded. The prefix tells Fiber the remainder is a base64-encoded SHA-512 digest; base64.StdEncoding.DecodeString returns an error for bad padding, illegal characters, or wrong length. The error propagates up and surfaces as a panic at app construction because invalid credentials are a configuration defect, not a runtime condition.

Solutions

  1. Regenerate with standard encoding: printf '%s' "$pw" | sha512sum | awk '{print $1}' | xxd -r -p | base64, then prefix {SHA512}.
  2. Strip whitespace/newlines before storing: tr -d ' \n' on the value.
  3. If you have URL-safe base64, re-encode to standard: replace - with + and _ with /.
  4. Validate the length after decoding matches sha512.Size (64 bytes) to also avoid error from the next guard.
  5. Load credentials from a vetted source (env, sealed secret) rather than hand-editing.

Example fix

// before
basicauth.New(basicauth.Config{Users: map[string]string{"admin": "{SHA512}" + urlSafeDigest}})

// after (regenerate as standard base64 of the raw 32/64-byte digest)
Digest: "{"SHA512}" + base64.StdEncoding.EncodeToString(sha512.Sum512_256(raw)) // ensure 64-byte digest
Defensive patterns

Strategy: validation

Validate before calling

func validateSHA512Hash(h string) error {
    if !strings.HasPrefix(h, "{SHA512}") { return nil }
    b, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(h, "{SHA512}"))
    if err != nil { return fmt.Errorf("bad SHA512 base64: %w", err) }
    if len(b) != sha512.Size { return fmt.Errorf("SHA512 digest must be %d bytes, got %d", sha512.Size, len(b)) }
    return nil
}

Prevention

When it happens

Trigger: Users/Passwords map has a value like '{SHA512}<garbage>' where the part after the prefix is not valid standard base64: truncated, URL-safe base64 (- and _) instead of (+ and /), missing padding, or contains whitespace/newlines copied from a terminal.

Common situations: Operator generated the digest with base64.URLEncoding instead of StdEncoding; copy-paste lost trailing '=' padding; secret was rotated through a YAML/JSON loader that stripped characters; CI pipeline encoded with `base64 -w0` on a system whose default differs; trailing newline from echo included in the value.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/373f1aada4c9e135. Report an issue: GitHub.

Appendix: source

Thrown at middleware/basicauth/config.go:273

func (s verifierStrength) betterThan(other verifierStrength) bool {
	if s.algorithm != other.algorithm {
		return s.algorithm > other.algorithm
	}

	return s.cost > other.cost
}

func parseHashedPassword(h string) (passwordVerifier, error) {
	switch {
	case strings.HasPrefix(h, "$2"):
		hash := []byte(h)
		return func(p string) bool {
			return bcrypt.CompareHashAndPassword(hash, []byte(p)) == nil
		}, nil
	case strings.HasPrefix(h, "{SHA512}"):
		b, err := base64.StdEncoding.DecodeString(h[len("{SHA512}"):])
		if err != nil {
			return nil, fmt.Errorf("decode SHA512 password: %w", err)
		}
		// A digest of the wrong size can never equal a SHA-512 sum, so
		// accepting it would silently reject every password for this user.
		// Report it instead, which surfaces as a panic at startup.
		if len(b) != sha512.Size {
			return nil, ErrInvalidSHA512PasswordLength
		}
		return func(p string) bool {
			sum := sha512.Sum512([]byte(p))
			return subtle.ConstantTimeCompare(sum[:], b) == 1
		}, nil
	case strings.HasPrefix(h, "{SHA256}"):
		b, err := base64.StdEncoding.DecodeString(h[len("{SHA256}"):])
		if err != nil {
			return nil, fmt.Errorf("decode SHA256 password: %w", err)
		}
		if len(b) != sha256.Size {
			return nil, ErrInvalidSHA256PasswordLength

View on GitHub (pinned to a105acad6c)