golang/go · error

pbkdf2: keyLength too long

Error message

pbkdf2: keyLength too long

What it means

PBKDF2 rejects keyLength values that are unreasonably large. Two conditions trigger this: integer overflow detected via keyLength + hashLen < keyLength (signed wraparound), or numBlocks = ceil(keyLength / hashLen) exceeding 2^32 - 1 (the maximum block counter, since the block index is a 32-bit big-endian integer in the PRF input).

Source

Thrown at src/crypto/internal/fips140/pbkdf2/pbkdf2.go:36

// of the integer size.
func divRoundUp(x, y int) int {
	return int((int64(x) + int64(y) - 1) / int64(y))
}

func Key[Hash hash.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) {
	setServiceIndicator(salt, keyLength)

	if keyLength <= 0 {
		return nil, errors.New("pbkdf2: keyLength must be larger than 0")
	}

	prf := hmac.New(h, []byte(password))
	hmac.MarkAsUsedInKDF(prf)
	hashLen := prf.Size()
	numBlocks := divRoundUp(keyLength, hashLen)
	const maxBlocks = int64(1<<32 - 1)
	if keyLength+hashLen < keyLength || int64(numBlocks) > maxBlocks {
		return nil, errors.New("pbkdf2: keyLength too long")
	}

	var buf [4]byte
	dk := make([]byte, 0, numBlocks*hashLen)
	U := make([]byte, hashLen)
	for block := 1; block <= numBlocks; block++ {
		// N.B.: || means concatenation, ^ means XOR
		// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
		// U_1 = PRF(password, salt || uint(i))
		prf.Reset()
		prf.Write(salt)
		buf[0] = byte(block >> 24)
		buf[1] = byte(block >> 16)
		buf[2] = byte(block >> 8)
		buf[3] = byte(block)
		prf.Write(buf[:4])
		dk = prf.Sum(dk)
		T := dk[len(dk)-hashLen:]

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Clamp keyLength to a reasonable maximum (e.g., 64 * hashLen) before calling Key()
  2. Validate keyLength against the formula: keyLength <= (2^32 - 1) * hashLen
  3. Audit where keyLength originates — it should be a small, well-known constant like 16, 32, or 64

Example fix

// before
dk, err := pbkdf2.Key(sha256.New, password, salt, iter, requestedLen)

// after
maxKeyLen := (1<<32 - 1) * sha256.New().Size()
if requestedLen > maxKeyLen {
    return nil, fmt.Errorf("keyLength %d exceeds maximum %d", requestedLen, maxKeyLen)
}
dk, err := pbkdf2.Key(sha256.New, password, salt, iter, requestedLen)
Defensive patterns

Strategy: validation

Validate before calling

func validatePbkdf2KeyLength(keyLen, hashLen int) error {
    if keyLen <= 0 {
        return fmt.Errorf("keyLength must be positive")
    }
    maxBlocks := int64(1<<32 - 1)
    numBlocks := int64((int64(keyLen) + int64(hashLen) - 1) / int64(hashLen))
    if numBlocks > maxBlocks {
        return fmt.Errorf("keyLength %d too large", keyLen)
    }
    return nil
}

hashLen := sha256.New().Size()
if err := validatePbkdf2KeyLength(keyLen, hashLen); err != nil { return err }
dk, err := pbkdf2.Key(sha256.New, password, salt, iter, keyLen)

Try / catch

dk, err := pbkdf2.Key(h, password, salt, iter, keyLen)
if err != nil {
    return fmt.Errorf("PBKDF2 key derivation failed: %w", err)
}

Prevention

When it happens

Trigger: Calling Key() with a very large keyLength — near INT_MAX, negative-when-cast, or requiring more than 2^32 - 1 hash-sized blocks to fill.

Common situations: keyLength read from an untrusted 64-bit field without clamping; a bug where a byte count and a bit count are confused (multiplying by 8); a configuration typo using an extremely large number.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/027f97e3880e7d5b. Report an issue: GitHub.