Table of Contents

MAC Algorithms Reference

This page provides detailed documentation for all Message Authentication Code (MAC) algorithms implemented in the CryptoHives.Foundation.Security.Cryptography package.

Namespace

using CryptoHives.Foundation.Security.Cryptography.Mac;

Overview

Message Authentication Codes (MACs) provide both data integrity and authenticity verification. Unlike simple hash functions, MACs require a secret key, ensuring that only parties with the key can generate or verify the authentication tag.

MAC vs Hash

Feature Hash MAC
Secret key required No Yes
Data integrity Yes Yes
Data authenticity No Yes
Use case Fingerprinting Authentication

KMAC128

KMAC128 is the Keccak Message Authentication Code with 128-bit security, defined in NIST SP 800-185.

Class Declaration

public sealed class KMac128 : HashAlgorithm

Properties

Property Value
Security 128 bits
Output Size Variable (default 32 bytes)
Key Size Any length
Block Size 168 bytes (rate)

Constructor

public KMac128(byte[] key, int outputBytes = 32, string customization = "")

Parameters:

  • key - The secret key (any length, cannot be empty)
  • outputBytes - Desired output size in bytes (default: 32)
  • customization - Optional customization string for domain separation

Factory Method

public static KMac128 Create(byte[] key, int outputBytes = 32, string customization = "")

Usage Examples

byte[] key = new byte[32];
RandomNumberGenerator.Fill(key);
byte[] message = Encoding.UTF8.GetBytes("Hello, World!");

// Basic KMAC128
using var kmac = KMac128.Create(key, outputBytes: 32);
byte[] mac = kmac.ComputeHash(message);

// With customization string
using var kmac = KMac128.Create(key, outputBytes: 32, customization: "MyApp v1.0");
byte[] mac = kmac.ComputeHash(message);

// Variable output length
using var kmac = KMac128.Create(key, outputBytes: 64);
byte[] longMac = kmac.ComputeHash(message);

Incremental Usage

using var kmac = KMac128.Create(key, outputBytes: 32, customization: "");

// Process data in chunks
kmac.TransformBlock(chunk1, 0, chunk1.Length, null, 0);
kmac.TransformBlock(chunk2, 0, chunk2.Length, null, 0);
kmac.TransformFinalBlock(chunk3, 0, chunk3.Length);

byte[] mac = kmac.Hash;

KMAC256

KMAC256 is the Keccak Message Authentication Code with 256-bit security, defined in NIST SP 800-185.

Class Declaration

public sealed class KMac256 : HashAlgorithm

Properties

Property Value
Security 256 bits
Output Size Variable (default 64 bytes)
Key Size Any length
Block Size 136 bytes (rate)

Constructor

public KMac256(byte[] key, int outputBytes = 64, string customization = "")

Parameters:

  • key - The secret key (any length, cannot be empty)
  • outputBytes - Desired output size in bytes (default: 64)
  • customization - Optional customization string for domain separation

Factory Method

public static KMac256 Create(byte[] key, int outputBytes = 64, string customization = "")

Usage Examples

byte[] key = new byte[32];
RandomNumberGenerator.Fill(key);
byte[] message = Encoding.UTF8.GetBytes("Hello, World!");

// Basic KMAC256
using var kmac = KMac256.Create(key, outputBytes: 64);
byte[] mac = kmac.ComputeHash(message);

// With customization string for domain separation
using var kmac = KMac256.Create(key, outputBytes: 64, customization: "Session Authentication");
byte[] mac = kmac.ComputeHash(message);

BLAKE2 MAC

BLAKE2b and BLAKE2s support built-in keyed hashing mode for message authentication.

Blake2b Keyed Mode

public static Blake2b Create(byte[]? key = null, int hashSize = 64)

Properties:

  • Security: Up to 256 bits (depends on key and output size)
  • Key Size: 1-64 bytes
  • Output Size: 1-64 bytes

Usage:

byte[] key = new byte[32]; // Up to 64 bytes
RandomNumberGenerator.Fill(key);

using var blake2b = Blake2b.Create(key: key, hashSize: 32);
byte[] mac = blake2b.ComputeHash(message);

Blake2s Keyed Mode

public static Blake2s Create(byte[]? key = null, int hashSize = 32)

Properties:

  • Security: Up to 128 bits (depends on key and output size)
  • Key Size: 1-32 bytes
  • Output Size: 1-32 bytes

Usage:

byte[] key = new byte[16]; // Up to 32 bytes
RandomNumberGenerator.Fill(key);

using var blake2s = Blake2s.Create(key: key, hashSize: 16);
byte[] mac = blake2s.ComputeHash(message);

BLAKE3 MAC

BLAKE3 provides a dedicated keyed hashing mode for message authentication.

Blake3 Keyed Mode

public static Blake3 CreateKeyed(byte[] key, int outputBytes = 32)

Properties:

  • Security: 128 bits
  • Key Size: Exactly 32 bytes
  • Output Size: Variable (default 32 bytes)

Usage:

byte[] key = new byte[32]; // Must be exactly 32 bytes
RandomNumberGenerator.Fill(key);

// Standard 32-byte MAC
using var blake3 = Blake3.CreateKeyed(key);
byte[] mac = blake3.ComputeHash(message);

// Extended 64-byte MAC
using var blake3 = Blake3.CreateKeyed(key, outputBytes: 64);
byte[] longMac = blake3.ComputeHash(message);

BLAKE3 Key Derivation

BLAKE3 also supports key derivation from a context string and input key material:

public static Blake3 CreateDeriveKey(string context, int outputBytes = 32)

Usage:

string context = "MyApp 2025-01-01 encryption key";
byte[] inputKeyMaterial = ...; // Your master key or password-derived key

using var blake3 = Blake3.CreateDeriveKey(context);
byte[] derivedKey = blake3.ComputeHash(inputKeyMaterial);

Algorithm Comparison

Security Levels

Algorithm Security Strength Notes
KMAC256 256 bits Highest security, NIST approved
KMAC128 128 bits Good security, NIST approved
BLAKE3 keyed 128 bits High performance
BLAKE2b keyed Up to 256 bits Depends on key/output size
BLAKE2s keyed Up to 128 bits Good for embedded systems

Performance

Algorithm Relative Speed Best For
BLAKE3 keyed Fastest High-throughput applications
BLAKE2b keyed Very fast General purpose on 64-bit
BLAKE2s keyed Fast 32-bit and embedded systems
KMAC256 Moderate Maximum security
KMAC128 Moderate NIST compliance

Feature Comparison

Feature KMAC BLAKE2 BLAKE3
Variable output
Customization string
NIST approved
Key derivation
Arbitrary key size

Best Practices

Key Generation

Always use cryptographically secure random number generators for key generation:

byte[] key = new byte[32];
RandomNumberGenerator.Fill(key);

Key Storage

  • Never hardcode keys in source code
  • Use secure key storage (Azure Key Vault, AWS KMS, etc.)
  • Rotate keys periodically

Domain Separation

Use customization strings (KMAC) or different contexts (BLAKE3) to separate different uses of the same key:

// Authentication for different message types
using var kmacAuth = KMac256.Create(key, customization: "Auth");
using var kmacEncrypt = KMac256.Create(key, customization: "Encrypt");

// BLAKE3 key derivation with context
using var authKey = Blake3.CreateDeriveKey("MyApp Auth Key");
using var encKey = Blake3.CreateDeriveKey("MyApp Encryption Key");

Verification

When verifying MACs, use constant-time comparison to prevent timing attacks:

using System.Security.Cryptography;

bool VerifyMac(byte[] expected, byte[] actual)
{
    return CryptographicOperations.FixedTimeEquals(expected, actual);
}

Common Patterns

Authenticated Encryption

public class AuthenticatedMessage
{
    public byte[] Ciphertext { get; set; }
    public byte[] Mac { get; set; }
    
    public static AuthenticatedMessage Create(byte[] key, byte[] plaintext)
    {
        // Encrypt (using your preferred cipher)
        byte[] ciphertext = Encrypt(plaintext);
        
        // Authenticate
        using var kmac = KMac256.Create(key, customization: "Auth");
        byte[] mac = kmac.ComputeHash(ciphertext);
        
        return new AuthenticatedMessage { Ciphertext = ciphertext, Mac = mac };
    }
    
    public bool Verify(byte[] key)
    {
        using var kmac = KMac256.Create(key, customization: "Auth");
        byte[] expectedMac = kmac.ComputeHash(Ciphertext);
        return CryptographicOperations.FixedTimeEquals(Mac, expectedMac);
    }
}

API Request Signing

public string SignRequest(byte[] key, string method, string path, string timestamp)
{
    string message = $"{method}:{path}:{timestamp}";
    byte[] messageBytes = Encoding.UTF8.GetBytes(message);
    
    using var blake3 = Blake3.CreateKeyed(key);
    byte[] signature = blake3.ComputeHash(messageBytes);
    
    return Convert.ToBase64String(signature);
}

Session Token Generation

public byte[] GenerateSessionKey(byte[] masterKey, string userId, DateTime expiry)
{
    string context = $"session:{userId}:{expiry:O}";
    using var blake3 = Blake3.CreateDeriveKey(context);
    return blake3.ComputeHash(masterKey);
}

See Also


© 2026 The Keepers of the CryptoHives