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
- Clamp keyLength to a reasonable maximum (e.g., 64 * hashLen) before calling Key()
- Validate keyLength against the formula: keyLength <= (2^32 - 1) * hashLen
- 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
- keyLength should be a small known constant (16, 32, 64), not a computed large value
- Audit where keyLength originates — clamp untrusted input to a reasonable maximum
- Watch for byte/bit confusion (multiplying by 8) when deriving key sizes
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
- pbkdf2: keyLength must be larger than 0
- mlkem: invalid encapsulation key length
- mlkem: invalid ciphertext length
- mlkem: invalid seed length
- mlkem: invalid NIST decapsulation key length
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/027f97e3880e7d5b.
Report an issue: GitHub.