Package net.randombit.botan.mac
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
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 whetherdoFinal()has been called, which auto-resets the statecurrentKey- stores the current key for re-initialization after explicitreset()
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:
- CMAC -
BotanMac.CMac- Cipher-based MAC using AES (16-byte output) - Poly1305 -
BotanMac.Poly1305- Poly1305 MAC (16-byte output) - SipHash -
BotanMac.SipHash- SipHash-2-4 (8-byte output) - HMAC-MD5 -
BotanMac.HMacMd5- HMAC with MD5 (16-byte output) - HMAC-RIPEMD160 -
BotanMac.HMacRipeMd160- HMAC with RIPEMD-160 (20-byte output) - HMAC-SHA1 -
BotanMac.HMacSha1- HMAC with SHA-1 (20-byte output) - HMAC-SHA224 -
BotanMac.HMacSha224- HMAC with SHA-224 (28-byte output) - HMAC-SHA256 -
BotanMac.HMacSha256- HMAC with SHA-256 (32-byte output) - HMAC-SHA384 -
BotanMac.HMacSha384- HMAC with SHA-384 (48-byte output) - HMAC-SHA512 -
BotanMac.HMacSha512- HMAC with SHA-512 (64-byte output)
Implementation Notes
- Cloning Not Supported - Calling
clone()throwsCloneNotSupportedExceptionbecause 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 explicitreset()is not needed - Memory Safety - Native resources are guaranteed to be freed even if explicit cleanup is not called, thanks to the Cleaner API
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classstatic final classstatic final classstatic final classstatic final classstatic final classstatic final classstatic final classstatic final classstatic final class -
Method Summary
Modifier and TypeMethodDescriptionclone()protected byte[]protected intprotected voidengineInit(Key key, AlgorithmParameterSpec params) protected voidprotected voidengineUpdate(byte input) protected voidengineUpdate(byte[] input, int offset, int len) protected StringgetBotanMacName(int keySize) Gets the native botan cipher name (e.g.Methods inherited from class javax.crypto.MacSpi
engineUpdate
-
Method Details
-
getBotanMacName
Gets the native botan cipher name (e.g. 'CMAC(AES-128)').- Parameters:
keySize- the key size- Returns:
Stringcontaining the Botan MAC name.- Throws:
InvalidKeyException
-
engineGetMacLength
protected int engineGetMacLength()- Specified by:
engineGetMacLengthin classMacSpi
-
engineInit
- Specified by:
engineInitin classMacSpi- Throws:
InvalidKeyException
-
engineUpdate
protected void engineUpdate(byte input) - Specified by:
engineUpdatein classMacSpi
-
engineUpdate
protected void engineUpdate(byte[] input, int offset, int len) - Specified by:
engineUpdatein classMacSpi
-
engineDoFinal
protected byte[] engineDoFinal()- Specified by:
engineDoFinalin classMacSpi
-
engineReset
protected void engineReset()- Specified by:
engineResetin classMacSpi
-
clone
- Overrides:
clonein classMacSpi- Throws:
CloneNotSupportedException
-