Balloon space cost wraps before conversion to the 64-bit block count
Closed, ResolvedPublic

Assigned To
Authored By
werner
Tue, Aug 4, 4:55 PM

Description

Balloon space cost wraps before conversion to the 64-bit block count

Balloon stores its block count in 64 bits, but computes s_cost * 1024 while both operands are still 32-bit. An accepted public s_cost = 4194305 therefore wraps the requested roughly 4-GiB work factor to 1024 bytes; with SHA-256 the KDF allocates and processes only 32 blocks while retaining the large advertised parameter.

Vulnerable code

cipher/kdf.c, balloon_open:

c
      s_cost = (unsigned int)param[0];
      t_cost = (unsigned int)param[1];
      if (paramlen >= 3)
        parallelism = (unsigned int)param[2];
c
  if (s_cost < 1)
    return GPG_ERR_INV_VALUE;
c
  b->s_cost = s_cost;
  b->t_cost = t_cost;
  b->parallelism = parallelism;

  b->n_blocks = (s_cost * 1024) / b->blklen;

  block = xtrycalloc (parallelism * b->n_blocks, b->blklen);

Why it matters

The allocator receives the already wrapped small block count, so ordinary overflow checks and memory limits do not reject it. Expansion and mixing use b->n_blocks, making the operation substantially less memory-hard and nonconforming rather than merely misreporting an allocation. An application must trust externally supplied Balloon parameters for an attacker to turn this into a cost-policy bypass; fixed application-owned parameters are unaffected. The resulting derivation still includes the original s_cost, so it should not be described as identical to an ordinary low-cost parameter set.

Proposed fix

Promote before multiplication, for example computing ((u64)s_cost * 1024) / blklen, then verify that the derived block count, parallelism * n_blocks, and final byte allocation all fit size_t. Apply an explicit supported upper bound before allocating. Add a regression for 4194305 with SHA-256 that requires clean rejection (or the full representable cost), plus boundary/reference-vector tests proving no wrapped parameter runs with a reduced block count.

Revisions and Commits

Event Timeline

werner triaged this task as Normal priority.Tue, Aug 4, 4:55 PM
werner created this task.
werner created this object with visibility "Public (No Login Required)".
werner created this object with edit policy "Contributor (Project)".
gniibe added a subscriber: gniibe.

(an expired) IETF draft for Baloon says:

MIN_SPACECOST: the minimum space cost, which is 0 as an integer.
MAX_SPACECOST: the maximum space cost, which is 32 as an integer.
MIN_TIMECOST: the minimum time cost, which is 1 as an integer.
MAX_TIMECOST: the maximum time cost, which is 16777215 as an integer.
MIN_PARALLELISM: the minimum parallelism, which is 1 as an integer.
MAX_PARALLELISM: the maximum parallelism, which is 16777215 as an integer.

I think that validating these constants and suggested fix of s_cost * 1024 should be added.

gniibe mentioned this in Unknown Object (Maniphest Task).Mon, Aug 10, 3:55 AM
gniibe changed the task status from Open to Testing.Tue, Aug 11, 4:16 AM
gniibe mentioned this in Unknown Object (Maniphest Task).Mon, Aug 24, 8:26 AM
werner shifted this object from the Restricted Space space to the S1 Public space.