peass-ng/PEASS-ng · error · ArgumentException

must be in the range 1 to 7

Error message

must be in the range 1 to 7

What it means

KeccakDigest.AbsorbBits(int, int) throws ArgumentException when the `bits` parameter is outside 1..7. AbsorbBits exists to absorb a sub-byte (partial byte) quantity; absorbing 0 or 8+ bits makes no sense — 8 bits go through the byte Absorb path. Called from the partial-byte DoFinal path.

Source

Thrown at winPEAS/winPEASexe/winPEAS/3rdParty/BouncyCastle/crypto/digests/KeccakDigest.cs:204

                count += available;
                KeccakAbsorb(dataQueue, 0);
            }

            int remaining;
            while ((remaining = (len - count)) >= rateBytes)
            {
                KeccakAbsorb(data, off + count);
                count += rateBytes;
            }

            Array.Copy(data, off + count, dataQueue, 0, remaining);
            this.bitsInQueue = remaining << 3;
        }

        protected void AbsorbBits(int data, int bits)
        {
            if (bits < 1 || bits > 7)
                throw new ArgumentException("must be in the range 1 to 7", "bits");
            if ((bitsInQueue & 7) != 0)
                throw new InvalidOperationException("attempt to absorb with odd length queue");
            if (squeezing)
                throw new InvalidOperationException("attempt to absorb while squeezing");

            int mask = (1 << bits) - 1;
            dataQueue[bitsInQueue >> 3] = (byte)(data & mask);

            // NOTE: After this, bitsInQueue is no longer a multiple of 8, so no more absorbs will work
            bitsInQueue += bits;
        }

        private void PadAndSwitchToSqueezingPhase()
        {
            Debug.Assert(bitsInQueue < rate);

            dataQueue[bitsInQueue >> 3] |= (byte)(1 << (bitsInQueue & 7));

View on GitHub (pinned to 53fb989abc)

Solutions

  1. Clamp/validate partialBits to 1..7 before calling; when no partial bits remain, use the plain DoFinal overload.
  2. Use plain DoFinal(output, outOff) when input is byte-aligned.
  3. Guard bit-count math so trailing bits are computed as (totalBits % 8) and skipped when 0.

Example fix

// before
int partialBits = totalBits % 8; // can be 0
digest.DoFinal(outBytes, 0, partialByte, partialBits); // throws when 0
// after
if (totalBits % 8 == 0)
    digest.DoFinal(outBytes, 0);
else
    digest.DoFinal(outBytes, 0, partialByte, totalBits % 8);
Defensive patterns

Strategy: validation

Validate before calling

if (partialBits < 1 || partialBits > 7)
    throw new ArgumentOutOfRangeException(nameof(partialBits), "must be in the range 1 to 7");
digest.DoFinal(output, outOff, partialByte, partialBits);

Type guard

bool IsValidPartialBits(int bits) => bits >= 1 && bits <= 7;

Try / catch

try { digest.DoFinal(outBuf, 0, partialByte, partialBits); } catch (ArgumentException ex) when (ex.ParamName == "bits") { digest.DoFinal(outBuf, 0); // byte-aligned fallback }

Prevention

When it happens

Trigger: Passing partialBits = 0 or partialBits > 7 to the extended DoFinal(output, outOff, partialByte, partialBits) overload, which forwards to AbsorbBits.

Common situations: Generic hashing wrappers computing partialBits from a bit-length count where the count is byte-aligned (yields 0) or mis-clamped; ported code from APIs that allow 0 partial bits.

Related errors


AI-assisted analysis of peass-ng/PEASS-ng@53fb989abc (2026-09-02). Data as JSON: /api/errors/9abb2572596933c7. Report an issue: GitHub.