Java Platform Guide
Overview
MetaMUI Crypto for Java provides enterprise-grade cryptographic implementations for JVM applications. Supporting Java 8+ and fully compatible with Android, it offers both individual algorithm JARs and convenient suite packages through Maven Central Enterprise repository.
Installation
Enterprise Setup
# Download and run the installer
# Contact sales@metamui.id for access
java -jar metamui-crypto-installer.jar --license-key YOUR_LICENSE_KEY
# Configure Maven settings
cp metamui-settings.xml ~/.m2/settings.xml
Maven Configuration
Add to your pom.xml:
<repositories>
<repository>
<id>metamui-enterprise</id>
<name>MetaMUI Enterprise Repository</name>
<url>https://maven.metamui.id/repository/enterprise</url>
</repository>
</repositories>
<!-- Individual algorithms -->
<dependencies>
<dependency>
<groupId>id.metamui.crypto</groupId>
<artifactId>metamui-blake3</artifactId>
<version>3.0.0-enterprise</version>
</dependency>
<dependency>
<groupId>id.metamui.crypto</groupId>
<artifactId>metamui-mlkem768</artifactId>
<version>3.0.0-enterprise</version>
</dependency>
<dependency>
<groupId>id.metamui.crypto</groupId>
<artifactId>metamui-chacha20poly1305</artifactId>
<version>3.0.0-enterprise</version>
</dependency>
</dependencies>
Gradle Configuration
Add to your build.gradle:
repositories {
maven {
url "https://maven.metamui.id/repository/enterprise"
credentials {
username = "license"
password = System.getenv("METAMUI_LICENSE_KEY")
}
}
}
dependencies {
// Individual algorithms
implementation 'id.metamui.crypto:metamui-blake3:3.0.0-enterprise'
implementation 'id.metamui.crypto:metamui-mlkem768:3.0.0-enterprise'
implementation 'id.metamui.crypto:metamui-chacha20poly1305:3.0.0-enterprise'
// Suite packages
implementation 'id.metamui.crypto:metamui-pqc-suite:3.0.0-enterprise'
implementation 'id.metamui.crypto:metamui-kpqc-suite:3.0.0-enterprise'
implementation 'id.metamui.crypto:metamui-recommended-suite:3.0.0-enterprise'
}
Android Configuration
For Android projects, add to build.gradle:
android {
packagingOptions {
pickFirst 'lib/x86/libmetamui-crypto.so'
pickFirst 'lib/x86_64/libmetamui-crypto.so'
pickFirst 'lib/armeabi-v7a/libmetamui-crypto.so'
pickFirst 'lib/arm64-v8a/libmetamui-crypto.so'
}
}
dependencies {
implementation 'id.metamui.crypto:metamui-android:3.0.0-enterprise'
}
Usage Examples
Basic Hashing with BLAKE3
import id.metamui.crypto.Blake3;
import id.metamui.crypto.HashResult;
public class HashingExample {
public static void main(String[] args) {
// Simple hashing
byte[] data = "Hello, World!".getBytes(StandardCharsets.UTF_8);
byte[] hash = Blake3.hash(data);
System.out.println("BLAKE3 Hash: " + bytesToHex(hash));
// Streaming hash for large data
Blake3.Hasher hasher = Blake3.newHasher();
hasher.update(data1);
hasher.update(data2);
byte[] result = hasher.finalize();
// Keyed hashing (MAC)
byte[] key = new byte[32];
SecureRandom.getInstanceStrong().nextBytes(key);
byte[] mac = Blake3.keyedHash(key, data);
// Derive key material
byte[] derivedKey = Blake3.deriveKey("context string", data);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
}
Post-Quantum Key Exchange (ML-KEM-768)
import id.metamui.crypto.pqc.MlKem768;
import id.metamui.crypto.pqc.KemKeypair;
import id.metamui.crypto.pqc.EncapsulationResult;
public class QuantumSafeKeyExchange {
public static void demonstrateKEM() throws Exception {
// Generate keypair
KemKeypair keypair = MlKem768.generateKeypair();
byte[] publicKey = keypair.getPublicKey();
byte[] secretKey = keypair.getSecretKey();
// Sender: Encapsulate shared secret
EncapsulationResult encapResult = MlKem768.encapsulate(publicKey);
byte[] ciphertext = encapResult.getCiphertext();
byte[] sharedSecretSender = encapResult.getSharedSecret();
// Receiver: Decapsulate shared secret
byte[] sharedSecretReceiver = MlKem768.decapsulate(ciphertext, secretKey);
// Verify shared secrets match
boolean match = Arrays.equals(sharedSecretSender, sharedSecretReceiver);
System.out.println("Shared secrets match: " + match);
// Use shared secret for AES encryption
SecretKeySpec aesKey = new SecretKeySpec(sharedSecretSender, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
// Clean up sensitive data
Arrays.fill(secretKey, (byte) 0);
Arrays.fill(sharedSecretSender, (byte) 0);
Arrays.fill(sharedSecretReceiver, (byte) 0);
}
}
Authenticated Encryption (ChaCha20-Poly1305)
import id.metamui.crypto.ChaCha20Poly1305;
import id.metamui.crypto.AeadResult;
public class SecureMessaging {
private static final int KEY_SIZE = 32;
private static final int NONCE_SIZE = 12;
private static final int TAG_SIZE = 16;
public static AeadResult encrypt(byte[] plaintext, byte[] key,
byte[] associatedData) throws Exception {
// Generate random nonce
byte[] nonce = new byte[NONCE_SIZE];
SecureRandom.getInstanceStrong().nextBytes(nonce);
// Create cipher instance
ChaCha20Poly1305 cipher = new ChaCha20Poly1305(key);
// Encrypt with associated data
byte[] ciphertext = cipher.encrypt(nonce, plaintext, associatedData);
return new AeadResult(ciphertext, nonce);
}
public static byte[] decrypt(byte[] ciphertext, byte[] nonce,
byte[] key, byte[] associatedData) throws Exception {
ChaCha20Poly1305 cipher = new ChaCha20Poly1305(key);
// Decrypt and verify
byte[] plaintext = cipher.decrypt(nonce, ciphertext, associatedData);
return plaintext;
}
public static void demonstrateAEAD() throws Exception {
// Generate key
byte[] key = new byte[KEY_SIZE];
SecureRandom.getInstanceStrong().nextBytes(key);
// Data to encrypt
byte[] message = "Secret message".getBytes(StandardCharsets.UTF_8);
byte[] metadata = "Public metadata".getBytes(StandardCharsets.UTF_8);
// Encrypt
AeadResult encrypted = encrypt(message, key, metadata);
// Decrypt
byte[] decrypted = decrypt(encrypted.getCiphertext(),
encrypted.getNonce(), key, metadata);
System.out.println("Decrypted: " + new String(decrypted, StandardCharsets.UTF_8));
}
}
Digital Signatures with Dilithium
import id.metamui.crypto.pqc.Dilithium3;
import id.metamui.crypto.pqc.SignatureKeypair;
public class QuantumSafeSignatures {
public static void demonstrateSignatures() throws Exception {
// Generate signing keypair
SignatureKeypair keypair = Dilithium3.generateKeypair();
byte[] publicKey = keypair.getPublicKey();
byte[] privateKey = keypair.getPrivateKey();
// Sign a message
byte[] message = "Important document".getBytes(StandardCharsets.UTF_8);
byte[] signature = Dilithium3.sign(message, privateKey);
// Verify signature
boolean valid = Dilithium3.verify(message, signature, publicKey);
System.out.println("Signature valid: " + valid);
// Batch verification for performance
List<VerificationTask> tasks = new ArrayList<>();
for (int i = 0; i < 100; i++) {
tasks.add(new VerificationTask(messages[i], signatures[i], publicKeys[i]));
}
boolean[] results = Dilithium3.batchVerify(tasks);
// Secure cleanup
Arrays.fill(privateKey, (byte) 0);
}
}
Password Hashing with Argon2id
import id.metamui.crypto.Argon2id;
import id.metamui.crypto.Argon2Config;
import id.metamui.crypto.Argon2Result;
public class PasswordManager {
public static String hashPassword(String password) throws Exception {
// Generate salt
byte[] salt = new byte[16];
SecureRandom.getInstanceStrong().nextBytes(salt);
// Configure Argon2id parameters
Argon2Config config = Argon2Config.builder()
.memoryCost(65536) // 64 MB
.timeCost(4) // 4 iterations
.parallelism(2) // 2 threads
.hashLength(32) // 32 bytes output
.salt(salt)
.build();
// Hash password
Argon2Result result = Argon2id.hash(password.toCharArray(), config);
// Return encoded string (includes all parameters)
return result.getEncoded();
}
public static boolean verifyPassword(String password, String encodedHash) {
return Argon2id.verify(encodedHash, password.toCharArray());
}
public static void demonstratePasswordHashing() throws Exception {
String password = "userPassword123!";
// Hash password
String hash = hashPassword(password);
System.out.println("Encoded hash: " + hash);
// Verify password
boolean valid = verifyPassword(password, hash);
System.out.println("Password valid: " + valid);
// Test invalid password
boolean invalid = verifyPassword("wrongPassword", hash);
System.out.println("Wrong password rejected: " + !invalid);
}
}
Suite Package Usage
PQC Suite Example
import id.metamui.crypto.suites.PQCSuite;
import static id.metamui.crypto.suites.PQC.*;
public class PostQuantumCrypto {
public static void usePQCSuite() throws Exception {
// ML-KEM for key exchange
var kemKeypair = MlKem768.generateKeypair();
var encapResult = MlKem768.encapsulate(kemKeypair.getPublicKey());
// ML-DSA for signatures
var dsaKeypair = MlDsa65.generateKeypair();
byte[] signature = MlDsa65.sign(message, dsaKeypair.getPrivateKey());
// Falcon for compact signatures
var falconKeypair = Falcon512.generateKeypair();
byte[] compactSig = Falcon512.sign(message, falconKeypair.getPrivateKey());
// SLH-DSA for stateless signatures
var slhKeypair = SlhDsaShake256f.generateKeypair();
byte[] statelessSig = SlhDsaShake256f.sign(message, slhKeypair.getPrivateKey());
// XMSS for stateful signatures
var xmssKeypair = XmssMtShake256h60.generateKeypair();
byte[] statefulSig = XmssMtShake256h60.sign(message, xmssKeypair.getPrivateKey());
}
}
KPQC Suite Example
import id.metamui.crypto.suites.KPQCSuite;
import static id.metamui.crypto.suites.KPQC.*;
public class KoreanPQC {
public static void useKPQCSuite() throws Exception {
// SMAUG-T for key encapsulation
var smaugKeypair = SmaugT3.generateKeypair();
var smaugResult = SmaugT3.encapsulate(smaugKeypair.getPublicKey());
// Haetae for signatures
var haetaeKeypair = Haetae3.generateKeypair();
byte[] haetaeSig = Haetae3.sign(message, haetaeKeypair.getPrivateKey());
// AIMer for MPC-based signatures
var aimerKeypair = Aimer128f.generateKeypair();
byte[] aimerSig = Aimer128f.sign(message, aimerKeypair.getPrivateKey());
// NTRU+ for alternative KEM
var ntruKeypair = NtruPlus768.generateKeypair();
var ntruResult = NtruPlus768.encapsulate(ntruKeypair.getPublicKey());
// MQSign for multivariate signatures
var mqKeypair = MqSign128.generateKeypair();
byte[] mqSig = MqSign128.sign(message, mqKeypair.getPrivateKey());
}
}
Spring Boot Integration
@Configuration
@EnableConfigurationProperties(MetaMUICryptoProperties.class)
public class CryptoConfiguration {
@Bean
public Blake3Service blake3Service() {
return new Blake3Service();
}
@Bean
public MlKem768Service mlKem768Service() {
return new MlKem768Service();
}
@Bean
@ConditionalOnProperty(
prefix = "metamui.crypto",
name = "hardware-acceleration",
havingValue = "true"
)
public HardwareAccelerator hardwareAccelerator() {
return new NativeHardwareAccelerator();
}
}
@Service
public class CryptoService {
private final Blake3Service blake3;
private final MlKem768Service mlKem;
@Autowired
public CryptoService(Blake3Service blake3, MlKem768Service mlKem) {
this.blake3 = blake3;
this.mlKem = mlKem;
}
public byte[] hashData(byte[] data) {
return blake3.hash(data);
}
public KemKeypair generateQuantumSafeKeypair() {
return mlKem.generateKeypair();
}
}
Android Integration
public class CryptoActivity extends AppCompatActivity {
private MetaMUICrypto crypto;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialize MetaMUI Crypto
crypto = MetaMUICrypto.initialize(this, BuildConfig.METAMUI_LICENSE_KEY);
// Check hardware capabilities
if (crypto.hasHardwareAES()) {
Log.d("Crypto", "Hardware AES available");
}
// Use Android Keystore for key storage
storeKeyInKeystore();
}
private void storeKeyInKeystore() throws Exception {
// Generate key using MetaMUI
byte[] key = Blake3.deriveKey("app-encryption-key", getDeviceId());
// Store in Android Keystore
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry(secretKey);
keyStore.setEntry("MetaMUIKey", secretKeyEntry,
new KeyStore.PasswordProtection("".toCharArray()));
}
private byte[] getDeviceId() {
String androidId = Settings.Secure.getString(
getContentResolver(),
Settings.Secure.ANDROID_ID
);
return androidId.getBytes(StandardCharsets.UTF_8);
}
}
Concurrent Operations
import java.util.concurrent.*;
public class ConcurrentCrypto {
private static final ExecutorService executor =
Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
public static Map<String, byte[]> hashFilesInParallel(List<File> files)
throws InterruptedException, ExecutionException {
List<Future<HashResult>> futures = new ArrayList<>();
for (File file : files) {
Future<HashResult> future = executor.submit(() -> {
try (InputStream is = new FileInputStream(file)) {
Blake3.Hasher hasher = Blake3.newHasher();
byte[] buffer = new byte[8192];
int read;
while ((read = is.read(buffer)) != -1) {
hasher.update(buffer, 0, read);
}
return new HashResult(file.getName(), hasher.finalize());
} catch (IOException e) {
throw new RuntimeException(e);
}
});
futures.add(future);
}
Map<String, byte[]> results = new HashMap<>();
for (Future<HashResult> future : futures) {
HashResult result = future.get();
results.put(result.filename, result.hash);
}
return results;
}
static class HashResult {
final String filename;
final byte[] hash;
HashResult(String filename, byte[] hash) {
this.filename = filename;
this.hash = hash;
}
}
}
Secure Memory Management
import id.metamui.crypto.security.SecureMemory;
import id.metamui.crypto.security.SecureString;
public class SecureOperations {
public static void handleSensitiveData() {
// Allocate secure memory
try (SecureMemory memory = SecureMemory.allocate(32)) {
byte[] buffer = memory.getBuffer();
// Use buffer for sensitive operations
generateSecretKey(buffer);
// Memory is automatically zeroed when closed
}
// Secure string handling
try (SecureString password = new SecureString("sensitive_password")) {
char[] chars = password.getChars();
// Use password
authenticate(chars);
// Chars are automatically cleared
}
// Lock memory pages (prevent swapping)
byte[] criticalData = new byte[1024];
SecureMemory.lock(criticalData);
try {
// Perform critical operations
} finally {
SecureMemory.unlock(criticalData);
Arrays.fill(criticalData, (byte) 0);
}
}
}
JNI Performance Optimization
public class NativeCrypto {
static {
System.loadLibrary("metamui-crypto-jni");
}
// Native method declarations
private static native byte[] blake3HashNative(byte[] data);
private static native byte[] chaCha20Poly1305EncryptNative(
byte[] plaintext, byte[] key, byte[] nonce, byte[] aad
);
public static byte[] fastHash(byte[] data) {
// Use native implementation for large data
if (data.length > 1024 * 1024) { // > 1 MB
return blake3HashNative(data);
} else {
// Use pure Java for small data
return Blake3.hash(data);
}
}
}
Error Handling
import id.metamui.crypto.exceptions.*;
public class ErrorHandling {
public static void handleCryptoErrors() {
try {
MlKem768.encapsulate(publicKey);
} catch (InvalidKeyException e) {
// Handle invalid key
logger.error("Invalid public key", e);
} catch (CryptoException e) {
// Handle general crypto errors
logger.error("Cryptographic operation failed", e);
} catch (LicenseException e) {
// Handle licensing issues
logger.error("License validation failed", e);
notifyLicenseExpiry();
} catch (UnsupportedAlgorithmException e) {
// Handle unsupported algorithms
logger.error("Algorithm not available", e);
}
}
}
Performance Benchmarks
| Algorithm | Operation | Time (ms) | Throughput |
|---|---|---|---|
| BLAKE3 | Hash 1 MB | 1.0 | 1 GB/s |
| ChaCha20-Poly1305 | Encrypt 1 MB | 1.5 | 667 MB/s |
| ML-KEM-768 | Key Generation | 0.07 | 14,285 ops/s |
| Dilithium3 | Sign | 0.4 | 2,500 ops/s |
| Argon2id | Hash (64MB, 4 iter) | 120 | 8 ops/s |
Platform Support
| JVM Version | Support Level | Notes |
|---|---|---|
| Java 21 | ✅ Full | Latest LTS, recommended |
| Java 17 | ✅ Full | LTS, full support |
| Java 11 | ✅ Full | LTS, full support |
| Java 8 | ✅ Full | Extended support |
| Android 7+ | ✅ Full | API Level 24+ |
| GraalVM | ⚠️ Limited | Native image support |
License Management
import id.metamui.crypto.license.LicenseManager;
import id.metamui.crypto.license.LicenseInfo;
public class LicenseManagement {
public static void checkLicense() {
LicenseManager manager = LicenseManager.getInstance();
// Check license status
LicenseInfo info = manager.getLicenseInfo();
System.out.println("License valid until: " + info.getExpiryDate());
System.out.println("Algorithms licensed: " + info.getAlgorithmCount());
System.out.println("Support tier: " + info.getSupportTier());
// Validate specific algorithm access
if (manager.isAlgorithmLicensed("ML-KEM-768")) {
// Use ML-KEM-768
}
// Register license expiry callback
manager.onLicenseExpiring((daysRemaining) -> {
logger.warn("License expiring in {} days", daysRemaining);
if (daysRemaining <= 7) {
sendLicenseRenewalNotification();
}
});
}
}
Testing
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class CryptoTest {
@Test
public void testBlake3Hashing() {
byte[] data = "test data".getBytes(StandardCharsets.UTF_8);
byte[] hash = Blake3.hash(data);
assertEquals(32, hash.length);
assertNotNull(hash);
// Verify deterministic
byte[] hash2 = Blake3.hash(data);
assertArrayEquals(hash, hash2);
}
@Test
public void testMlKem768KeyExchange() throws Exception {
// Generate keypairs
var aliceKeypair = MlKem768.generateKeypair();
var bobKeypair = MlKem768.generateKeypair();
// Alice encapsulates for Bob
var encapResult = MlKem768.encapsulate(bobKeypair.getPublicKey());
// Bob decapsulates
byte[] sharedSecret = MlKem768.decapsulate(
encapResult.getCiphertext(),
bobKeypair.getSecretKey()
);
// Verify shared secrets match
assertArrayEquals(encapResult.getSharedSecret(), sharedSecret);
}
}
Support Resources
- Documentation: Included in JAR files
- Javadoc: Available at javadoc.metamui.id
- Sample Projects:
/opt/metamui/crypto/samples/java/ - Support Portal: support.metamui.id
- Enterprise Support: enterprise-support@metamui.id
- Maven Repository: maven.metamui.id