peass-ng/PEASS-ng · error · InvalidOperationException
outputLength not a multiple of 8
Error message
outputLength not a multiple of 8
What it means
KeccakDigest.Squeeze throws InvalidOperationException when the requested outputLength in bits is not a whole number of bytes ((outputLength & 7) != 0). The squeeze loop produces bytes only, so a bit-level output length is unsupported. Reached via DoFinal with a partial-bit request.
Source
Thrown at winPEAS/winPEASexe/winPEAS/3rdParty/BouncyCastle/crypto/digests/KeccakDigest.cs:256
ulong mask = (1UL << partial) - 1UL;
state[full] ^= Pack.LE_To_UInt64(dataQueue, off) & mask;
}
}
state[(rate - 1) >> 6] ^= (1UL << 63);
bitsInQueue = 0;
squeezing = true;
}
protected void Squeeze(byte[] output, int offset, long outputLength)
{
if (!squeezing)
{
PadAndSwitchToSqueezingPhase();
}
if ((outputLength & 7L) != 0L)
throw new InvalidOperationException("outputLength not a multiple of 8");
long i = 0;
while (i < outputLength)
{
if (bitsInQueue == 0)
{
KeccakExtract();
}
int partialBlock = (int)System.Math.Min((long)bitsInQueue, outputLength - i);
Array.Copy(dataQueue, (rate - bitsInQueue) >> 3, output, offset + (int)(i >> 3), partialBlock >> 3);
bitsInQueue -= partialBlock;
i += partialBlock;
}
}
private void KeccakAbsorb(byte[] data, int off)
{
int count = rate >> 6;View on GitHub (pinned to 53fb989abc)
Solutions
- Round the requested output length up to a multiple of 8 bits, then truncate the resulting byte array yourself.
- Verify the outputLength parameter passed down from your wrapper is byte-aligned.
- For truncated output, generate the next multiple of 8 bits and copy the needed bytes.
Example fix
// before int outBits = 100; // not a multiple of 8 -> throws Squeeze(output, outBits); // after int outBits = ((100 + 7) / 8) * 8; // 104 byte[] buf = new byte[outBits / 8]; Squeeze(buf, outBits); byte[] truncated = buf.Take(13).ToArray();
Defensive patterns
Strategy: validation
Validate before calling
if ((outputLengthBits & 7L) != 0L)
outputLengthBits = (outputLengthBits + 7) / 8 * 8; // round up to byte boundary Type guard
bool IsByteAligned(long bits) => (bits & 7L) == 0L;
Try / catch
try { Squeeze(buf, outputLengthBits); } catch (InvalidOperationException ex) when (ex.Message.Contains("multiple of 8")) { throw new ArgumentOutOfRangeException(nameof(outputLengthBits), "Must be a multiple of 8"); } Prevention
- Express output sizes in bytes, converting to bits only at the call site.
- Truncate larger byte-aligned outputs in application code instead of asking the digest for bit-level output.
- Assert outputLength % 8 == 0 in tests for custom Keccak configurations.
When it happens
Trigger: Requesting a digest/DoFinal output whose bit length is not a multiple of 8 (e.g. 254 bits instead of 256) through the partial-bits output path.
Common situations: Custom rate/output-size configuration for Keccak where the developer divides bits by 8 incorrectly; truncated-hash schemes computed in bits.
Related errors
- attempt to absorb while squeezing
- must be in the range 1 to 7
- data
- must be in the range 0 to 7
- if 'data' is empty, 'padBits' must be 0
AI-assisted analysis of peass-ng/PEASS-ng@53fb989abc (2026-09-02).
Data as JSON: /api/errors/ff8a89b189ecf6b2.
Report an issue: GitHub.