{"record":{"id":"20fc3a7496aa903e","repo":"jstedfast/MailKit","slug":"inputoffset-md4","errorCode":null,"errorMessage":"inputOffset","messagePattern":"inputOffset","errorType":"validation","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"MailKit/Security/Ntlm/MD4.cs","lineNumber":345,"sourceCode":"\n\t\t\tdo {\n\t\t\t\tif ((nread = inputStream.Read (buffer, 0, buffer.Length)) > 0)\n\t\t\t\t\tHashCore (buffer, 0, nread);\n\t\t\t} while (nread > 0);\n\n\t\t\thashValue = HashFinal ();\n\t\t\tInitialize ();\n\n\t\t\treturn hashValue;\n\t\t}\n\n\t\tpublic int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)\n\t\t{\n\t\t\tif (inputBuffer == null)\n\t\t\t\tthrow new ArgumentNullException (nameof (inputBuffer));\n\n\t\t\tif (inputOffset < 0 || inputOffset > inputBuffer.Length)\n\t\t\t\tthrow new ArgumentOutOfRangeException (nameof (inputOffset));\n\n\t\t\tif (inputCount < 0 || inputOffset > inputBuffer.Length - inputCount)\n\t\t\t\tthrow new ArgumentOutOfRangeException (nameof (inputCount));\n\n\t\t\tif (outputBuffer != null) {\n\t\t\t\tif (outputOffset < 0 || outputOffset > outputBuffer.Length - inputCount)\n\t\t\t\t\tthrow new ArgumentOutOfRangeException (nameof (outputOffset));\n\t\t\t}\n\n\t\t\tHashCore (inputBuffer, inputOffset, inputCount);\n\n\t\t\tif (outputBuffer != null)\n\t\t\t\tBuffer.BlockCopy (inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount);\n\n\t\t\treturn inputCount;\n\t\t}\n\n\t\tpublic byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/jstedfast/MailKit/blob/9d3859a7855e3e17582c07fd01972b8e262bf176/MailKit/Security/Ntlm/MD4.cs#L327-L363","documentation":"TransformBlock throws ArgumentOutOfRangeException named \"inputOffset\" when inputOffset is negative or greater than inputBuffer.Length. This keeps the transform's read window within the input array, mirroring ICryptoTransform argument contracts. It is thrown before HashCore mutates state, so incremental hashing remains consistent.","triggerScenarios":"Calling TransformBlock(buf, -1, len, null, 0) or TransformBlock(buf, buf.Length + 1, 0, null, 0); incremental loops where a running offset accumulates past the buffer end due to a wrong increment or stale offset variable.","commonSituations":"Chunked hashing where chunk offsets are computed from previous chunk sizes with an off-by-one; NTLM message assembly code reusing an offset across differently sized buffers.","solutions":["Recompute/validate inputOffset per call: it must satisfy 0 <= inputOffset <= inputBuffer.Length.","Track the running offset from the same buffer being transformed; reset it when switching buffers.","Use safe chunking (offset advances by chunk.Length from 0) instead of manual arithmetic.","Validate externally supplied offsets before the call and reject with a clear message."],"exampleFix":"// before\ntransform.TransformBlock(buf, pos, buf.Length - pos, null, 0); // pos may exceed buf.Length\n// after\nint pos = 0;\nwhile (pos < buf.Length) {\n    int n = Math.Min(4096, buf.Length - pos);\n    transform.TransformBlock(buf, pos, n, null, 0);\n    pos += n;\n}","handlingStrategy":"validation","validationCode":"if (inputOffset < 0 || inputOffset > inputBuffer.Length)\n    throw new ArgumentOutOfRangeException(nameof(inputOffset));","typeGuard":"static bool IsValidOffset(byte[] buf, int offset) => offset >= 0 && offset <= buf.Length;","tryCatchPattern":"try { transform.TransformBlock(buf, offset, count, null, 0); }\ncatch (ArgumentOutOfRangeException ex) when (ex.ParamName == \"inputOffset\") { log.LogError(ex, \"inputOffset {Offset} invalid for len {Len}\", offset, buf.Length); throw; }","preventionTips":["Advance running offsets from the same buffer being transformed","Reset offsets when switching buffers","Favor simple chunk loops (offset += chunkSize from 0) over manual arithmetic"],"tags":["argument-exception","crypto","out-of-range","transformblock"],"backgroundTag":"argument-out-of-range","analyzedSha":"9d3859a7855e3e17582c07fd01972b8e262bf176","analyzedAt":"2026-09-15T15:46:11.592Z","contentChangedAt":"2026-09-15T15:46:11.592Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}