gofiber/fiber · error

decode SHA512 password: %w

Error message

decode SHA512 password: %w

What it means

Emitted by parseHashedPassword when a Users entry begins with the literal '{SHA512}' prefix but the remainder is not valid standard base64. Fiber expects '{SHA512}' immediately followed by the base64-encoded 64-byte SHA-512 digest of the password (binary form, not hex). This is the Apache htpasswd '{SHA}'-style scheme; any base64 corruption — wrong padding, URL-safe alphabet, or truncation — surfaces here.

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 9a4c7e57fe)

Solutions

  1. Regenerate the digest as raw bytes in standard base64: printf '%s' "$PW" | openssl dgst -sha512 -binary | base64, then set Users[u] = "{SHA512}" + that.
  2. Strip any whitespace/newlines from the value before embedding it in config.
  3. Make sure the value uses standard base64 (+ and /, = padding), not URL-safe (- and _) or hex.
  4. Confirm length is 64 bytes after decode, or you'll next hit ErrInvalidSHA512PasswordLength.

Example fix

// before: hex digest after the prefix -> base64 decode fails
users := map[string]string{"alice": "{SHA512}" + hexSHA512}

// after: raw bytes, standard base64
// $ printf '%s' 'hunter2' | openssl dgst -sha512 -binary | base64
users := map[string]string{"alice": "{SHA512}" + b64RawBytes}
Defensive patterns

Strategy: validation

Validate before calling

// Validate a {SHA512} password entry before configuring basicauth.
func validSHA512Entry(v string) error {
    const p = "{SHA512}"
    if !strings.HasPrefix(v, p) {
        return fmt.Errorf("missing %q prefix", p)
    }
    b, err := base64.StdEncoding.DecodeString(v[len(p):])
    if err != nil {
        return fmt.Errorf("not standard base64: %w", err)
    }
    if len(b) != sha512.Size {
        return fmt.Errorf("decoded length %d != %d", len(b), sha512.Size)
    }
    return nil
}

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Configuring middleware/basicauth with Users map[string]string where a value is "{SHA512}" + something that base64.StdEncoding.DecodeString rejects: e.g. '{SHA512}dGhpcyBpc', missing '==' padding, contains '-'/'_' (URL-safe alphabet), or has whitespace/newline. A digest produced with 'openssl dgst -sha512 | cut' (hex output) instead of raw bytes also fails.

Common situations: Generating the hash with the wrong tool (printf of hex instead of base64); copying the value from a YAML that ate trailing '=' padding; mixing up {SHA256} vs {SHA512} digests; pasting a value that wrapped across lines in the terminal.

Related errors


AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04). Data as JSON: /data/errors/373f1aada4c9e135.json. Report an issue: GitHub.