peass-ng/PEASS-ng · error · ArgumentException

a hexadecimal encoding must have an even number of character

Error message

a hexadecimal encoding must have an even number of characters

What it means

HexEncoder.DecodeStrict requires the decoded region to contain an even number of characters because hex encodes two characters per byte. A odd len throws ArgumentException('a hexadecimal encoding must have an even number of characters', 'len').

Source

Thrown at winPEAS/winPEASexe/winPEAS/3rdParty/BouncyCastle/util/encoders/HexEncoder.cs:223

                length++;
            }

            if (bufOff > 0)
            {
                outStream.Write(buf, 0, bufOff);
            }

            return length;
        }

        internal byte[] DecodeStrict(string str, int off, int len)
        {
            if (null == str)
                throw new ArgumentNullException("str");
            if (off < 0 || len < 0 || off > (str.Length - len))
                throw new IndexOutOfRangeException("invalid offset and/or length specified");
            if (0 != (len & 1))
                throw new ArgumentException("a hexadecimal encoding must have an even number of characters", "len");

            int resultLen = len >> 1;
            byte[] result = new byte[resultLen];

            int strPos = off;
            for (int i = 0; i < resultLen; ++i)
            {
                byte b1 = decodingTable[str[strPos++]];
                byte b2 = decodingTable[str[strPos++]];

                if ((b1 | b2) >= 0x80)
                    throw new IOException("invalid characters encountered in Hex data");

                result[i] = (byte)((b1 << 4) | b2);
            }
            return result;
        }
    }

View on GitHub (pinned to 53fb989abc)

Solutions

  1. Check len % 2 == 0 (and the underlying string length parity) before decoding.
  2. Fix the slice computation so off/len land on 2-character byte boundaries.
  3. If the source is truncated, re-fetch or repair the data instead of decoding half a byte.
  4. Strip prefixes/suffixes (0x, whitespace) so the remaining character count is even.

Example fix

// before
DecodeStrict(s, 0, s.Length); // s.Length == 11 -> throws
// after
if (s.Length % 2 != 0) throw new FormatException("odd-length hex");
DecodeStrict(s, 0, s.Length);
Defensive patterns

Strategy: validation

Validate before calling

if ((len & 1) != 0 || off + len > str.Length) throw new FormatException("hex slice must be even-length and in bounds");

Type guard

static bool IsEvenHexSlice(string s, int off, int len) => off >= 0 && len >= 0 && (len & 1) == 0 && off + len <= s.Length;

Try / catch

try { DecodeStrict(s, off, len); } catch (ArgumentException ex) when (ex.ParamName == "len") { padOrRejectInput(); }

Prevention

When it happens

Trigger: Calling strict decode with an odd len value — e.g. slicing a hex string at the wrong boundary, or the source string itself has odd length (truncated hex).

Common situations: Truncated hex from cut-and-paste or log truncation; string slicing with off-by-one; a leading '0x' stripped only partially leaving odd count.

Related errors


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