jstedfast/MailKit · error · ArgumentOutOfRangeException

offset

Error message

offset

What it means

ComputeHash(buffer, offset, count) throws ArgumentOutOfRangeException named "offset" when offset is negative or greater than buffer.Length. MailKit's MD4 (its NTLM-supported MD4 hasher, since .NET dropped MD4) mirrors System.Security.Cryptography hash argument validation so callers get the same guards they'd expect from a HashAlgorithm. It fires before any hashing happens, so no partial state is produced.

Solutions

  1. Check the offset value at the call site and clamp/fix it to 0..buffer.Length before calling.
  2. Ensure the offset is into the same array instance actually passed as buffer (not a resized/copied array).
  3. If passing user-derived offsets, validate with a pre-check (offset >= 0 && offset <= buffer.Length) and reject bad input upstream.
  4. Wrap in try/catch (ArgumentOutOfRangeException) only at UI/API boundaries to report bad input cleanly.

Example fix

// before
hasher.ComputeHash(data, offset, count); // offset could be -1
// after
if (offset < 0 || offset > data.Length) throw new ArgumentException("bad offset");
hasher.ComputeHash(data, offset, count);
Defensive patterns

Strategy: validation

Validate before calling

static void ValidateRange(byte[] buffer, int offset, int count) {
    if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException(nameof(offset));
    if (count < 0 || offset > buffer.Length - count) throw new ArgumentOutOfRangeException(nameof(count));
}

Type guard

static bool IsValidWindow(byte[] buffer, int offset, int count) =>
    buffer != null && offset >= 0 && count >= 0 && offset <= buffer.Length && offset <= buffer.Length - count;

Try / catch

try { hash = md4.ComputeHash(data, offset, count); }
catch (ArgumentOutOfRangeException ex) { log.LogError(ex, "Bad hash window: {Param}", ex.ParamName); throw new ArgumentException("Invalid offset/count", ex); }

Prevention

When it happens

Trigger: Calling ComputeHash(buffer, offset, count) with offset < 0, or offset > buffer.Length; e.g. ComputeHash(data, -1, data.Length) or ComputeHash(data, data.Length + 1, 0). Also produced by arithmetic bugs where an offset variable underflows (e.g. baseIndex - amount going negative).

Common situations: Slice/copy logic that computes an offset into a padded or chunked buffer; off-by-one when hashing the tail of a message; porting NTLM/NTLMv2 code where a length prefix was mistakenly added to the offset.

Related errors


AI-assisted analysis of jstedfast/MailKit@9d3859a785 (2026-09-15). Data as JSON: /api/errors/a4223bdba322457e. Report an issue: GitHub.

Appendix: source

Thrown at MailKit/Security/Ntlm/MD4.cs:293

			HH (ref b, c, d, a, x[13], S34); /* 44 */
			HH (ref a, b, c, d, x[ 3], S31); /* 45 */
			HH (ref d, a, b, c, x[11], S32); /* 46 */
			HH (ref c, d, a, b, x[ 7], S33); /* 47 */
			HH (ref b, c, d, a, x[15], S34); /* 48 */

			state [0] += a;
			state [1] += b;
			state [2] += c;
			state [3] += d;
		}

		public byte[] ComputeHash (byte[] buffer, int offset, int count)
		{
			if (buffer == null)
				throw new ArgumentNullException (nameof (buffer));

			if (offset < 0 || offset > buffer.Length)
				throw new ArgumentOutOfRangeException (nameof (offset));

			if (count < 0 || offset > buffer.Length - count)
				throw new ArgumentOutOfRangeException (nameof (count));

			if (disposed)
				throw new ObjectDisposedException (nameof (MD4));

			HashCore (buffer, offset, count);
			hashValue = HashFinal ();
			Initialize ();

			return hashValue;
		}

		public byte[] ComputeHash (byte[] buffer)
		{
			if (buffer == null)
				throw new ArgumentNullException (nameof (buffer));

View on GitHub (pinned to 9d3859a785)