peass-ng/PEASS-ng · error · InvalidOperationException

invalid rate value

Error message

invalid rate value

What it means

InitSponge computes the sponge rate as 1600 - 2*bitLength and requires it to be positive, below 1600, and 64-bit aligned. A rate violating this invariant leaves the Keccak permutation operating on inconsistent parameters, so InitSponge throws InvalidOperationException.

Source

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

            switch (bitLength)
            {
                case 128:
                case 224:
                case 256:
                case 288:
                case 384:
                case 512:
                    InitSponge(1600 - (bitLength << 1));
                    break;
                default:
                    throw new ArgumentException("must be one of 128, 224, 256, 288, 384, or 512.", "bitLength");
            }
        }

        private void InitSponge(int rate)
        {
            if (rate <= 0 || rate >= 1600 || (rate & 63) != 0)
                throw new InvalidOperationException("invalid rate value");

            this.rate = rate;
            Array.Clear(state, 0, state.Length);
            Arrays.Fill(this.dataQueue, (byte)0);
            this.bitsInQueue = 0;
            this.squeezing = false;
            this.fixedOutputLength = (1600 - rate) >> 1;
        }

        protected void Absorb(byte data)
        {
            if ((bitsInQueue & 7) != 0)
                throw new InvalidOperationException("attempt to absorb with odd length queue");
            if (squeezing)
                throw new InvalidOperationException("attempt to absorb while squeezing");

            dataQueue[bitsInQueue >> 3] = data;
            if ((bitsInQueue += 8) == rate)

View on GitHub (pinned to 53fb989abc)

Solutions

  1. Use only standard Keccak bit lengths (128/224/256/288/384/512) so the computed rate is always valid.
  2. If subclassing, ensure bitLength yields 1600 - 2*bitLength in (0, 1600) and 64-byte aligned.
  3. Fix any modified library code so Init's allow-list runs before InitSponge.

Example fix

// before
class CustomKeccak : KeccakDigest { public CustomKeccak() : base(800) { } } // rate = 0
// after
class CustomKeccak : KeccakDigest { public CustomKeccak() : base(256) { } } // rate = 1088
Defensive patterns

Strategy: validation

Validate before calling

int rate = 1600 - (bitLength << 1);
if (rate <= 0 || rate >= 1600 || (rate & 63) != 0)
    throw new ArgumentOutOfRangeException(nameof(bitLength), "bitLength yields invalid sponge rate");
var keccak = new KeccakDigest(bitLength);

Type guard

static bool HasValidRate(int bitLength) { int r = 1600 - (bitLength << 1); return r > 0 && r < 1600 && (r & 63) == 0; }

Try / catch

try { k.BlockUpdate(data, 0, len); }
catch (InvalidOperationException ex) { /* recreate with standard bitLength */ }

Prevention

When it happens

Trigger: InitSponge(rate) called (from Init/constructor paths) with a bitLength that yields rate <= 0, rate >= 1600, or a rate not divisible by 64 — e.g. bitLength >= 800 or a bitLength producing a non-aligned rate. Only reachable if Init's case switch was bypassed or a subclass passes odd bitLengths.

Common situations: Subclassing KeccakDigest with a custom fixedBitLength not in the supported set; forks that relaxed the constructor check; bitLength of 0 or negative from config defaults.

Related errors


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