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 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
cipherIBlockCipherThe block cipher whose encrypt primitive generates the keystream.
initialCounterbyte[]The starting counter block. Must equal the cipher block size. A defensive copy is taken.
Exceptions
- ArgumentNullException
cipherorinitialCounteris null.- ArgumentException
initialCounterlength 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
inputReadOnlySpan<byte>The input data to transform. Its length must be a positive multiple of the underlying cipher block size.
outputSpan<byte>The destination span. Its length must be greater than or equal to the length of
input.encryptbool
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 whenoutputis too small.
Applies to
| Product | Versions |
|---|---|
| .NET | 8, 10 |