jstedfast/MailKit · error · ArgumentOutOfRangeException
Can only transform 8 bytes at a time.
Error message
Can only transform 8 bytes at a time.
What it means
DES is a strict 64-bit block cipher, so MailKit's TransformBlock only accepts exactly 8 bytes per call and throws ArgumentOutOfRangeException with message "Can only transform 8 bytes at a time." when inputCount != 8. This follows .NET's block-cipher contract where a block transform processes one block per invocation.
Solutions
- Loop over the input in 8-byte chunks, calling TransformBlock once per chunk.
- Pad input to a multiple of 8 bytes (NTLM usage pads per its spec) or route the final partial block through TransformFinalBlock as appropriate.
- If transforming multiple blocks, call TransformBlock repeatedly rather than passing a larger count.
Example fix
// before
des.TransformBlock(data, 0, data.Length, output, 0); // data.Length may be > 8
// after
for (int i = 0; i + 8 <= data.Length; i += 8)
des.TransformBlock(data, i, 8, output, i); Defensive patterns
Strategy: validation
Validate before calling
if (data.Length % 8 != 0) throw new InvalidOperationException("DES input must be padded to a multiple of 8 bytes");
for (int i = 0; i < data.Length; i += 8)
des.TransformBlock(data, i, 8, output, i); Type guard
static bool IsBlockAligned(byte[] b) => b != null && b.Length % 8 == 0;
Try / catch
try {
des.TransformBlock(data, 0, 8, output, 0);
} catch (ArgumentOutOfRangeException ex) when (ex.Message.Contains("8 bytes")) {
// wrong chunk size: fix the loop stride to 8
} Prevention
- Always use a chunk size of exactly 8 for DES block transforms.
- Pad inputs per the protocol spec (NTLM pads to 8-byte multiples) before transforming.
- Never call a block transform with multi-block counts; loop instead.
When it happens
Trigger: Calling TransformBlock with any inputCount other than 8 (e.g., 16 to 'transform two blocks', or a leftover 3-byte tail of a stream).
Common situations: Trying to process a whole buffer in one call instead of looping in 8-byte chunks; passing a non-padded plaintext length; porting code from a streaming cipher that accepted arbitrary lengths.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
AI-assisted analysis of jstedfast/MailKit@9d3859a785 (2026-09-15).
Data as JSON: /api/errors/e83807fe90b3174b.
Report an issue: GitHub.
Appendix: source
Thrown at MailKit/Security/Ntlm/DES.cs:117
}
public int OutputBlockSize {
get { return 8; }
}
public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputBuffer == null)
throw new ArgumentNullException ("inputBuffer");
if (inputOffset < 0 || inputOffset > inputBuffer.Length)
throw new ArgumentOutOfRangeException ("inputOffset");
if (inputCount < 0 || inputOffset > inputBuffer.Length - inputCount)
throw new ArgumentOutOfRangeException ("inputCount");
if (inputCount != 8)
throw new ArgumentOutOfRangeException ("inputCount", "Can only transform 8 bytes at a time.");
if (outputBuffer == null)
throw new ArgumentNullException ("outputBuffer");
if (outputOffset < 0 || outputOffset > outputBuffer.Length - 8)
throw new ArgumentOutOfRangeException ("outputOffset");
return engine.ProcessBlock (inputBuffer, inputOffset, outputBuffer, outputOffset);
}
public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
{
if (inputBuffer == null)
throw new ArgumentNullException ("inputBuffer");
if (inputOffset < 0 || inputOffset > inputBuffer.Length)
throw new ArgumentOutOfRangeException ("inputOffset");
View on GitHub (pinned to 9d3859a785)