From b50438899e231d8c8f38343e16ee32eb01335cf0 Mon Sep 17 00:00:00 2001
From: Frans van Dorsselaer <17404029+dorssel@users.noreply.github.com>
Date: Tue, 14 Jan 2025 02:52:23 +0100
Subject: [PATCH] Improve constructors and CryptoConfig support
---
AesExtra/AesCmac.cs | 234 ++++++++++---
AesExtra/AesCtr.cs | 443 +++++++++++++++++++++---
AesExtra/AesSiv.cs | 11 +-
UnitTests/AesCmac_KAT.cs | 3 +-
UnitTests/AesCmac_Tests.cs | 117 ++++++-
UnitTests/AesCtr_KAT.cs | 40 +--
UnitTests/AesCtr_Tests.cs | 407 +++++++++++++++++++---
UnitTests/NistAesCtrSampleTestVector.cs | 110 +++---
UnitTests/RfcAesSivTestVector.cs | 38 +-
9 files changed, 1137 insertions(+), 266 deletions(-)
diff --git a/AesExtra/AesCmac.cs b/AesExtra/AesCmac.cs
index 63cadfe..6a25c13 100644
--- a/AesExtra/AesCmac.cs
+++ b/AesExtra/AesCmac.cs
@@ -6,6 +6,7 @@
using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
using System.Security.Cryptography;
namespace Dorssel.Security.Cryptography;
@@ -21,8 +22,35 @@ public sealed class AesCmac
const int BLOCKSIZE = 16; // bytes
const int BitsPerByte = 8;
+ #region CryptoConfig
+ static readonly object RegistrationLock = new();
+ static bool TriedRegisterOnce;
+
+ ///
+ /// Registers the class with , such that it can be created by name.
+ ///
+ ///
+ ///
+ /// is not supported in browsers.
+ ///
+#if !NETSTANDARD2_0
+ [UnsupportedOSPlatform("browser")]
+#endif
+ public static void RegisterWithCryptoConfig()
+ {
+ lock (RegistrationLock)
+ {
+ if (!TriedRegisterOnce)
+ {
+ TriedRegisterOnce = true;
+ CryptoConfig.AddAlgorithm(typeof(AesCmac), nameof(AesCmac), typeof(AesCmac).FullName!);
+ }
+ }
+ }
+
///
/// A new instance.
+ [Obsolete("Use one of the constructors instead.")]
public static new AesCmac Create()
{
return new AesCmac();
@@ -33,86 +61,196 @@ public sealed class AesCmac
#if !NETSTANDARD2_0
[RequiresUnreferencedCode("The default algorithm implementations might be removed, use strong type references like 'RSA.Create()' instead.")]
#endif
- public static new KeyedHashAlgorithm? Create(string algorithmName)
+ public static new AesCmac? Create(string algorithmName)
+ {
+ if (algorithmName is null)
+ {
+ throw new ArgumentNullException(nameof(algorithmName));
+ }
+ // Our class is sealed, so there definitely is no other implementation.
+ return algorithmName == nameof(AesCmac) || algorithmName == typeof(AesCmac).FullName! ? new AesCmac() : null;
+ }
+ #endregion
+
+ /// is other than 128, 192, or 256 bits.
+ static void ThrowIfInvalidKeySize(int keySize)
+ {
+ if (keySize is not (128 or 192 or 256))
+ {
+ throw new CryptographicException("Specified key size is valid for this algorithm.");
+ }
+ }
+
+ /// The length is other than 16, 24, or 32 bytes (128, 192, or 256 bits).
+ static void ThrowIfInvalidKey(ReadOnlySpan key)
+ {
+ if (key.Length is not (16 or 24 or 32))
+ {
+ throw new CryptographicException("Specified key is not a valid size for this algorithm.");
+ }
+ }
+
+ /// is .
+ ///
+ static void ThrowIfInvalidKey(byte[] key)
+ {
+ if (key is null)
+ {
+ throw new ArgumentNullException(nameof(key));
+ }
+ ThrowIfInvalidKey(key.AsSpan());
+ }
+
+ void InitializeFixedValues()
+ {
+ HashSizeValue = BLOCKSIZE * 8;
+ }
+
+ ///
+ /// Initializes a new instance of the class with a randomly generated 256-bit key.
+ ///
+ public AesCmac()
+ : this(256)
{
- return algorithmName == nameof(AesCmac) ? Create() : KeyedHashAlgorithm.Create(algorithmName);
}
///
/// Initializes a new instance of the class with a randomly generated key.
///
/// The size, in bits, of the randomly generated key.
- public AesCmac(int keySize = 256)
+ ///
+ public AesCmac(int keySize)
{
- AesEcb = Aes.Create();
- AesEcb.Mode = CipherMode.ECB; // DevSkim: ignore DS187371
- AesEcb.BlockSize = BLOCKSIZE * BitsPerByte;
- AesEcb.KeySize = keySize;
- HashSizeValue = BLOCKSIZE * 8;
+ ThrowIfInvalidKeySize(keySize);
+
+ InitializeFixedValues();
+
+ KeyValue = new byte[keySize / BitsPerByte];
+ using var rng = RandomNumberGenerator.Create();
+ rng.GetBytes(KeyValue);
}
///
/// Initializes a new instance of the class with the specified key data.
///
/// The secret key for AES-CMAC algorithm.
+ /// is .
+ ///
public AesCmac(byte[] key)
- : this()
+ : this(new ReadOnlySpan(key ?? throw new ArgumentNullException(nameof(key))))
{
- Key = key;
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified key data.
+ ///
+ /// The secret key for AES-CMAC algorithm.
+ ///
+ public AesCmac(ReadOnlySpan key)
+ {
+ ThrowIfInvalidKey(key);
+
+ InitializeFixedValues();
+
+ KeyValue = key.ToArray();
}
#region IDisposable
+ bool IsDisposed;
+
///
protected override void Dispose(bool disposing)
{
+ if (IsDisposed)
+ {
+ return;
+ }
+
if (disposing)
{
- CryptographicOperations.ZeroMemory(KeyValue);
- CryptographicOperations.ZeroMemory(K1Value);
- CryptographicOperations.ZeroMemory(K2Value);
- CryptographicOperations.ZeroMemory(C);
- CryptographicOperations.ZeroMemory(Partial);
- AesEcb.Dispose();
- CryptoTransformValue?.Dispose();
- CryptoTransformValue = null;
- K1Value = null;
- K2Value = null;
- PartialLength = 0;
- State = 0;
+ AesEcbTransformValue?.Dispose();
}
+
+ CryptographicOperations.ZeroMemory(KeyValue);
+ CryptographicOperations.ZeroMemory(K1Value);
+ CryptographicOperations.ZeroMemory(K2Value);
+ CryptographicOperations.ZeroMemory(C);
+ CryptographicOperations.ZeroMemory(Partial);
+ K1Value = null;
+ K2Value = null;
+ PartialLength = 0;
+ State = 0;
+ AesEcbTransformValue = null;
+ IsDisposed = true;
+
base.Dispose(disposing);
}
#endregion
+ /// The instance has been disposed.
+ void ThrowIfDisposed()
+ {
+ if (IsDisposed)
+ {
+ throw new ObjectDisposedException(nameof(AesCmac));
+ }
+ }
+
///
+ ///
+ ///
+ /// An attempt was made to change the during a computation.
public override byte[] Key
{
- get => AesEcb.Key;
+ get
+ {
+ ThrowIfDisposed();
+
+ return (byte[])KeyValue.Clone();
+ }
set
{
+ // Input validation
+
+ ThrowIfInvalidKey(value);
+
+ // State validation
+
+ ThrowIfDisposed();
+
if (State != 0)
{
throw new InvalidOperationException("Key cannot be changed during a computation.");
}
- AesEcb.Key = value;
+
+ // Side effects
+
+ CryptographicOperations.ZeroMemory(KeyValue);
CryptographicOperations.ZeroMemory(K1Value);
CryptographicOperations.ZeroMemory(K2Value);
- CryptoTransformValue?.Dispose();
- CryptoTransformValue = null;
+ AesEcbTransformValue?.Dispose();
+ AesEcbTransformValue = null;
K1Value = null;
K2Value = null;
+
+ KeyValue = (byte[])value.Clone();
}
}
- readonly Aes AesEcb;
- ICryptoTransform? CryptoTransformValue;
+ ICryptoTransform? AesEcbTransformValue;
- ICryptoTransform CryptoTransform
+ ICryptoTransform AesEcbTransform
{
get
{
- CryptoTransformValue ??= AesEcb.CreateEncryptor();
- return CryptoTransformValue;
+ if (AesEcbTransformValue is null)
+ {
+ using var aes = Aes.Create();
+ aes.Mode = CipherMode.ECB; // DevSkim: ignore DS187371
+ aes.BlockSize = BLOCKSIZE * BitsPerByte;
+ AesEcbTransformValue = aes.CreateEncryptor(KeyValue, null);
+ }
+ return AesEcbTransformValue;
}
}
@@ -161,12 +299,15 @@ byte[] K2
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void CIPH_K_InPlace(byte[] X)
{
- _ = CryptoTransform.TransformBlock(X, 0, BLOCKSIZE, X, 0);
+ _ = AesEcbTransform.TransformBlock(X, 0, BLOCKSIZE, X, 0);
}
///
+ ///
public override void Initialize()
{
+ ThrowIfDisposed();
+
// See: NIST SP 800-38B, Section 6.2, Step 5
C.AsSpan().Clear();
PartialLength = 0;
@@ -187,6 +328,9 @@ void AddBlock(ReadOnlySpan block)
///
protected override void HashCore(byte[] array, int ibStart, int cbSize)
{
+ // This is only called by HashAlgorithm, which is known to behave well.
+ // We skip input validation for performance reasons; there is no unsafe code.
+
UncheckedHashCore(array.AsSpan(ibStart, cbSize));
}
@@ -196,6 +340,9 @@ protected override
#endif
void HashCore(ReadOnlySpan source)
{
+ // This is only called by HashAlgorithm, which is known to behave well.
+ // We skip input validation for performance reasons; there is no unsafe code.
+
UncheckedHashCore(source);
}
@@ -258,6 +405,9 @@ protected override
#endif
bool TryHashFinal(Span destination, out int bytesWritten)
{
+ // This is only called by HashAlgorithm, which promises to never call us with a destination that is too short.
+ // We skip input validation for performance reasons; there is no unsafe code.
+
UncheckedHashFinal(destination);
bytesWritten = BLOCKSIZE;
return true;
@@ -345,26 +495,6 @@ static async ValueTask UncheckedOneShotAsync(byte[] key, Stream source, MemoryThe length is other than 16, 24, or 32 bytes (128, 192, or 256 bits).
- static void ThrowIfInvalidKey(ReadOnlySpan key)
- {
- if (key.Length is not (16 or 24 or 32))
- {
- throw new CryptographicException("Specified key is not a valid size for this algorithm.", nameof(key));
- }
- }
-
- /// is .
- ///
- static void ThrowIfInvalidKey(byte[] key)
- {
- if (key is null)
- {
- throw new ArgumentNullException(nameof(key));
- }
- ThrowIfInvalidKey(key.AsSpan());
- }
-
/// is .
static void ThrowIfInvalidSource(byte[] source)
{
diff --git a/AesExtra/AesCtr.cs b/AesExtra/AesCtr.cs
index cb96209..87c66e2 100644
--- a/AesExtra/AesCtr.cs
+++ b/AesExtra/AesCtr.cs
@@ -2,8 +2,8 @@
//
// SPDX-License-Identifier: MIT
-using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using System.Runtime.Versioning;
using System.Security.Cryptography;
namespace Dorssel.Security.Cryptography;
@@ -21,7 +21,34 @@ public sealed class AesCtr
const PaddingMode FixedPaddingValue = PaddingMode.None;
const int FixedFeedbackSizeValue = BLOCKSIZE * BitsPerByte;
+ #region CryptoConfig
+ static readonly object RegistrationLock = new();
+ static bool TriedRegisterOnce;
+
+ ///
+ /// Registers the class with , such that it can be created by name.
+ ///
+ ///
+ ///
+ /// is not supported in browsers.
+ ///
+#if !NETSTANDARD2_0
+ [UnsupportedOSPlatform("browser")]
+#endif
+ public static void RegisterWithCryptoConfig()
+ {
+ lock (RegistrationLock)
+ {
+ if (!TriedRegisterOnce)
+ {
+ TriedRegisterOnce = true;
+ CryptoConfig.AddAlgorithm(typeof(AesCtr), nameof(AesCtr), typeof(AesCtr).FullName!);
+ }
+ }
+ }
+
///
+ [Obsolete("Use one of the constructors instead.")]
public static new AesCtr Create()
{
return new AesCtr();
@@ -32,14 +59,72 @@ public sealed class AesCtr
#if !NETSTANDARD2_0
[RequiresUnreferencedCode("The default algorithm implementations might be removed, use strong type references like 'RSA.Create()' instead.")]
#endif
- public static new Aes? Create(string algorithmName)
+ public static new AesCtr? Create(string algorithmName)
+ {
+ if (algorithmName is null)
+ {
+ throw new ArgumentNullException(nameof(algorithmName));
+ }
+ // Our class is sealed, so there definitely is no other implementation.
+ return algorithmName == nameof(AesCtr) || algorithmName == typeof(AesCtr).FullName! ? new AesCtr() : null;
+ }
+ #endregion
+
+ /// is other than 128, 192, or 256 bits.
+ static void ThrowIfInvalidKeySize(int keySize)
{
- return algorithmName == nameof(AesCtr) ? Create() : Aes.Create(algorithmName);
+ if (keySize is not (128 or 192 or 256))
+ {
+ throw new CryptographicException("Specified key size is valid for this algorithm.");
+ }
}
- AesCtr()
+ /// The length is other than 16, 24, or 32 bytes (128, 192, or 256 bits).
+ static void ThrowIfInvalidKey(ReadOnlySpan key)
+ {
+ if (key.Length is not (16 or 24 or 32))
+ {
+ throw new CryptographicException("Specified key is not a valid size for this algorithm.");
+ }
+ }
+
+ /// is .
+ ///
+ static void ThrowIfInvalidKey(byte[] key, string argumentName = "key")
+ {
+ if (key is null)
+ {
+ throw new ArgumentNullException(argumentName);
+ }
+ ThrowIfInvalidKey(key.AsSpan());
+ }
+
+ /// is .
+ ///
+ static void ThrowIfInvalidIV(byte[] iv, string argumentName = "iv")
+ {
+ if (iv is null)
+ {
+ throw new ArgumentNullException(argumentName);
+ }
+ ThrowIfInvalidIV(iv.AsSpan());
+ }
+
+ ///
+ /// is the incorrect length.
+ /// Callers are expected to pass an initialization vector that is exactly in length,
+ /// converted to bytes (`BlockSize / 8`).
+ ///
+ static void ThrowIfInvalidIV(ReadOnlySpan iv, string argumentName = "iv")
+ {
+ if (iv.Length != BLOCKSIZE)
+ {
+ throw new ArgumentException("Specified initial counter (IV) does not match the block size for this algorithm.", argumentName);
+ }
+ }
+
+ void InitializeFixedValues()
{
- KeySizeValue = 256;
ModeValue = FixedModeValue;
PaddingValue = FixedPaddingValue;
FeedbackSizeValue = FixedFeedbackSizeValue;
@@ -48,18 +133,211 @@ public sealed class AesCtr
LegalKeySizesValue = [new(128, 256, 64)];
}
- #region IDisposable
- ///
- protected override void Dispose(bool disposing)
+ ///
+ /// Initializes a new instance of the class with a randomly generated 256-bit key and an initial counter of zero.
+ ///
+ public AesCtr()
+ : this(256)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a randomly generated key and an initial counter of zero.
+ ///
+ /// The size, in bits, of the randomly generated key.
+ ///
+ public AesCtr(int keySize)
+ {
+ ThrowIfInvalidKeySize(keySize);
+
+ InitializeFixedValues();
+
+ KeySizeValue = keySize;
+ IVValue = new byte[BLOCKSIZE];
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified key data and a randomly generated initial counter.
+ ///
+ /// The secret key for the AES-CTR algorithm.
+ /// is .
+ ///
+ public AesCtr(byte[] key)
+ : this(new ReadOnlySpan(key ?? throw new ArgumentNullException(nameof(key))))
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified key data and a randomly generated initial counter.
+ ///
+ /// The secret key for the AES-CTR algorithm.
+ public AesCtr(ReadOnlySpan key)
+ {
+ ThrowIfInvalidKey(key);
+
+ InitializeFixedValues();
+
+ KeyValue = key.ToArray();
+ KeySizeValue = key.Length * BitsPerByte;
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified key data and initial counter.
+ ///
+ /// The secret key for the AES-CTR algorithm.
+ /// The initialization vector (initial counter).
+ /// is .
+ /// is .
+ ///
+ public AesCtr(byte[] key, byte[] iv) :
+ this(new ReadOnlySpan(key ?? throw new ArgumentNullException(nameof(key))),
+ new ReadOnlySpan(iv ?? throw new ArgumentNullException(nameof(iv))))
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified key data and initial counter.
+ ///
+ /// The secret key for the AES-CTR algorithm.
+ /// The initialization vector (initial counter).
+ ///
+ ///
+ public AesCtr(ReadOnlySpan key, ReadOnlySpan iv)
+ {
+ ThrowIfInvalidKey(key);
+ ThrowIfInvalidIV(iv);
+
+ InitializeFixedValues();
+
+ KeyValue = key.ToArray();
+ KeySizeValue = key.Length * BitsPerByte;
+ IVValue = iv.ToArray();
+ }
+
+ void PurgeKeyValue()
{
CryptographicOperations.ZeroMemory(KeyValue);
KeyValue = null;
+ }
+
+ void PurgeIVValue()
+ {
CryptographicOperations.ZeroMemory(IVValue);
IVValue = null;
+ }
+
+ #region IDisposable
+ bool IsDisposed;
+
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ if (IsDisposed)
+ {
+ return;
+ }
+
+ PurgeKeyValue();
+ PurgeIVValue();
+ IsDisposed = true;
+
base.Dispose(disposing);
}
#endregion
+ /// The instance has been disposed.
+ void ThrowIfDisposed()
+ {
+ if (IsDisposed)
+ {
+ throw new ObjectDisposedException(nameof(AesCtr));
+ }
+ }
+
+ ///
+ ///
+ ///
+ /// Setting this property always resets the key to a new random value, even if the key size
+ /// is set to current value.
+ ///
+ ///
+ ///
+ public override int KeySize
+ {
+ get
+ {
+ ThrowIfDisposed();
+
+ return KeySizeValue;
+ }
+
+ set
+ {
+ ThrowIfInvalidKeySize(value);
+
+ ThrowIfDisposed();
+
+ PurgeKeyValue();
+ KeySizeValue = value;
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public override byte[] Key
+ {
+ get
+ {
+ ThrowIfDisposed();
+
+ UncheckedGenerateKeyValueIfNull();
+ return (byte[])KeyValue!.Clone();
+ }
+
+ set
+ {
+ ThrowIfInvalidKey(value, nameof(Key));
+
+ ThrowIfDisposed();
+
+ PurgeKeyValue();
+ KeySizeValue = value.Length * 8;
+
+ KeyValue = (byte[])value.Clone();
+ }
+ }
+
+ ///
+ ///
+ ///
+ /// For AES-CTR, the initialization vector (IV) is the initial counter.
+ ///
+ ///
+ ///
+ public override byte[] IV
+ {
+ get
+ {
+ ThrowIfDisposed();
+
+ UncheckedGenerateIVValueIfNull();
+ return (byte[])IVValue!.Clone();
+ }
+
+ set
+ {
+ ThrowIfInvalidIV(value, nameof(IV));
+
+ ThrowIfDisposed();
+
+ PurgeIVValue();
+
+ IVValue = (byte[])value.Clone();
+ }
+ }
+
///
/// always pretends to use .
public override CipherMode Mode
@@ -102,41 +380,106 @@ public override int FeedbackSize
}
}
- // CTR.Encrypt === CTR.Decrypt; the transform is entirely symmetric.
- static AesCtrTransform CreateTransform(byte[] rgbKey, byte[]? rgbIV)
+ ///
+ ///
+ public override ICryptoTransform CreateDecryptor()
{
- return rgbIV is not null ? new(rgbKey, rgbIV)
- : throw new CryptographicException("The cipher mode specified requires that an initialization vector(IV) be used.");
+ ThrowIfDisposed();
+
+ UncheckedGenerateKeyValueIfNull();
+ UncheckedGenerateIVValueIfNull();
+ return new AesCtrTransform(KeyValue!, IVValue!);
}
- ///
+ ///
+ /// Creates a symmetric decryptor object with the specified key and initial counter (IV).
+ ///
+ /// The secret key to use for the symmetric algorithm.
+ /// The initialization vector (initial counter).
+ /// A symmetric decryptor object.
+ ///
+ ///
+ ///
public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[]? rgbIV)
{
- return CreateTransform(rgbKey, rgbIV);
+ ThrowIfDisposed();
+
+ ThrowIfInvalidKey(rgbKey, nameof(rgbKey));
+ ThrowIfInvalidIV(rgbIV ?? throw new CryptographicException("The cipher mode specified requires that an initialization vector (IV) be used."),
+ nameof(rgbIV));
+
+ return new AesCtrTransform(rgbKey, rgbIV);
}
- ///
+ ///
+ ///
+ public override ICryptoTransform CreateEncryptor()
+ {
+ ThrowIfDisposed();
+
+ UncheckedGenerateKeyValueIfNull();
+ UncheckedGenerateIVValueIfNull();
+ return new AesCtrTransform(KeyValue!, IVValue!);
+ }
+
+ ///
+ /// Creates a symmetric encryptor object with the specified key and initial counter (IV).
+ ///
+ /// The secret key to use for the symmetric algorithm.
+ /// The initialization vector (initial counter).
+ /// A symmetric encryptor object.
+ ///
+ ///
+ ///
public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[]? rgbIV)
{
- return CreateTransform(rgbKey, rgbIV);
+ ThrowIfDisposed();
+
+ ThrowIfInvalidKey(rgbKey, nameof(rgbKey));
+ ThrowIfInvalidIV(rgbIV ?? throw new CryptographicException("The cipher mode specified requires that an initialization vector (IV) be used."),
+ nameof(rgbIV));
+
+ return new AesCtrTransform(rgbKey, rgbIV);
+ }
+
+ void UncheckedGenerateIVValueIfNull()
+ {
+ if (IVValue is null)
+ {
+ IVValue = new byte[BLOCKSIZE];
+ using var randomNumberGenerator = RandomNumberGenerator.Create();
+ randomNumberGenerator.GetBytes(IVValue);
+ }
}
///
+ ///
public override void GenerateIV()
{
- CryptographicOperations.ZeroMemory(IVValue);
- using var randomNumberGenerator = RandomNumberGenerator.Create();
- IVValue = new byte[BLOCKSIZE];
- randomNumberGenerator.GetBytes(IVValue);
+ ThrowIfDisposed();
+
+ PurgeIVValue();
+ UncheckedGenerateIVValueIfNull();
+ }
+
+ void UncheckedGenerateKeyValueIfNull()
+ {
+ if (KeyValue is null)
+ {
+ KeyValue = new byte[KeySizeValue / BitsPerByte];
+ using var randomNumberGenerator = RandomNumberGenerator.Create();
+ randomNumberGenerator.GetBytes(KeyValue);
+ }
}
///
+ ///
public override void GenerateKey()
{
- CryptographicOperations.ZeroMemory(KeyValue);
- using var randomNumberGenerator = RandomNumberGenerator.Create();
- KeyValue = new byte[KeySize / BitsPerByte];
- randomNumberGenerator.GetBytes(KeyValue);
+ ThrowIfDisposed();
+
+ PurgeKeyValue();
+ UncheckedGenerateKeyValueIfNull();
}
#region Modern_SymmetricAlgorithm
@@ -149,30 +492,6 @@ static void ThrowIfInvalidInput(byte[] input)
}
}
- /// is .
- ///
- static void ThrowIfInvalidIV(byte[] iv)
- {
- if (iv is null)
- {
- throw new ArgumentNullException(nameof(iv));
- }
- ThrowIfInvalidIV(iv.AsSpan());
- }
-
- ///
- /// is the incorrect length.
- /// Callers are expected to pass an initialization vector that is exactly in length,
- /// converted to bytes (`BlockSize / 8`).
- ///
- static void ThrowIfInvalidIV(ReadOnlySpan iv)
- {
- if (iv.Length != BLOCKSIZE)
- {
- throw new ArgumentException("Specified initial counter (IV) does not match the block size for this algorithm.", nameof(iv));
- }
- }
-
/// The buffer in is too small to hold the transformed data.
static void ThrowIfInvalidDestination(Span destination, int requiredLength)
{
@@ -189,14 +508,17 @@ static void ThrowIfInvalidDestination(Span destination, int requiredLength
/// The initialization vector (initial counter).
/// The transformed data.
///
- ///
+ ///
public byte[] TransformCtr(byte[] input, byte[] iv)
{
ThrowIfInvalidInput(input);
ThrowIfInvalidIV(iv);
+ ThrowIfDisposed();
+
var output = new byte[input.Length];
- using var transform = new AesCtrTransform(Key, iv);
+ UncheckedGenerateKeyValueIfNull();
+ using var transform = new AesCtrTransform(KeyValue!, iv);
transform.UncheckedTransform(input, output);
return output;
}
@@ -207,13 +529,16 @@ public byte[] TransformCtr(byte[] input, byte[] iv)
/// The data to transform.
/// The initialization vector (initial counter).
/// The transformed data.
- ///
+ ///
public byte[] TransformCtr(ReadOnlySpan input, ReadOnlySpan iv)
{
ThrowIfInvalidIV(iv);
+ ThrowIfDisposed();
+
var output = new byte[input.Length];
- using var transform = new AesCtrTransform(Key, iv);
+ UncheckedGenerateKeyValueIfNull();
+ using var transform = new AesCtrTransform(KeyValue!, iv);
transform.UncheckedTransform(input, output);
return output;
}
@@ -225,14 +550,17 @@ public byte[] TransformCtr(ReadOnlySpan input, ReadOnlySpan iv)
/// The initialization vector (initial counter).
/// The buffer to receive the transformed data.
/// The total number of bytes written to .
- ///
+ ///
///
public int TransformCtr(ReadOnlySpan input, ReadOnlySpan iv, Span destination)
{
ThrowIfInvalidIV(iv);
ThrowIfInvalidDestination(destination, input.Length);
- using var transform = new AesCtrTransform(Key, iv);
+ ThrowIfDisposed();
+
+ UncheckedGenerateKeyValueIfNull();
+ using var transform = new AesCtrTransform(KeyValue!, iv);
transform.UncheckedTransform(input, destination);
return input.Length;
}
@@ -247,18 +575,21 @@ public int TransformCtr(ReadOnlySpan input, ReadOnlySpan iv, Span
/// if was large enough to receive the transformed data; otherwise, .
///
- ///
+ ///
public bool TryTransformCtr(ReadOnlySpan input, ReadOnlySpan iv, Span destination, out int bytesWritten)
{
ThrowIfInvalidIV(iv);
+ ThrowIfDisposed();
+
if (destination.Length < input.Length)
{
bytesWritten = 0;
return false;
}
- using var transform = new AesCtrTransform(Key, iv);
+ UncheckedGenerateKeyValueIfNull();
+ using var transform = new AesCtrTransform(KeyValue!, iv);
transform.UncheckedTransform(input, destination);
bytesWritten = input.Length;
return true;
diff --git a/AesExtra/AesSiv.cs b/AesExtra/AesSiv.cs
index de7d98c..e856b8f 100644
--- a/AesExtra/AesSiv.cs
+++ b/AesExtra/AesSiv.cs
@@ -17,7 +17,7 @@ public sealed class AesSiv
/// Initializes a new instance of the class with a provided key.
///
/// The secret key to use for this instance.
- ///
+ /// is .
public AesSiv(byte[] key)
: this(new ReadOnlySpan(key ?? throw new ArgumentNullException(nameof(key))))
{
@@ -31,7 +31,7 @@ public AesSiv(ReadOnlySpan key)
{
if (key.Length is not (32 or 48 or 64))
{
- throw new CryptographicException("Specified key is not a valid size for this algorithm.", nameof(key));
+ throw new CryptographicException("Specified key is not a valid size for this algorithm.");
}
using var cmacKey = new SecureByteArray(key[..(key.Length / 2)]);
@@ -64,6 +64,7 @@ public void Dispose()
}
#endregion
+ /// The instance has been disposed.
void ThrowIfDisposed()
{
if (IsDisposed)
@@ -219,6 +220,7 @@ static void ThrowIfInvalidAssociatedData(ReadOnlySpan> asso
///
///
///
+ ///
public void Encrypt(byte[] plaintext, byte[] ciphertext, params byte[][] associatedData)
{
// Input validation
@@ -258,6 +260,7 @@ public void Encrypt(byte[] plaintext, byte[] ciphertext, params byte[][] associa
/// The byte array to receive the encrypted contents, prepended with the synthetic IV.
/// Extra data associated with this message, which must also be provided during decryption.
///
+ ///
public void Encrypt(ReadOnlySpan plaintext, Span ciphertext, ReadOnlySpan associatedData)
{
// Input validation
@@ -289,6 +292,7 @@ public void Encrypt(ReadOnlySpan plaintext, Span ciphertext, ReadOnl
/// Extra data associated with this message, which must also be provided during decryption.
///
///
+ ///
public void Encrypt(ReadOnlySpan plaintext, Span ciphertext, params ReadOnlySpan> associatedData)
{
// Input validation
@@ -326,6 +330,7 @@ public void Encrypt(ReadOnlySpan plaintext, Span ciphertext, params
///
///
///
+ ///
/// The tag value could not be verified.
public void Decrypt(byte[] ciphertext, byte[] plaintext, params byte[][] associatedData)
{
@@ -373,6 +378,7 @@ public void Decrypt(byte[] ciphertext, byte[] plaintext, params byte[][] associa
/// Extra data associated with this message, which must match the value provided during encryption.
///
///
+ ///
/// The tag value could not be verified.
public void Decrypt(ReadOnlySpan ciphertext, Span plaintext, ReadOnlySpan associatedData)
{
@@ -413,6 +419,7 @@ public void Decrypt(ReadOnlySpan ciphertext, Span plaintext, ReadOnl
///
///
///
+ ///
/// The tag value could not be verified.
public void Decrypt(ReadOnlySpan ciphertext, Span plaintext, params ReadOnlySpan> associatedData)
{
diff --git a/UnitTests/AesCmac_KAT.cs b/UnitTests/AesCmac_KAT.cs
index 84c971a..d1eb952 100644
--- a/UnitTests/AesCmac_KAT.cs
+++ b/UnitTests/AesCmac_KAT.cs
@@ -12,8 +12,7 @@ sealed class AesCmac_KAT
[NistAesCmacSampleDataSource]
public void NistExample_ComputeHash(NistAesCmacSampleTestVector testVector)
{
- using var aesCmac = AesCmac.Create();
- aesCmac.Key = testVector.Key.ToArray();
+ using var aesCmac = new AesCmac(testVector.Key.Span);
var tag = aesCmac.ComputeHash(testVector.PT.ToArray());
CollectionAssert.AreEqual(testVector.Tag.ToArray(), tag);
}
diff --git a/UnitTests/AesCmac_Tests.cs b/UnitTests/AesCmac_Tests.cs
index 8a38ea4..0dcde0a 100644
--- a/UnitTests/AesCmac_Tests.cs
+++ b/UnitTests/AesCmac_Tests.cs
@@ -68,20 +68,48 @@ public override void Write(byte[] buffer, int offset, int count)
}
}
+ [TestMethod]
+ public void RegisterWithCryptoConfig()
+ {
+ AesCmac.RegisterWithCryptoConfig();
+ using var aesCmac = (AesCmac?)CryptoConfig.CreateFromName("AesCmac");
+ Assert.IsNotNull(aesCmac);
+ }
+
+ [TestMethod]
+ public void RegisterWithCryptoConfig_Twice()
+ {
+ AesCmac.RegisterWithCryptoConfig();
+ AesCmac.RegisterWithCryptoConfig();
+ using var aesCmac = (AesCmac?)CryptoConfig.CreateFromName("Dorssel.Security.Cryptography.AesCmac");
+ Assert.IsNotNull(aesCmac);
+ }
+
[TestMethod]
public void Create()
{
- using var keyedHashAlgorithm = AesCmac.Create();
- Assert.IsNotNull(keyedHashAlgorithm);
+#pragma warning disable CS0618 // Type or member is obsolete
+ using var aesCmac = AesCmac.Create();
+#pragma warning restore CS0618 // Type or member is obsolete
+ Assert.IsNotNull(aesCmac);
}
[TestMethod]
public void Create_Name()
{
#pragma warning disable CS0618 // Type or member is obsolete
- using var keyedHashAlgorithm = AesCmac.Create("AesCmac");
+ using var aesCmac = AesCmac.Create("AesCmac");
+#pragma warning restore CS0618 // Type or member is obsolete
+ Assert.IsNotNull(aesCmac);
+ }
+
+ [TestMethod]
+ public void Create_FullName()
+ {
+#pragma warning disable CS0618 // Type or member is obsolete
+ using var aesCmac = AesCmac.Create("Dorssel.Security.Cryptography.AesCmac");
#pragma warning restore CS0618 // Type or member is obsolete
- Assert.IsNotNull(keyedHashAlgorithm);
+ Assert.IsNotNull(aesCmac);
}
[TestMethod]
@@ -90,7 +118,7 @@ public void Create_NullNameFails()
Assert.ThrowsException(() =>
{
#pragma warning disable CS0618 // Type or member is obsolete
- using var keyedHashAlgorithm = AesCmac.Create(null!);
+ using var aesCmac = AesCmac.Create(null!);
#pragma warning restore CS0618 // Type or member is obsolete
});
}
@@ -99,37 +127,70 @@ public void Create_NullNameFails()
public void Create_OtherNameReturnsNull()
{
#pragma warning disable CS0618 // Type or member is obsolete
- using var keyedHashAlgorithm = AesCmac.Create("SomeOtherName");
+ using var aesCmac = AesCmac.Create("SomeOtherName");
#pragma warning restore CS0618 // Type or member is obsolete
- Assert.IsNull(keyedHashAlgorithm);
+ Assert.IsNull(aesCmac);
}
[TestMethod]
public void Constructor_Default()
{
using var aesCmac = new AesCmac();
+
+ Assert.AreEqual(256, aesCmac.Key.Length * 8);
+ CollectionAssert.AreNotEqual(new byte[aesCmac.Key.Length], aesCmac.Key);
}
[TestMethod]
[DataRow(128)]
[DataRow(192)]
[DataRow(256)]
- public void Constructor_WithKey(int keySize)
+ public void Constructor_Int(int keySize)
+ {
+ using var aesCmac = new AesCmac(keySize);
+
+ Assert.AreEqual(keySize, aesCmac.Key.Length * 8);
+ CollectionAssert.AreNotEqual(new byte[aesCmac.Key.Length], aesCmac.Key);
+ }
+
+ [TestMethod]
+ [DataRow(0)]
+ [DataRow(1)]
+ [DataRow(16)]
+ [DataRow(24)]
+ [DataRow(32)]
+ public void Constructor_Int_Invalid(int keySize)
+ {
+ Assert.ThrowsException(() =>
+ {
+ using var aesCmac = new AesCmac(keySize);
+ });
+ }
+
+ [TestMethod]
+ [DataRow(128)]
+ [DataRow(192)]
+ [DataRow(256)]
+ public void Constructor_Array(int keySize)
{
using var aesCmac = new AesCmac(new byte[keySize / 8]);
}
[TestMethod]
- public void Constructor_WithInvalidKeySize()
+ [DataRow(0)]
+ [DataRow(16)]
+ [DataRow(24)]
+ [DataRow(32)]
+ public void Constructor_Array_Invalid(int keySize)
{
Assert.ThrowsException(() =>
{
- using var aesCmac = new AesCmac(new byte[42]);
+ using var aesCmac = new AesCmac(new byte[keySize / 8]);
});
}
[TestMethod]
- public void Constructor_WithNullKey()
+ public void Constructor_Array_Null()
{
Assert.ThrowsException(() =>
{
@@ -137,6 +198,28 @@ public void Constructor_WithNullKey()
});
}
+ [TestMethod]
+ [DataRow(128)]
+ [DataRow(192)]
+ [DataRow(256)]
+ public void Constructor_ReadOnlySpan(int keySize)
+ {
+ using var aesCmac = new AesCmac(new byte[keySize / 8].AsSpan());
+ }
+
+ [TestMethod]
+ [DataRow(0)]
+ [DataRow(16)]
+ [DataRow(24)]
+ [DataRow(32)]
+ public void Constructor_ReadOnlySpan_Invalid(int keySize)
+ {
+ Assert.ThrowsException(() =>
+ {
+ using var aesCmac = new AesCmac(new byte[keySize / 8].AsSpan());
+ });
+ }
+
[TestMethod]
public void Dispose()
{
@@ -179,6 +262,18 @@ public void Key_ChangeWhileBusy()
});
}
+ [TestMethod]
+ public void Key_ChangeAfterDispose()
+ {
+ using var aesCmac = new AesCmac();
+ aesCmac.Dispose();
+
+ Assert.ThrowsException(() =>
+ {
+ aesCmac.Key = TestKey;
+ });
+ }
+
[TestMethod]
public void ComputeHash_Segmented()
{
diff --git a/UnitTests/AesCtr_KAT.cs b/UnitTests/AesCtr_KAT.cs
index 0a98408..e36af73 100644
--- a/UnitTests/AesCtr_KAT.cs
+++ b/UnitTests/AesCtr_KAT.cs
@@ -12,9 +12,7 @@ sealed class AesCtr_KAT
[NistAesCtrSampleDataSource]
public void Encrypt_Write(NistAesCtrSampleTestVector testVector)
{
- using var aes = AesCtr.Create();
- aes.Key = testVector.Key.ToArray();
- aes.IV = testVector.InitialCounter.ToArray();
+ using var aes = new AesCtr(testVector.Key.Span, testVector.InitialCounter.Span);
using var plaintextStream = new MemoryStream(testVector.Plaintext.ToArray());
using var ciphertextStream = new MemoryStream();
{
@@ -30,9 +28,7 @@ public void Encrypt_Write(NistAesCtrSampleTestVector testVector)
[NistAesCtrSampleDataSource]
public void Encrypt_Read(NistAesCtrSampleTestVector testVector)
{
- using var aes = AesCtr.Create();
- aes.Key = testVector.Key.ToArray();
- aes.IV = testVector.InitialCounter.ToArray();
+ using var aes = new AesCtr(testVector.Key.Span, testVector.InitialCounter.Span);
using var plaintextStream = new MemoryStream(testVector.Plaintext.ToArray());
using var ciphertextStream = new MemoryStream();
{
@@ -48,9 +44,7 @@ public void Encrypt_Read(NistAesCtrSampleTestVector testVector)
[NistAesCtrSampleDataSource]
public void Decrypt_Write(NistAesCtrSampleTestVector testVector)
{
- using var aes = AesCtr.Create();
- aes.Key = testVector.Key.ToArray();
- aes.IV = testVector.InitialCounter.ToArray();
+ using var aes = new AesCtr(testVector.Key.Span, testVector.InitialCounter.Span);
using var ciphertextStream = new MemoryStream(testVector.Ciphertext.ToArray());
using var plaintextStream = new MemoryStream();
{
@@ -66,9 +60,7 @@ public void Decrypt_Write(NistAesCtrSampleTestVector testVector)
[NistAesCtrSampleDataSource]
public void Decrypt_Read(NistAesCtrSampleTestVector testVector)
{
- using var aes = AesCtr.Create();
- aes.Key = testVector.Key.ToArray();
- aes.IV = testVector.InitialCounter.ToArray();
+ using var aes = new AesCtr(testVector.Key.Span, testVector.InitialCounter.Span);
using var ciphertextStream = new MemoryStream(testVector.Ciphertext.ToArray());
using var plaintextStream = new MemoryStream();
{
@@ -84,8 +76,7 @@ public void Decrypt_Read(NistAesCtrSampleTestVector testVector)
[NistAesCtrSampleDataSource]
public void Encrypt_TransformCtr_Array_Array(NistAesCtrSampleTestVector testVector)
{
- using var aes = AesCtr.Create();
- aes.Key = testVector.Key.ToArray();
+ using var aes = new AesCtr(testVector.Key.Span);
var destination = aes.TransformCtr(testVector.Plaintext.ToArray(), testVector.InitialCounter.ToArray());
@@ -97,8 +88,7 @@ public void Encrypt_TransformCtr_Array_Array(NistAesCtrSampleTestVector testVect
[NistAesCtrSampleDataSource]
public void Encrypt_TransformCtr_ReadOnlySpan_ReadOnlySpan(NistAesCtrSampleTestVector testVector)
{
- using var aes = AesCtr.Create();
- aes.Key = testVector.Key.ToArray();
+ using var aes = new AesCtr(testVector.Key.Span);
var destination = aes.TransformCtr(testVector.Plaintext.Span, testVector.InitialCounter.Span);
@@ -110,8 +100,7 @@ public void Encrypt_TransformCtr_ReadOnlySpan_ReadOnlySpan(NistAesCtrSampleTestV
[NistAesCtrSampleDataSource]
public void Encrypt_TransformCtr_ReadOnlySpan_ReadOnlySpan_Span(NistAesCtrSampleTestVector testVector)
{
- using var aes = AesCtr.Create();
- aes.Key = testVector.Key.ToArray();
+ using var aes = new AesCtr(testVector.Key.Span);
var destination = new byte[testVector.Ciphertext.Length];
var count = aes.TransformCtr(testVector.Plaintext.Span, testVector.InitialCounter.Span, destination);
@@ -125,8 +114,7 @@ public void Encrypt_TransformCtr_ReadOnlySpan_ReadOnlySpan_Span(NistAesCtrSample
[NistAesCtrSampleDataSource]
public void Encrypt_TryTransformCtr(NistAesCtrSampleTestVector testVector)
{
- using var aes = AesCtr.Create();
- aes.Key = testVector.Key.ToArray();
+ using var aes = new AesCtr(testVector.Key.Span);
var destination = new byte[testVector.Ciphertext.Length];
var success = aes.TryTransformCtr(testVector.Plaintext.Span, testVector.InitialCounter.Span, destination, out var bytesWritten);
@@ -141,8 +129,7 @@ public void Encrypt_TryTransformCtr(NistAesCtrSampleTestVector testVector)
[NistAesCtrSampleDataSource]
public void Decrypt_TransformCtr_Array_Array(NistAesCtrSampleTestVector testVector)
{
- using var aes = AesCtr.Create();
- aes.Key = testVector.Key.ToArray();
+ using var aes = new AesCtr(testVector.Key.Span);
var destination = aes.TransformCtr(testVector.Ciphertext.ToArray(), testVector.InitialCounter.ToArray());
@@ -154,8 +141,7 @@ public void Decrypt_TransformCtr_Array_Array(NistAesCtrSampleTestVector testVect
[NistAesCtrSampleDataSource]
public void Decrypt_TransformCtr_ReadOnlySpan_ReadOnlySpan(NistAesCtrSampleTestVector testVector)
{
- using var aes = AesCtr.Create();
- aes.Key = testVector.Key.ToArray();
+ using var aes = new AesCtr(testVector.Key.Span);
var destination = aes.TransformCtr(testVector.Ciphertext.Span, testVector.InitialCounter.Span);
@@ -167,8 +153,7 @@ public void Decrypt_TransformCtr_ReadOnlySpan_ReadOnlySpan(NistAesCtrSampleTestV
[NistAesCtrSampleDataSource]
public void Decrypt_TransformCtr_ReadOnlySpan_ReadOnlySpan_Span(NistAesCtrSampleTestVector testVector)
{
- using var aes = AesCtr.Create();
- aes.Key = testVector.Key.ToArray();
+ using var aes = new AesCtr(testVector.Key.Span);
var destination = new byte[testVector.Plaintext.Length];
var count = aes.TransformCtr(testVector.Ciphertext.Span, testVector.InitialCounter.Span, destination);
@@ -182,8 +167,7 @@ public void Decrypt_TransformCtr_ReadOnlySpan_ReadOnlySpan_Span(NistAesCtrSample
[NistAesCtrSampleDataSource]
public void Decrypt_TryTransformCtr(NistAesCtrSampleTestVector testVector)
{
- using var aes = AesCtr.Create();
- aes.Key = testVector.Key.ToArray();
+ using var aes = new AesCtr(testVector.Key.Span);
var destination = new byte[testVector.Plaintext.Length];
var success = aes.TryTransformCtr(testVector.Ciphertext.Span, testVector.InitialCounter.Span, destination, out var bytesWritten);
diff --git a/UnitTests/AesCtr_Tests.cs b/UnitTests/AesCtr_Tests.cs
index b891a67..8f48aeb 100644
--- a/UnitTests/AesCtr_Tests.cs
+++ b/UnitTests/AesCtr_Tests.cs
@@ -24,15 +24,38 @@ sealed class AesCtr_Tests
static readonly byte[] TestMessage = [1, 2, 3, 4, 5];
- static readonly byte[] TestInvalidIV = new byte[BLOCKSIZE - 1];
+ static readonly byte[] TestIVInvalid = new byte[BLOCKSIZE - 1];
+
+ static byte[] TestKeyNull => null!;
+
+ static byte[] TestIVNull => null!;
[TestMethod]
- public void Create()
+ public void RegisterWithCryptoConfig()
+ {
+ AesCtr.RegisterWithCryptoConfig();
+ using var aes = (AesCtr?)CryptoConfig.CreateFromName("AesCtr");
+ Assert.IsNotNull(aes);
+ }
+
+ [TestMethod]
+ public void RegisterWithCryptoConfig_Twice()
{
- using var aes = AesCtr.Create();
+ AesCtr.RegisterWithCryptoConfig();
+ AesCtr.RegisterWithCryptoConfig();
+ using var aes = (AesCtr?)CryptoConfig.CreateFromName("Dorssel.Security.Cryptography.AesCtr");
Assert.IsNotNull(aes);
}
+ [TestMethod]
+ public void Create()
+ {
+#pragma warning disable CS0618 // Type or member is obsolete
+ using var aesCtr = AesCtr.Create();
+#pragma warning restore CS0618 // Type or member is obsolete
+ Assert.IsNotNull(aesCtr);
+ }
+
[TestMethod]
public void Create_Name()
{
@@ -42,6 +65,16 @@ public void Create_Name()
Assert.IsNotNull(aes);
}
+ [TestMethod]
+ public void Create_FullName()
+ {
+#pragma warning disable CS0618 // Type or member is obsolete
+ using var aes = AesCtr.Create("Dorssel.Security.Cryptography.AesCtr");
+#pragma warning restore CS0618 // Type or member is obsolete
+ Assert.IsNotNull(aes);
+ }
+
+
[TestMethod]
public void Create_NullNameFails()
{
@@ -62,17 +95,205 @@ public void Create_OtherNameReturnsNull()
Assert.IsNull(aes);
}
+ [TestMethod]
+ public void Constructor()
+ {
+ using var aes = new AesCtr();
+
+ Assert.AreEqual(256, aes.KeySize);
+ Assert.AreEqual(256 / 8, aes.Key.Length);
+ CollectionAssert.AreNotEqual(new byte[aes.Key.Length], aes.Key);
+ Assert.AreEqual(256, aes.KeySize);
+ }
+
+ [TestMethod]
+ [DataRow(128)]
+ [DataRow(192)]
+ [DataRow(256)]
+ public void Constructor_Int(int keySize)
+ {
+ using var aes = new AesCtr(keySize);
+
+ Assert.AreEqual(keySize, aes.KeySize);
+ Assert.AreEqual(keySize / 8, aes.Key.Length);
+ CollectionAssert.AreNotEqual(new byte[aes.Key.Length], aes.Key);
+ Assert.AreEqual(keySize, aes.KeySize);
+ }
+
+ [TestMethod]
+ [DataRow(0)]
+ [DataRow(1)]
+ [DataRow(16)]
+ [DataRow(24)]
+ [DataRow(32)]
+ public void Constructor_Int_Invalid(int keySize)
+ {
+ Assert.ThrowsException(() =>
+ {
+ using var aes = new AesCtr(keySize);
+ });
+ }
+
+ [TestMethod]
+ [DataRow(128)]
+ [DataRow(192)]
+ [DataRow(256)]
+ public void Constructor_Array(int keySize)
+ {
+ using var aes = new AesCtr(new byte[keySize / 8]);
+
+ Assert.AreEqual(keySize, aes.KeySize);
+ Assert.AreEqual(keySize / 8, aes.Key.Length);
+ Assert.AreEqual(keySize, aes.KeySize);
+ }
+
+ [TestMethod]
+ [DataRow(0)]
+ [DataRow(16)]
+ [DataRow(24)]
+ [DataRow(32)]
+ public void Constructor_Array_Invalid(int keySize)
+ {
+ Assert.ThrowsException(() =>
+ {
+ using var aes = new AesCtr(new byte[keySize / 8]);
+ });
+ }
+
+ [TestMethod]
+ public void Constructor_Array_Null()
+ {
+ Assert.ThrowsException(() =>
+ {
+ using var aes = new AesCtr(TestKeyNull);
+ });
+ }
+
+ [TestMethod]
+ [DataRow(128)]
+ [DataRow(192)]
+ [DataRow(256)]
+ public void Constructor_ReadOnlySpan(int keySize)
+ {
+ using var aes = new AesCtr(new byte[keySize / 8].AsSpan());
+
+ Assert.AreEqual(keySize, aes.KeySize);
+ Assert.AreEqual(keySize / 8, aes.Key.Length);
+ Assert.AreEqual(keySize, aes.KeySize);
+ }
+
+ [TestMethod]
+ [DataRow(0)]
+ [DataRow(16)]
+ [DataRow(24)]
+ [DataRow(32)]
+ public void Constructor_ReadOnlySpan_Invalid(int keySize)
+ {
+ Assert.ThrowsException(() =>
+ {
+ using var aes = new AesCtr(new byte[keySize / 8].AsSpan());
+ });
+ }
+
+ [TestMethod]
+ [DataRow(128)]
+ [DataRow(192)]
+ [DataRow(256)]
+ public void Constructor_Array_Array(int keySize)
+ {
+ using var aes = new AesCtr(new byte[keySize / 8], TestIV);
+
+ Assert.AreEqual(keySize, aes.KeySize);
+ Assert.AreEqual(keySize / 8, aes.Key.Length);
+ Assert.AreEqual(keySize, aes.KeySize);
+ }
+
+ [TestMethod]
+ [DataRow(0)]
+ [DataRow(16)]
+ [DataRow(24)]
+ [DataRow(32)]
+ public void Constructor_Array_Array_KeyInvalid(int keySize)
+ {
+ Assert.ThrowsException(() =>
+ {
+ using var aes = new AesCtr(new byte[keySize / 8], TestIV);
+ });
+ }
+
+ [TestMethod]
+ public void Constructor_Array_Array_KeyNull()
+ {
+ Assert.ThrowsException(() =>
+ {
+ using var aes = new AesCtr(TestKeyNull, TestIV);
+ });
+ }
+
+ [TestMethod]
+ public void Constructor_Array_Array_IVInvalid()
+ {
+ Assert.ThrowsException(() =>
+ {
+ using var aes = new AesCtr(TestKey, TestIVInvalid);
+ });
+ }
+
+ [TestMethod]
+ public void Constructor_Array_Array_IVNull()
+ {
+ Assert.ThrowsException(() =>
+ {
+ using var aes = new AesCtr(TestKey, TestIVNull);
+ });
+ }
+
+ [TestMethod]
+ [DataRow(128)]
+ [DataRow(192)]
+ [DataRow(256)]
+ public void Constructor_ReadOnlySpan_ReadOnlySpan(int keySize)
+ {
+ using var aes = new AesCtr(new byte[keySize / 8].AsSpan(), TestIV.AsSpan());
+
+ Assert.AreEqual(keySize, aes.KeySize);
+ Assert.AreEqual(keySize / 8, aes.Key.Length);
+ Assert.AreEqual(keySize, aes.KeySize);
+ }
+
+ [TestMethod]
+ [DataRow(0)]
+ [DataRow(16)]
+ [DataRow(24)]
+ [DataRow(32)]
+ public void Constructor_ReadOnlySpan_ReadOnlySpan_KeyInvalid(int keySize)
+ {
+ Assert.ThrowsException(() =>
+ {
+ using var aes = new AesCtr(new byte[keySize / 8].AsSpan(), TestIV.AsSpan());
+ });
+ }
+
+ [TestMethod]
+ public void Constructor_ReadOnlySpan_ReadOnlySpan_IVInvalid()
+ {
+ Assert.ThrowsException(() =>
+ {
+ using var aes = new AesCtr(TestKey.AsSpan(), TestIVInvalid.AsSpan());
+ });
+ }
+
[TestMethod]
public void Dispose()
{
- var aes = AesCtr.Create();
+ var aes = new AesCtr();
aes.Dispose();
}
[TestMethod]
public void Dispose_Double()
{
- var aes = AesCtr.Create();
+ var aes = new AesCtr();
aes.Dispose();
aes.Dispose();
}
@@ -80,7 +301,7 @@ public void Dispose_Double()
[TestMethod]
public void Mode_SetUnchanged()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
Assert.AreEqual(CipherMode.CTS, aes.Mode); // DevSkim: ignore DS187371
aes.Mode = CipherMode.CTS; // DevSkim: ignore DS187371
Assert.AreEqual(CipherMode.CTS, aes.Mode); // DevSkim: ignore DS187371
@@ -89,7 +310,7 @@ public void Mode_SetUnchanged()
[TestMethod]
public void Mode_CannotChange()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
Assert.AreEqual(CipherMode.CTS, aes.Mode); // DevSkim: ignore DS187371
Assert.ThrowsException(() =>
{
@@ -101,7 +322,7 @@ public void Mode_CannotChange()
[TestMethod]
public void Padding_SetUnchanged()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
Assert.AreEqual(PaddingMode.None, aes.Padding);
aes.Padding = PaddingMode.None;
Assert.AreEqual(PaddingMode.None, aes.Padding);
@@ -110,7 +331,7 @@ public void Padding_SetUnchanged()
[TestMethod]
public void Padding_CannotChange()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
var padding = aes.Padding;
Assert.AreEqual(PaddingMode.None, padding);
Assert.ThrowsException(() =>
@@ -123,7 +344,7 @@ public void Padding_CannotChange()
[TestMethod]
public void FeedbackSize_SetUnchanged()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
Assert.AreEqual(aes.BlockSize, aes.FeedbackSize);
aes.FeedbackSize = aes.BlockSize;
Assert.AreEqual(aes.BlockSize, aes.FeedbackSize);
@@ -132,7 +353,7 @@ public void FeedbackSize_SetUnchanged()
[TestMethod]
public void FeedbackSize_CannotChange()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
Assert.AreEqual(aes.BlockSize, aes.FeedbackSize);
Assert.ThrowsException(() =>
{
@@ -144,7 +365,7 @@ public void FeedbackSize_CannotChange()
[TestMethod]
public void KeySize_AllValid()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
foreach (var legalKeySize in aes.LegalKeySizes)
{
for (var keySize = legalKeySize.MinSize; keySize <= legalKeySize.MaxSize; keySize += Math.Max(legalKeySize.SkipSize, 1))
@@ -156,10 +377,80 @@ public void KeySize_AllValid()
}
}
+ [TestMethod]
+ public void Key_AllValid()
+ {
+ using var aes = new AesCtr();
+ foreach (var legalKeySize in aes.LegalKeySizes)
+ {
+ for (var keySize = legalKeySize.MinSize; keySize <= legalKeySize.MaxSize; keySize += Math.Max(legalKeySize.SkipSize, 1))
+ {
+ aes.Key = new byte[keySize / 8];
+ Assert.AreEqual(keySize, aes.KeySize);
+ Assert.AreEqual(keySize, aes.Key.Length * 8);
+ }
+ }
+ }
+
+ [TestMethod]
+ public void Key_Null()
+ {
+ using var aes = new AesCtr();
+
+ Assert.ThrowsException(() =>
+ {
+ aes.Key = TestKeyNull;
+ });
+ }
+
+ [TestMethod]
+ public void Key_AfterDispose()
+ {
+ using var aes = new AesCtr();
+ aes.Dispose();
+
+ Assert.ThrowsException(() =>
+ {
+ aes.Key = TestKey;
+ });
+ }
+
+ [TestMethod]
+ public void IV()
+ {
+ using var aes = new AesCtr();
+
+ aes.IV = TestIV;
+ CollectionAssert.AreEqual(TestIV, aes.IV);
+ }
+
+ [TestMethod]
+ public void IV_Null()
+ {
+ using var aes = new AesCtr();
+
+ Assert.ThrowsException(() =>
+ {
+ aes.IV = TestIVNull;
+ });
+ }
+
+ [TestMethod]
+ public void IV_AfterDispose()
+ {
+ using var aes = new AesCtr();
+ aes.Dispose();
+
+ Assert.ThrowsException(() =>
+ {
+ aes.IV = TestIV;
+ });
+ }
+
[TestMethod]
public void BlockSize_AllValid()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
foreach (var legalBlockSize in aes.LegalBlockSizes)
{
for (var blockSize = legalBlockSize.MinSize; blockSize <= legalBlockSize.MaxSize; blockSize += Math.Max(legalBlockSize.SkipSize, 1))
@@ -176,7 +467,7 @@ public void BlockSize_AllValid()
[DataRow(256)]
public void GenerateIV_HasCorrectLength(int keySize)
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
aes.KeySize = keySize;
aes.GenerateIV();
Assert.AreEqual(aes.BlockSize, aes.IV.Length * 8);
@@ -188,7 +479,7 @@ public void GenerateIV_HasCorrectLength(int keySize)
[DataRow(256)]
public void GenerateKey_HasCorrectLength(int keySize)
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
aes.KeySize = keySize;
aes.GenerateKey();
Assert.AreEqual(keySize, aes.Key.Length * 8);
@@ -197,41 +488,75 @@ public void GenerateKey_HasCorrectLength(int keySize)
[TestMethod]
public void CreateEncryptor()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
using var _ = aes.CreateEncryptor();
}
[TestMethod]
- public void CreateEncryptor_Null()
+ public void CreateEncryptor_Array_Array()
+ {
+ using var aes = new AesCtr();
+ using var _ = aes.CreateEncryptor(TestKey, TestIV);
+ }
+
+ [TestMethod]
+ public void CreateEncryptor_Array_Array_KeyNull()
+ {
+ using var aes = new AesCtr();
+ Assert.ThrowsException(() =>
+ {
+ using var _ = aes.CreateEncryptor(TestKeyNull, TestIV);
+ });
+ }
+
+ [TestMethod]
+ public void CreateEncryptor_Array_Array_IVNull()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
Assert.ThrowsException(() =>
{
- using var _ = aes.CreateEncryptor(TestKey, null);
+ using var _ = aes.CreateEncryptor(TestKey, TestIVNull);
});
}
[TestMethod]
public void CreateDecryptor()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
using var _ = aes.CreateDecryptor();
}
[TestMethod]
- public void CreateDecryptor_Null()
+ public void CreateDecryptor_Array_Array()
+ {
+ using var aes = new AesCtr();
+ using var _ = aes.CreateDecryptor(TestKey, TestIV);
+ }
+
+ [TestMethod]
+ public void CreateDecryptor_Array_Array_KeyNull()
+ {
+ using var aes = new AesCtr();
+ Assert.ThrowsException(() =>
+ {
+ using var _ = aes.CreateDecryptor(TestKeyNull, TestIV);
+ });
+ }
+
+ [TestMethod]
+ public void CreateDecryptor_Array_Array_IVNull()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
Assert.ThrowsException(() =>
{
- using var _ = aes.CreateDecryptor(TestKey, null);
+ using var _ = aes.CreateDecryptor(TestKey, TestIVNull);
});
}
[TestMethod]
public void TransformCtr_Array_Array()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
aes.TransformCtr(TestMessage, TestIV);
}
@@ -239,40 +564,40 @@ public void TransformCtr_Array_Array()
[TestMethod]
public void TransformCtr_Null_Array()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
Assert.ThrowsException(() =>
{
- aes.TransformCtr(null!, TestIV);
+ aes.TransformCtr(TestKeyNull, TestIV);
});
}
[TestMethod]
public void TransformCtr_Array_Null()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
Assert.ThrowsException(() =>
{
- aes.TransformCtr(TestMessage, null!);
+ aes.TransformCtr(TestMessage, TestIVNull);
});
}
[TestMethod]
public void TransformCtr_Array_Array_InvalidIV()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
Assert.ThrowsException(() =>
{
- aes.TransformCtr(TestMessage, TestInvalidIV);
+ aes.TransformCtr(TestMessage, TestIVInvalid);
});
}
[TestMethod]
public void TransformCtr_ReadOnlySpan_ReadOnlySpan()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
aes.TransformCtr(TestMessage.AsSpan(), TestIV.AsSpan());
}
@@ -280,18 +605,18 @@ public void TransformCtr_ReadOnlySpan_ReadOnlySpan()
[TestMethod]
public void TransformCtr_ReadOnlySpan_ReadOnlySpan_InvalidIV()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
Assert.ThrowsException(() =>
{
- aes.TransformCtr(TestMessage.AsSpan(), TestInvalidIV.AsSpan());
+ aes.TransformCtr(TestMessage.AsSpan(), TestIVInvalid.AsSpan());
});
}
[TestMethod]
public void TransformCtr_ReadOnlySpan_ReadOnlySpan_Span()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
var destination = new byte[TestMessage.Length];
aes.TransformCtr(TestMessage.AsSpan(), TestIV.AsSpan(), destination);
@@ -300,19 +625,19 @@ public void TransformCtr_ReadOnlySpan_ReadOnlySpan_Span()
[TestMethod]
public void TransformCtr_ReadOnlySpan_ReadOnlySpan_Span_InvalidIV()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
var destination = new byte[TestMessage.Length];
Assert.ThrowsException(() =>
{
- aes.TransformCtr(TestMessage, TestInvalidIV, destination);
+ aes.TransformCtr(TestMessage, TestIVInvalid, destination);
});
}
[TestMethod]
public void TransformCtr_ReadOnlySpan_ReadOnlySpan_Span_Short()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
var destination = new byte[TestMessage.Length - 1];
Assert.ThrowsException(() =>
@@ -324,7 +649,7 @@ public void TransformCtr_ReadOnlySpan_ReadOnlySpan_Span_Short()
[TestMethod]
public void TryTransformCtr()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
var destination = new byte[TestMessage.Length];
aes.TryTransformCtr(TestMessage.AsSpan(), TestIV.AsSpan(), destination, out _);
@@ -333,19 +658,19 @@ public void TryTransformCtr()
[TestMethod]
public void TryTransformCtr_InvalidIV()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
var destination = new byte[TestMessage.Length];
Assert.ThrowsException(() =>
{
- aes.TryTransformCtr(TestMessage.AsSpan(), TestInvalidIV, destination, out _);
+ aes.TryTransformCtr(TestMessage.AsSpan(), TestIVInvalid, destination, out _);
});
}
[TestMethod]
public void TryTransformCtr_Short()
{
- using var aes = AesCtr.Create();
+ using var aes = new AesCtr();
var destination = new byte[TestMessage.Length - 1];
var success = aes.TryTransformCtr(TestMessage, TestIV, destination, out var bytesWritten);
diff --git a/UnitTests/NistAesCtrSampleTestVector.cs b/UnitTests/NistAesCtrSampleTestVector.cs
index 5443fef..ebd992d 100644
--- a/UnitTests/NistAesCtrSampleTestVector.cs
+++ b/UnitTests/NistAesCtrSampleTestVector.cs
@@ -93,79 +93,79 @@ static NistAesCtrSampleTestVector()
var testVectors = new List
{
new("F.5.1", "CTR-AES128.Encrypt", @"
- Key 2b7e151628aed2a6abf7158809cf4f3c
- Init. Counter f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
+ Key 2B7E151628AED2A6ABF7158809CF4F3C
+ Init. Counter F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
Block #1
- Input Block f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
- Output Block ec8cdf7398607cb0f2d21675ea9ea1e4
- Plaintext 6bc1bee22e409f96e93d7e117393172a
- Ciphertext 874d6191b620e3261bef6864990db6ce
+ Input Block F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+ Output Block EC8CDF7398607CB0F2D21675EA9EA1E4
+ Plaintext 6BC1BEE22E409F96E93D7E117393172A
+ Ciphertext 874D6191B620E3261BEF6864990DB6CE
Block #2
- Input Block f0f1f2f3f4f5f6f7f8f9fafbfcfdff00
- Output Block 362b7c3c6773516318a077d7fc5073ae
- Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
- Ciphertext 9806f66b7970fdff8617187bb9fffdff
+ Input Block F0F1F2F3F4F5F6F7F8F9FAFBFCFDFF00
+ Output Block 362B7C3C6773516318A077D7FC5073AE
+ Plaintext AE2D8A571E03AC9C9EB76FAC45AF8E51
+ Ciphertext 9806F66B7970FDFF8617187BB9FFFDFF
Block #3
- Input Block f0f1f2f3f4f5f6f7f8f9fafbfcfdff01
- Output Block 6a2cc3787889374fbeb4c81b17ba6c44
- Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
- Ciphertext 5ae4df3edbd5d35e5b4f09020db03eab
+ Input Block F0F1F2F3F4F5F6F7F8F9FAFBFCFDFF01
+ Output Block 6A2CC3787889374FBEB4C81B17BA6C44
+ Plaintext 30C81C46A35CE411E5FBC1191A0A52EF
+ Ciphertext 5AE4DF3EDBD5D35E5B4F09020DB03EAB
Block #4
- Input Block f0f1f2f3f4f5f6f7f8f9fafbfcfdff02
- Output Block e89c399ff0f198c6d40a31db156cabfe
- Plaintext f69f2445df4f9b17ad2b417be66c3710
- Ciphertext 1e031dda2fbe03d1792170a0f3009cee
+ Input Block F0F1F2F3F4F5F6F7F8F9FAFBFCFDFF02
+ Output Block E89C399FF0F198C6D40A31DB156CABFE
+ Plaintext F69F2445DF4F9B17AD2B417BE66C3710
+ Ciphertext 1E031DDA2FBE03D1792170A0F3009CEE
"),
new("F.5.3", "CTR-AES192.Encrypt", @"
- Key 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
- Init. Counter f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
+ Key 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
+ Init. Counter F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
Block #1
- Input Block f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
- Output Block 717d2dc639128334a6167a488ded7921
- Plaintext 6bc1bee22e409f96e93d7e117393172a
- Ciphertext 1abc932417521ca24f2b0459fe7e6e0b
+ Input Block F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+ Output Block 717D2DC639128334A6167A488DED7921
+ Plaintext 6BC1BEE22E409F96E93D7E117393172A
+ Ciphertext 1ABC932417521CA24F2B0459FE7E6E0B
Block #2
- Input Block f0f1f2f3f4f5f6f7f8f9fafbfcfdff00
- Output Block a72eb3bb14a556734b7bad6ab16100c5
- Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
- Ciphertext 090339ec0aa6faefd5ccc2c6f4ce8e94
+ Input Block F0F1F2F3F4F5F6F7F8F9FAFBFCFDFF00
+ Output Block A72EB3BB14A556734B7BAD6AB16100C5
+ Plaintext AE2D8A571E03AC9C9EB76FAC45AF8E51
+ Ciphertext 090339EC0AA6FAEFD5CCC2C6F4CE8E94
Block #3
- Input Block f0f1f2f3f4f5f6f7f8f9fafbfcfdff01
- Output Block 2efeae2d72b722613446dc7f4c2af918
- Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
- Ciphertext 1e36b26bd1ebc670d1bd1d665620abf7
+ Input Block F0F1F2F3F4F5F6F7F8F9FAFBFCFDFF01
+ Output Block 2EFEAE2D72B722613446DC7F4C2AF918
+ Plaintext 30C81C46A35CE411E5FBC1191A0A52EF
+ Ciphertext 1E36B26BD1EBC670D1BD1D665620ABF7
Block #4
- Input Block f0f1f2f3f4f5f6f7f8f9fafbfcfdff02
- Output Block b9e783b30dd7924ff7bc9b97beaa8740
- Plaintext f69f2445df4f9b17ad2b417be66c3710
- Ciphertext 4f78a7f6d29809585a97daec58c6b050
+ Input Block F0F1F2F3F4F5F6F7F8F9FAFBFCFDFF02
+ Output Block B9E783B30DD7924FF7BC9B97BEAA8740
+ Plaintext F69F2445DF4F9B17AD2B417BE66C3710
+ Ciphertext 4F78A7F6D29809585A97DAEC58C6B050
"),
new("F.5.5", "CTR-AES256.Encrypt", @"
- Key 603deb1015ca71be2b73aef0857d7781
- 1f352c073b6108d72d9810a30914dff4
- Init. Counter f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
+ Key 603DEB1015CA71BE2B73AEF0857D7781
+ 1F352C073B6108D72D9810A30914DFF4
+ Init. Counter F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
Block #1
- Input Block f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
- Output Block 0bdf7df1591716335e9a8b15c860c502
- Plaintext 6bc1bee22e409f96e93d7e117393172a
- Ciphertext 601ec313775789a5b7a7f504bbf3d228
+ Input Block F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+ Output Block 0BDF7DF1591716335E9A8B15C860C502
+ Plaintext 6BC1BEE22E409F96E93D7E117393172A
+ Ciphertext 601EC313775789A5B7A7F504BBF3D228
Block #2
- Input Block f0f1f2f3f4f5f6f7f8f9fafbfcfdff00
- Output Block 5a6e699d536119065433863c8f657b94
- Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
- Ciphertext f443e3ca4d62b59aca84e990cacaf5c5
+ Input Block F0F1F2F3F4F5F6F7F8F9FAFBFCFDFF00
+ Output Block 5A6E699D536119065433863C8F657B94
+ Plaintext AE2D8A571E03AC9C9EB76FAC45AF8E51
+ Ciphertext F443E3CA4D62B59ACA84E990CACAF5C5
Block #3
- Input Block f0f1f2f3f4f5f6f7f8f9fafbfcfdff01
- Output Block 1bc12c9c01610d5d0d8bd6a3378eca62
- Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
- Ciphertext 2b0930daa23de94ce87017ba2d84988d
+ Input Block F0F1F2F3F4F5F6F7F8F9FAFBFCFDFF01
+ Output Block 1BC12C9C01610D5D0D8BD6A3378ECA62
+ Plaintext 30C81C46A35CE411E5FBC1191A0A52EF
+ Ciphertext 2B0930DAA23DE94CE87017BA2D84988D
Block #4
- Input Block f0f1f2f3f4f5f6f7f8f9fafbfcfdff02
- Output Block 2956e1c8693536b1bee99c73a31576b6
- Plaintext f69f2445df4f9b17ad2b417be66c3710
- Ciphertext dfc9c58db67aada613c2dd08457941a6
+ Input Block F0F1F2F3F4F5F6F7F8F9FAFBFCFDFF02
+ Output Block 2956E1C8693536B1BEE99C73A31576B6
+ Plaintext F69F2445DF4F9B17AD2B417BE66C3710
+ Ciphertext DFC9C58DB67AADA613C2DD08457941A6
"),
};
diff --git a/UnitTests/RfcAesSivTestVector.cs b/UnitTests/RfcAesSivTestVector.cs
index 749dd90..450042d 100644
--- a/UnitTests/RfcAesSivTestVector.cs
+++ b/UnitTests/RfcAesSivTestVector.cs
@@ -74,41 +74,41 @@ static RfcAesSivTestVector()
var testVectors = new List
{
new("Deterministic", @"
- fffefdfc fbfaf9f8 f7f6f5f4 f3f2f1f0
- f0f1f2f3 f4f5f6f7 f8f9fafb fcfdfeff
+ FFFEFDFC FBFAF9F8 F7F6F5F4 F3F2F1F0
+ F0F1F2F3 F4F5F6F7 F8F9FAFB FCFDFEFF
", [ @"
- 10111213 14151617 18191a1b 1c1d1e1f
+ 10111213 14151617 18191A1B 1C1D1E1F
20212223 24252627
" ],
null
, @"
- 11223344 55667788 99aabbcc ddee
+ 11223344 55667788 99AABBCC DDEE
", @"
- 85632d07 c6e8f37f 950acd32 0a2ecc93
- 40c02b96 90c4dc04 daef7f6a fe5c
+ 85632D07 C6E8F37F 950ACD32 0A2ECC93
+ 40C02B96 90C4DC04 DAEF7F6A FE5C
"
),
new("Nonce-Based", @"
- 7f7e7d7c 7b7a7978 77767574 73727170
- 40414243 44454647 48494a4b 4c4d4e4f
+ 7F7E7D7C 7B7A7978 77767574 73727170
+ 40414243 44454647 48494A4B 4C4D4E4F
", [ @"
- 00112233 44556677 8899aabb ccddeeff
- deaddada deaddada ffeeddcc bbaa9988
+ 00112233 44556677 8899AABB CCDDEEFF
+ DEADDADA DEADDADA FFEEDDCC BBAA9988
77665544 33221100
", @"
- 10203040 50607080 90a0
+ 10203040 50607080 90A0
" ], @"
- 09f91102 9d74e35b d84156c5 635688c0
+ 09F91102 9D74E35B D84156C5 635688C0
", @"
- 74686973 20697320 736f6d65 20706c61
- 696e7465 78742074 6f20656e 63727970
- 74207573 696e6720 5349562d 414553
+ 74686973 20697320 736F6D65 20706C61
+ 696E7465 78742074 6F20656E 63727970
+ 74207573 696E6720 5349562D 414553
", @"
- 7bdb6e3b 432667eb 06f4d14b ff2fbd0f
- cb900f2f ddbe4043 26601965 c889bf17
- dba77ceb 094fa663 b7a3f748 ba8af829
- ea64ad54 4a272e9c 485b62a3 fd5c0d
+ 7BDB6E3B 432667EB 06F4D14B FF2FBD0F
+ CB900F2F DDBE4043 26601965 C889BF17
+ DBA77CEB 094FA663 B7A3F748 BA8AF829
+ EA64AD54 4A272E9C 485B62A3 FD5C0D
"
),
};