Class BotanMac

java.lang.Object
javax.crypto.MacSpi
net.randombit.botan.mac.BotanMac
Direct Known Subclasses:
BotanMac.CMac, BotanMac.HMacMd5, BotanMac.HMacRipeMd160, BotanMac.HMacSha1, BotanMac.HMacSha224, BotanMac.HMacSha256, BotanMac.HMacSha384, BotanMac.HMacSha512, BotanMac.Poly1305, BotanMac.SipHash

public abstract class BotanMac extends MacSpi
Abstract base class for Message Authentication Code (MAC) implementations using the Botan cryptography library.

This class provides a JCE-compliant MAC implementation that delegates cryptographic operations to native Botan library functions via JNR-FFI. It implements automatic native resource management using the Java Cleaner API to ensure native MAC objects are properly destroyed when no longer needed.

Lifecycle and Resource Management

Native Botan MAC objects are created during initialization and destroyed either:

  • Explicitly when re-initializing with a new key (old object destroyed before creating new one)
  • Automatically by the Cleaner when the Java object becomes unreachable (garbage collection)

Thread Safety

This implementation is NOT thread-safe. Each thread should use its own MAC instance. The JCE API does not require MAC implementations to be thread-safe.

State Management

The MAC maintains internal state to optimize reset operations:

  • macFinalized - tracks whether doFinal() has been called, which auto-resets the state
  • currentKey - stores the current key for re-initialization after explicit reset()

Usage Examples

Basic HMAC-SHA256 Usage


 // Get MAC instance from the Botan provider
 Mac mac = Mac.getInstance("HmacSHA256", "Botan");

 // Initialize with a secret key
 SecretKeySpec key = new SecretKeySpec(keyBytes, "HmacSHA256");
 mac.init(key);

 // Update with data
 mac.update("Hello, ".getBytes());
 mac.update("World!".getBytes());

 // Compute the MAC
 byte[] macValue = mac.doFinal();
 

Incremental Processing with Reset


 Mac mac = Mac.getInstance("HmacSHA256", "Botan");
 SecretKeySpec key = new SecretKeySpec(keyBytes, "HmacSHA256");
 mac.init(key);

 // Process first message
 mac.update(message1);
 byte[] mac1 = mac.doFinal();  // Auto-resets after doFinal

 // Process second message (no need to call reset)
 mac.update(message2);
 byte[] mac2 = mac.doFinal();

 // Explicit reset if needed without doFinal
 mac.update(message3);
 mac.reset();  // Discard partial computation
 mac.update(message4);
 byte[] mac4 = mac.doFinal();
 

Re-initialization with Different Key


 Mac mac = Mac.getInstance("HmacSHA256", "Botan");

 // First key
 SecretKeySpec key1 = new SecretKeySpec(keyBytes1, "HmacSHA256");
 mac.init(key1);
 byte[] mac1 = mac.doFinal(data1);

 // Re-initialize with second key (automatically destroys old native object)
 SecretKeySpec key2 = new SecretKeySpec(keyBytes2, "HmacSHA256");
 mac.init(key2);  // Old Botan MAC object destroyed, new one created
 byte[] mac2 = mac.doFinal(data2);
 

Single-Byte Processing


 Mac mac = Mac.getInstance("Poly1305", "Botan");
 mac.init(key);

 // Process byte by byte (uses internal single-byte buffer)
 for (byte b : data) {
     mac.update(b);
 }
 byte[] result = mac.doFinal();
 

Supported Algorithms

The following MAC algorithms are available through concrete subclasses:

Implementation Notes

  • Cloning Not Supported - Calling clone() throws CloneNotSupportedException because native MAC state cannot be safely cloned
  • Key Size Validation - Key sizes are validated against Botan's key specification during initialization
  • Auto-Reset Optimization - After doFinal(), the MAC is automatically reset by Botan, so explicit reset() is not needed
  • Memory Safety - Native resources are guaranteed to be freed even if explicit cleanup is not called, thanks to the Cleaner API
Since:
0.1.0
Author:
Yasser Aziza
See Also: