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