Secure Memory Handling

Side-channel claim limit. Nothing on this page claims constant-time behaviour or side-channel resistance for any target: the side-channel harness covers nothing (finding A48) and no measurement exists. The Rust and C cores are designed for constant time and unmeasured; managed runtimes (JIT, GC, bounds checks) make no timing claim. Where this page names constant-time or side-channel techniques, in prose or in code, they are design intent or recommendations, not measured properties.

MetaMUI Crypto Primitives implements comprehensive secure memory handling across all 10 supported platforms.

Key Features

Automatic Memory Clearing

Memory Protection

Platform Implementation

C

#include <metamui_crypto/secure_memory.h>
#include <string.h>

// Secure allocation with automatic clearing
secure_ptr_t key = secure_alloc(32);
if (key != NULL) {
    // Use key for cryptographic operations
    metamui_chacha20_poly1305_encrypt(key, plaintext, ciphertext);
    
    // Secure free automatically zeros memory
    secure_free(key);
}

// Manual secure clearing with memory barrier
void secure_clear_example() {
    uint8_t secret[32];
    // ... use secret for operations ...
    
    // Secure zeroing with compiler barrier
    secure_memzero(secret, sizeof(secret));
    
    // Alternative: explicit_bzero (when available)
    #ifdef __GLIBC__
    explicit_bzero(secret, sizeof(secret));
    #endif
}

// Memory locking for sensitive data
void lock_memory_example() {
    uint8_t sensitive_key[32];
    
    #ifdef _WIN32
    VirtualLock(sensitive_key, sizeof(sensitive_key));
    #else
    mlock(sensitive_key, sizeof(sensitive_key));
    #endif
    
    // Use locked memory
    // ...
    
    // Clear before unlocking
    secure_memzero(sensitive_key, sizeof(sensitive_key));
    
    #ifdef _WIN32
    VirtualUnlock(sensitive_key, sizeof(sensitive_key));
    #else
    munlock(sensitive_key, sizeof(sensitive_key));
    #endif
}

C#

using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using MetaMUI.Crypto;

public class SecureMemoryExample
{
    // Using SecureString for passwords
    public static void SecurePasswordExample()
    {
        using (var securePassword = new SecureString())
        {
            // Build secure string character by character
            foreach (char c in "password")
                securePassword.AppendChar(c);
            
            securePassword.MakeReadOnly();
            
            // Use with cryptographic operations
            DeriveKeyFromPassword(securePassword);
        } // Automatically cleared
    }
    
    // Pinned memory for keys
    public static void PinnedMemoryExample()
    {
        byte[] key = new byte[32];
        GCHandle handle = GCHandle.Alloc(key, GCHandleType.Pinned);
        
        try
        {
            // Fill with random data
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(key);
            }
            
            // Use pinned memory for crypto operations
            ProcessWithKey(handle.AddrOfPinnedObject());
        }
        finally
        {
            // Clear memory before unpinning
            Array.Clear(key, 0, key.Length);
            handle.Free();
        }
    }
    
    // Secure byte array wrapper
    public static void SecureBytesExample()
    {
        using (var secureBytes = new SecureBytes(32))
        {
            secureBytes.Fill(RandomNumberGenerator.GetBytes);
            
            // Use for cryptographic operations
            var cipher = new ChaCha20Poly1305(secureBytes.GetBytes());
            
        } // Automatically cleared and unpinned
    }
}

Python

from metamui_crypto import SecureBytes

# Automatic clearing with context manager
with SecureBytes(32) as key:
    # Use key for cryptographic operations
    cipher = ChaCha20Poly1305(key)
    encrypted = cipher.encrypt(data)
# key is automatically cleared here

Rust

use metamui_crypto::secure::{SecureVec, Zeroize};

// Automatic zeroization on drop
{
    let mut key = SecureVec::new(32);
    // Use key...
} // Automatically zeroed

// Manual zeroization
let mut secret = vec![0u8; 32];
secret.zeroize();

TypeScript/JavaScript

import { SecureBuffer } from '@metamui/crypto';

// Secure buffer with automatic clearing
const key = new SecureBuffer(32);
try {
    // Use key
} finally {
    key.clear(); // Explicit clearing
}

Swift

// Automatic clearing with defer
var key = Data(count: 32)
defer { 
    key.withUnsafeMutableBytes { 
        $0.initializeMemory(as: UInt8.self, repeating: 0) 
    } 
}

Kotlin

// Use try-finally for cleanup
val key = ByteArray(32)
try {
    // Use key
} finally {
    key.fill(0) // Clear memory
}

WASM

// Memory is managed by WASM runtime
// Automatic cleanup when objects go out of scope
const crypto = await MetaMUICrypto.initialize();

// Create secure key - memory managed by WASM
const key = crypto.generateKey(32);
try {
    const cipher = crypto.createCipher('ChaCha20-Poly1305', key);
    const encrypted = cipher.encrypt(data);
} finally {
    // Explicit cleanup if needed
    key.destroy();
}

Go

package main

import (
    "crypto/rand"
    "github.com/SovereignWallet-Network/metamui-crypto-go/secure"
)

// Secure buffer with automatic clearing
func secureBufferExample() {
    key := secure.NewBuffer(32)
    defer key.Destroy() // Automatic zeroing on defer
    
    // Fill with random data
    rand.Read(key.Bytes())
    
    // Use for cryptographic operations
    cipher := NewChaCha20Poly1305(key.Bytes())
    encrypted := cipher.Encrypt(plaintext)
}

// Manual clearing for byte slices
func manualClearingExample() {
    secret := make([]byte, 32)
    defer func() {
        // Explicit zeroing with memory barrier
        for i := range secret {
            secret[i] = 0
        }
        // Force compiler to not optimize away the clearing
        runtime.KeepAlive(secret)
    }()
    
    // Use secret...
    processSecret(secret)
}

// Secure comparison
func secureCompareExample(a, b []byte) bool {
    // Use constant-time comparison
    return subtle.ConstantTimeCompare(a, b) == 1
}

// Protecting against string immutability
func stringHandlingExample(password string) {
    // Convert to mutable byte slice immediately
    passwordBytes := []byte(password)
    defer secure.Clear(passwordBytes)
    
    // Work with bytes, not strings
    key := deriveKey(passwordBytes)
    defer secure.Clear(key)
}

Java

import java.security.SecureRandom;
import java.util.Arrays;
import javax.crypto.SecretKey;
import javax.security.auth.DestroyFailedException;
import com.metamui.crypto.SecureBytes;
import com.metamui.crypto.ChaCha20Poly1305;

public class SecureMemoryExample {
    
    // Using try-with-resources for automatic clearing
    public static void secureByteExample() {
        try (SecureBytes key = SecureBytes.allocate(32)) {
            // Fill with secure random
            new SecureRandom().nextBytes(key.getBytes());
            
            // Use for cryptographic operations
            ChaCha20Poly1305 cipher = new ChaCha20Poly1305(key);
            byte[] encrypted = cipher.encrypt(plaintext);
            
        } // Automatically cleared on close
    }
    
    // Manual clearing with finally block
    public static void manualClearingExample() {
        byte[] secret = new byte[32];
        try {
            new SecureRandom().nextBytes(secret);
            
            // Use secret for operations
            processWithSecret(secret);
            
        } finally {
            // Explicit clearing
            Arrays.fill(secret, (byte) 0);
        }
    }
    
    // Using SecretKey with destroy
    public static void secretKeyExample() throws DestroyFailedException {
        SecretKey key = generateSecretKey();
        try {
            // Use key for operations
            Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            
        } finally {
            // Destroy if destroyable
            if (key instanceof Destroyable && !((Destroyable) key).isDestroyed()) {
                ((Destroyable) key).destroy();
            }
        }
    }
    
    // Character array for passwords (not String)
    public static void passwordHandling(char[] password) {
        try {
            // Use password for key derivation
            byte[] key = deriveKey(password);
            try {
                processWithKey(key);
            } finally {
                Arrays.fill(key, (byte) 0);
            }
        } finally {
            // Clear password array
            Arrays.fill(password, '\0');
        }
    }
}

## Best Practices

1. **Use Secure Wrappers**: Always use platform-specific secure memory wrappers
2. **Minimize Lifetime**: Keep sensitive data in memory for the shortest time possible
3. **Avoid Copies**: Prevent unnecessary copies of sensitive data
4. **Clear on Error**: Ensure memory is cleared even when errors occur
5. **No Logging**: Never log sensitive data
6. **Language-Specific Considerations**:
   - **C/C++**: Use compiler barriers and platform-specific secure functions
   - **C#/Java**: Pin memory when needed, use SecureString/char[] for passwords
   - **Go**: Account for garbage collection, use byte slices over strings
   - **All platforms**: Prefer automatic cleanup mechanisms (RAII, defer, using, try-with-resources)

## Memory Security Guarantees

- **Constant-Time**: not claimed (unmeasured, A48)
- **No Optimization**: Compiler optimizations that might skip clearing are prevented
- **Platform-Specific**: Uses best practices for each platform
- **Tested**: Regular testing ensures memory is properly cleared

## Common Patterns

### Key Derivation
```python
# Python: Derive key and clear intermediate values
salt = secure_random(16)
key = Argon2.derive_key(password, salt)
# password cleared internally
// Go: Key derivation with cleanup
func deriveKeySecurely(password []byte) []byte {
    salt := make([]byte, 16)
    rand.Read(salt)
    defer secure.Clear(password)
    
    key := argon2.DeriveKey(password, salt)
    return key
}

Temporary Secrets

# Python: Use temporary secrets safely
with SecureBytes.random(32) as temp_key:
    encrypted = encrypt_with_temp_key(data, temp_key)
# temp_key cleared automatically
// Java: Temporary secrets with try-with-resources
try (SecureBytes tempKey = SecureBytes.random(32)) {
    byte[] encrypted = encryptWithTempKey(data, tempKey.getBytes());
    return encrypted;
} // tempKey cleared automatically

Error Handling

// C: Ensure cleanup on all paths
int process_secure_data() {
    uint8_t* key = secure_alloc(32);
    if (!key) return -1;
    
    int result = process_with_key(key);
    
    // Always clear, regardless of result
    secure_free(key);
    return result;
}
// C#: Cleanup in finally block
byte[] key = null;
try {
    key = DeriveKey(password);
    return ProcessWithKey(key);
} finally {
    if (key != null) {
        Array.Clear(key, 0, key.Length);
    }
}

See Also