Table of Contents

CtrModeTransform Class

Definition

Namespace
Bodu.Security.Cryptography
Assembly
Bodu.Security.Cryptography.dll
Package
Bodu.Security.Cryptography 1.2.0
Source
CtrModeTransform.cs

Applies Counter (CTR) mode to an underlying IBlockCipher, turning it into a synchronous stream cipher. The counter is incremented in big-endian order (rightmost byte first), matching NIST SP 800-38A Section 6.5.

public sealed class CtrModeTransform : IBlockCipherModeTransform, IDisposable
Inheritance
CtrModeTransform
Implements
Inherited Members
Extension Methods

Examples

using System.Security.Cryptography;
using Bodu.Security.Cryptography;

// Most callers should set SymmetricAlgorithm.Mode = CipherBlockMode.CTR instead of using this directly.
using IBlockCipher cipher = new AesBlockCipher(key);

// Initial counter is typically `nonce || zero-counter`; the nonce must never repeat under one key.
byte[] initialCounter = BuildInitialCounter(nonce);
IBlockCipherModeTransform ctr = new CtrModeTransform(cipher, initialCounter);
byte[] ciphertext = new byte[plaintext.Length];
int written = ctr.Transform(plaintext, ciphertext, encrypt: true);

// The same call shape decrypts: encrypt: true / encrypt: false produce identical results.

Remarks

CTR panel - independent counter blocks are encrypted to form a keystream, then XORed with plaintext.

CTR is self-inverse: the same Transform(ReadOnlySpan<byte>, Span<byte>, bool) operation is applied for both encryption and decryption. The cipher's encrypt primitive is always used; the decrypt primitive is never called. See panel 5 of the diagram above: each cell has its own counter block CTRᵢ and no arrows connect one cell to the next - meaning the keystream is trivially parallelisable and supports random-access seeking into the middle of a message.

That independence is also where the sharpest pitfall lives. To protect against keystream reuse, the transform tracks counter wrap-around: once the block-width counter rolls over its full 2^n value space back to zero, the next call to Transform(ReadOnlySpan<byte>, Span<byte>, bool) throws CryptographicException. Reusing a (key, nonce) pair across messages is catastrophic - the XOR of two ciphertexts recovers the XOR of the two plaintexts - so callers must ensure each counter value is used at most once per key.

When to use CTR. The right confidentiality-only mode for new code that needs random access, parallelisable encryption, or a stream-cipher shape - disk encryption layers without authentication, network protocols where authentication is provided separately, and anywhere a precomputed keystream is useful. CTR is also the keystream layer of the major AEAD modes; if you need authentication as well, reach for GcmModeTransform (CTR + GHASH) or EaxModeTransform (CTR + OMAC) directly rather than building it on top of bare CTR.

The counter increment is parallelisable: every block's keystream can be produced independently, so throughput scales with available cores or SIMD width.

Constructors

CtrModeTransform(IBlockCipher, byte[])

Initializes a new instance of the CtrModeTransform class.

public CtrModeTransform(IBlockCipher cipher, byte[] initialCounter)

Parameters

cipher IBlockCipher

The block cipher whose encrypt primitive generates the keystream.

initialCounter byte[]

The starting counter block. Must equal the cipher block size. A defensive copy is taken.

Exceptions

ArgumentNullException

cipher or initialCounter is null.

ArgumentException

initialCounter length does not equal the cipher block size.

Methods

Dispose()

Releases the resources used by this instance and zeroes the retained counter state so that key-equivalent counter values do not linger in memory after disposal. The underlying IBlockCipher is not disposed by this type - ownership remains with the caller.

public void Dispose()

Remarks

Idempotent.

Transform(ReadOnlySpan<byte>, Span<byte>, bool)

Transforms input under the mode's chaining strategy and writes the result to output.

public int Transform(ReadOnlySpan<byte> input, Span<byte> output, bool encrypt)

Parameters

input ReadOnlySpan<byte>

The input data to transform. Its length must be a positive multiple of the underlying cipher block size.

output Span<byte>

The destination span. Its length must be greater than or equal to the length of input.

encrypt bool

true to encrypt the input; false to decrypt.

Returns

int

The number of bytes written to output.

Remarks

Each call consumes one counter block per whole or partial block of input; the unused keystream of a final partial block is discarded rather than carried into the next call. Counter blocks are encrypted a run at a time through EncryptBlocks(ReadOnlySpan<byte>, Span<byte>), except under Serpent128Cipher, whose kernels form the counter blocks in registers and combine their keystream with the input as they store it.

Exceptions

ArgumentException

Thrown when input's length is not a multiple of the block size or when output is too small.

Applies to

ProductVersions
.NET8, 10

See Also