AGENTS.md + code cleanup
This commit is contained in:
parent
21b4169130
commit
9df61e0cd3
20 changed files with 365 additions and 910 deletions
|
|
@ -8,43 +8,22 @@ import java.lang.foreign.MemorySegment;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Cross-platform memory locking and secure zeroing utilities.
|
||||
*
|
||||
* <p>This module provides optional memory protection for sensitive
|
||||
* cryptographic buffers. It fails gracefully if memory locking is
|
||||
* unavailable on the current platform (e.g., Windows on some JVM
|
||||
* configurations).</p>
|
||||
*
|
||||
* <h3>Protection Levels</h3>
|
||||
* <ul>
|
||||
* <li><b>"full"</b> — Memory locking and secure zeroing both available</li>
|
||||
* <li><b>"zeroing_only"</b> — Only secure zeroing available</li>
|
||||
* <li><b>"none"</b> — No memory protection available</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h3>Usage</h3>
|
||||
* <pre>{@code
|
||||
* try (SecureBuffer buf = SecureMemory.secureBytearray(sensitiveData)) {
|
||||
* // buf is locked and ready to use
|
||||
* process(buf.getData());
|
||||
* }
|
||||
* // buf is automatically zeroed and unlocked on exit
|
||||
* }</pre>
|
||||
* Cross-platform memory locking and secure zeroing for sensitive cryptographic buffers. Fails gracefully if unavailable.
|
||||
*/
|
||||
public final class SecureMemory {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private static volatile boolean secureMemoryEnabled = true;
|
||||
|
||||
@Getter
|
||||
private static final boolean HAS_MEMORY_LOCKING;
|
||||
@Getter
|
||||
private static final boolean HAS_SECURE_ZEROING;
|
||||
@Getter
|
||||
@Setter
|
||||
private static volatile boolean secureMemoryEnabled = true;
|
||||
|
||||
static {
|
||||
boolean locking = false;
|
||||
boolean zeroing = false;
|
||||
|
||||
try {
|
||||
locking = initMemoryLocking();
|
||||
zeroing = true; // Secure zeroing is always available at the JVM level
|
||||
|
|
@ -58,16 +37,59 @@ public final class SecureMemory {
|
|||
|
||||
private static boolean initMemoryLocking() {
|
||||
// FFM doesn't support memory locking at this point in time
|
||||
// TODO: Bypass this with native libraries
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a byte array with memory locking and guaranteed zeroing on exit.
|
||||
*
|
||||
* <p>Implements {@link AutoCloseable} for use with try-with-resources.
|
||||
* The buffer is automatically zeroed and unlocked when closed, even
|
||||
* if an exception occurs.</p>
|
||||
* Recommended way to handle sensitive data — use within try-with-resources for secure zeroing.
|
||||
*/
|
||||
public static SecureBuffer secureByteArray(byte[] data, boolean lock) {
|
||||
return new SecureBuffer(data, lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Always attempts locking.
|
||||
*/
|
||||
public static SecureBuffer secureByteArray(byte[] data) {
|
||||
return secureByteArray(data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #secureByteArray(byte[])} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static SecureBuffer secureBytes(byte[] data, boolean lock) {
|
||||
return new SecureBuffer(data, lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #secureByteArray(byte[])} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static SecureBuffer secureBytes(byte[] data) {
|
||||
return secureBytes(data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns protection capabilities: enabled, protection_level, has_memory_locking, has_secure_zeroing, supports_full_protection, page_size.
|
||||
*/
|
||||
public static Map<String, Object> getMemoryProtectionInfo() {
|
||||
String protectionLevel;
|
||||
if (HAS_MEMORY_LOCKING && HAS_SECURE_ZEROING) {
|
||||
protectionLevel = "full";
|
||||
} else if (HAS_SECURE_ZEROING) {
|
||||
protectionLevel = "zeroing_only";
|
||||
} else {
|
||||
protectionLevel = "none";
|
||||
}
|
||||
|
||||
boolean supportsFull = HAS_MEMORY_LOCKING && HAS_SECURE_ZEROING && secureMemoryEnabled;
|
||||
|
||||
return Map.of("enabled", secureMemoryEnabled, "protection_level", protectionLevel, "has_memory_locking", HAS_MEMORY_LOCKING, "has_secure_zeroing", HAS_SECURE_ZEROING, "supports_full_protection", supportsFull, "page_size", Constants.PAGE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps bytes with memory locking and guaranteed zeroing on close. AutoCloseable for try-with-resources.
|
||||
*/
|
||||
public static class SecureBuffer implements AutoCloseable {
|
||||
|
||||
|
|
@ -85,10 +107,8 @@ public final class SecureMemory {
|
|||
private boolean closed;
|
||||
|
||||
/**
|
||||
* Creates a new SecureBuffer wrapping the given data.
|
||||
*
|
||||
* @param data the byte array to wrap
|
||||
* @param lock whether to attempt memory locking
|
||||
* @param data byte array to wrap
|
||||
* @param lock whether to attempt memory locking
|
||||
*/
|
||||
public SecureBuffer(byte[] data, boolean lock) {
|
||||
this.arena = Arena.ofConfined();
|
||||
|
|
@ -110,19 +130,14 @@ public final class SecureMemory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Attempts to lock the buffer in memory, preventing swapping to disk.
|
||||
*
|
||||
* @return {@code true} if locking succeeded, {@code false} otherwise
|
||||
* Locks buffer in memory (prevents disk swapping). Returns false if unavailable.
|
||||
*/
|
||||
public boolean lock() {
|
||||
//data = data.asReadOnly();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks the buffer, allowing it to be swapped to disk.
|
||||
*
|
||||
* @return {@code true} if unlocking succeeded, {@code false} otherwise
|
||||
* Unlocks buffer (allows disk swapping).
|
||||
*/
|
||||
public boolean unlock() {
|
||||
if (!locked) return false;
|
||||
|
|
@ -131,7 +146,7 @@ public final class SecureMemory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Securely zeros the buffer contents.
|
||||
* Securely zeros buffer contents.
|
||||
*/
|
||||
public void zero() {
|
||||
if (data != null) {
|
||||
|
|
@ -150,88 +165,4 @@ public final class SecureMemory {
|
|||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SecureBuffer for the given data with memory locking.
|
||||
*
|
||||
* <p>This is the recommended way to handle sensitive data. The returned
|
||||
* buffer should be used within a try-with-resources block to ensure
|
||||
* secure zeroing on exit.</p>
|
||||
*
|
||||
* @param data the sensitive data bytes
|
||||
* @param lock whether to attempt memory locking
|
||||
* @return a new SecureBuffer
|
||||
*/
|
||||
public static SecureBuffer secureByteArray(byte[] data, boolean lock) {
|
||||
return new SecureBuffer(data, lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SecureBuffer for the given data with memory locking.
|
||||
* Convenience variant that always attempts locking.
|
||||
*
|
||||
* @param data the sensitive data bytes
|
||||
* @return a new SecureBuffer
|
||||
*/
|
||||
public static SecureBuffer secureByteArray(byte[] data) {
|
||||
return secureByteArray(data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SecureBuffer for the given data with memory locking.
|
||||
*
|
||||
* <p><b>Deprecated:</b> Use {@link #secureByteArray(byte[])} instead.
|
||||
* This method exists for compatibility with the Python reference.</p>
|
||||
*
|
||||
* @param data the sensitive data bytes
|
||||
* @param lock whether to attempt memory locking
|
||||
* @return a new SecureBuffer
|
||||
* @deprecated Use {@link #secureByteArray(byte[])} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static SecureBuffer secureBytes(byte[] data, boolean lock) {
|
||||
return new SecureBuffer(data, lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SecureBuffer for the given data with memory locking.
|
||||
*
|
||||
* <p><b>Deprecated:</b> Use {@link #secureByteArray(byte[])} instead.
|
||||
* This method exists for compatibility with the Python reference.</p>
|
||||
*
|
||||
* @param data the sensitive data bytes
|
||||
* @return a new SecureBuffer
|
||||
* @deprecated Use {@link #secureByteArray(byte[])} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static SecureBuffer secureBytes(byte[] data) {
|
||||
return secureBytes(data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information about the current memory protection capabilities.
|
||||
*
|
||||
* @return a map of protection capabilities
|
||||
*/
|
||||
public static Map<String, Object> getMemoryProtectionInfo() {
|
||||
String protectionLevel;
|
||||
if (HAS_MEMORY_LOCKING && HAS_SECURE_ZEROING) {
|
||||
protectionLevel = "full";
|
||||
} else if (HAS_SECURE_ZEROING) {
|
||||
protectionLevel = "zeroing_only";
|
||||
} else {
|
||||
protectionLevel = "none";
|
||||
}
|
||||
|
||||
boolean supportsFull = HAS_MEMORY_LOCKING && HAS_SECURE_ZEROING && secureMemoryEnabled;
|
||||
|
||||
return Map.of(
|
||||
"enabled", secureMemoryEnabled,
|
||||
"protection_level", protectionLevel,
|
||||
"has_memory_locking", HAS_MEMORY_LOCKING,
|
||||
"has_secure_zeroing", HAS_SECURE_ZEROING,
|
||||
"supports_full_protection", supportsFull,
|
||||
"page_size", Constants.PAGE_SIZE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue