10 public sealed
class CMac : IDisposable
12 private readonly SymmetricAlgorithm cipher;
13 private readonly
byte[] key;
14 private readonly
byte[] subKey1;
15 private readonly
byte[] subKey2;
16 private readonly
int blockSizeBits;
17 private readonly
int blockSizeBytes;
18 private bool disposed =
false;
28 private CMac(SymmetricAlgorithm Cipher,
byte[] Key,
byte[] K1,
byte[] K2)
34 this.blockSizeBits = this.cipher.BlockSize;
35 this.blockSizeBytes = this.blockSizeBits >> 3;
45 return CreateAesCMac(Key, zero16, 128, 128);
55 return CreateAesCMac(Key, zero16, 128, 192);
65 return CreateAesCMac(Key, zero16, 128, 256);
68 private static CMac CreateAesCMac(
byte[] Key,
byte[] Zero,
int BlockSize,
int KeySize)
71 throw new ArgumentNullException(nameof(Zero));
73 int BlockByteSize = BlockSize >> 3;
75 if (Zero.Length != BlockByteSize)
76 throw new ArgumentException(
"Zero block must match block size.", nameof(Zero));
78 Aes Aes = Aes.Create();
79 Aes.Mode = CipherMode.CBC;
80 Aes.Padding = PaddingMode.None;
81 Aes.BlockSize = BlockSize;
82 Aes.KeySize = KeySize;
86 using ICryptoTransform Encryptor = Aes.CreateEncryptor(Key, Zero);
88 byte[] L = Encryptor.TransformFinalBlock(Zero, 0, BlockByteSize);
93 if ((L[0] & 0x80) != 0)
94 K1[BlockByteSize - 1] ^= 0b10000111;
97 if ((K1[0] & 0x80) != 0)
98 K2[BlockByteSize - 1] ^= 0b10000111;
100 return new CMac(Aes, Key, K1, K2);
103 private static byte[] ShiftLeft(
byte[] Data)
106 byte[] Result = (
byte[])Data.Clone();
115 Carry = (Data[c] & 0x80) != 0;
128 this.disposed =
true;
130 Array.Clear(this.key, 0, this.key.Length);
131 Array.Clear(this.subKey1, 0, this.subKey1.Length);
132 Array.Clear(this.subKey2, 0, this.subKey2.Length);
134 this.cipher.Dispose();
144 public byte[]
Sign(
byte[] Message,
int Len)
146 if (Len > this.blockSizeBytes)
147 throw new ArgumentException(
"Requested signature length exceeds block size.", nameof(Len));
149 byte[] C = this.
Sign(Message);
150 if (Len == this.blockSizeBytes)
153 byte[] C2 =
new byte[Len];
154 Buffer.BlockCopy(C, 0, C2, 0, Len);
164 public byte[]
Sign(
byte[] Message)
169 throw new ArgumentNullException(nameof(Message));
171 using ICryptoTransform Cipher = this.cipher.CreateEncryptor(this.key, zero16);
173 byte[] M =
new byte[this.blockSizeBytes];
174 byte[] C =
new byte[this.blockSizeBytes];
176 int c = Message.Length;
178 int n = (c + this.blockSizeBytes - 1) / this.blockSizeBytes;
185 if (d >= this.blockSizeBytes)
187 Buffer.BlockCopy(Message, i, M, 0, this.blockSizeBytes);
188 i += this.blockSizeBytes;
191 XorInto(M, this.subKey1);
195 Buffer.BlockCopy(Message, i, M, 0, d);
199 if (d < this.blockSizeBytes)
200 Array.Clear(M, d, this.blockSizeBytes - d);
202 XorInto(M, this.subKey2);
207 byte[] C2 = Cipher.TransformFinalBlock(M, 0, this.blockSizeBytes);
209 Array.Clear(C, 0, this.blockSizeBytes);
214 Array.Clear(M, 0, this.blockSizeBytes);
219 private static readonly
byte[] zero16 =
new byte[16];
221 private static void XorInto(
byte[] Data,
byte[] Data2)
224 if (Data2.Length != c)
225 throw new ArgumentException(
"Data blocks must be of the same length.", nameof(Data2));
227 for (
int i = 0; i < c; i++)
237 public bool Verify(
byte[] Message,
byte[] Signature)
241 if (Message is
null || Signature is
null || (c = Signature.Length) >
this.blockSizeBytes)
244 byte[] Signature2 = this.
Sign(Message, c);
246 for (i = 0; i < c; i++)
248 if (Signature[i] != Signature2[i])
Implements the CMAC algorithm, as defined in NIST SP 800-38B, revision 2016. Ref: https://nvlpubs....
bool Verify(byte[] Message, byte[] Signature)
Verifies a CMAC Signature.
byte[] Sign(byte[] Message)
Signs a message using the current CMAC.
static CMac CreateAes192CMac(byte[] Key)
Creates an instance of CMAC using AES-192 as the underlying block cipher
static CMac CreateAes256CMac(byte[] Key)
Creates an instance of CMAC using AES-256 as the underlying block cipher
byte[] Sign(byte[] Message, int Len)
Signs a message using the current CMAC.
static CMac CreateAes128CMac(byte[] Key)
Creates an instance of CMAC using AES-128 as the underlying block cipher
void Dispose()
Disposes of the object.