Native Operations
Secure operations in EntanglementLib are performed in a Rust-based native library called entlib-native.
This native bridge module utilizes Java's Linker API (Project Panama) to overcome the instability and overhead of the existing JNI method, and implements high-performance operations without data copying by directly sharing memory addresses between Java and Rust.
The most core feature is compiler optimization-resistant secure erasure. Using Rust's ownership concept and the zeroize crate, it prevents the compiler from skipping data erasure for optimization reasons when releasing memory, and forces data to be physically overwritten with zeros. This fundamentally blocks information leakage through Data Remanence.
In addition, security has been strengthened through key masking and entanglement logic. By not storing the encryption key as is in memory, but storing it after XOR operation with a random mask, it is designed so that even if an attacker steals a memory dump, the original key cannot be recovered without the mask.
This module is responsible for native acceleration of Post-Quantum Cryptography. It processes the latest encryption algorithms such as ML-DSA, ML-KEM, and X25519 at high speed using SIMD (Single Instruction Multiple Data) instructions, and minimizes dependency on external Java libraries such as BouncyCastle to secure system lightweightness and independence.
Technology
The interaction between entlib-native and EntanglementLib follows a highly optimized mechanism that shares memory models and synchronizes security contexts, rather than simple function calls. This process can be largely divided into FFI Architecture, Memory Sharing Model, and Secure Operation Pipeline.
FFI Architecture
EntanglementLib implemented bridging based on the FFM API (Foreign Function & Memory API), which was officially introduced in Java 22, to eliminate the overhead and complexity of the existing JNI (Java Native Interface).
- Linking:
NativeLinkerManagerloads the native library (.so,.dll,.dylib) suitable for the operating system and looks up symbols (function addresses) throughLinker.nativeLinker(). In this process, it creates a downcall handle that follows the C ABI (Application Binary Interface) convention, allowing Java to call native functions as if they were normal methods. - Symbol Binding: On the Java side,
java.lang.invoke.MethodHandleis used to define the signature (argument type, return type) of the native function. For example, the secure erasure function is bound to receive a memory address (ADDRESS) and length (JAVA_LONG) as arguments.
Zero-Copy Memory Model
The core of this bridging is direct reference without data copying. By eliminating unnecessary marshalling costs between the Java heap and the native heap, was achieved.
SensitiveDataContainer allocates data to the native memory area (Off-Heap), not the Java heap. This address is managed as a java.lang.foreign.MemorySegment object, and the base address (pointer) of this segment is passed directly to Rust.
On the Rust side, the received raw pointer (*mut u8) and length (usize) are converted to a Rust slice (&mut [u8]) via std::slice::from_raw_parts_mut within an unsafe block. This allows Rust to control the memory area allocated by Java as if it were its own.
Secure Erasure and Lifecycle Control
The lifecycle of data is managed by combining Java's Arena scope and Rust's zeroize logic.
- Java: When
SensitiveDataContainer#close()is called, it first cleans up child containers bound to thebindingslist field. - Bridge: Calls the
entanglement_secure_wipenative function to pass the address of the memory segment. - Rust: Uses the
zeroizecrate to physically overwrite the memory area with zeros. At this time, avolatilewrite is performed to prevent compiler optimization (dead code elimination), securing resistance to memory dump attacks (anti-data remanence). - Panic Safety: Since a panic during Rust execution risks collapsing the entire JVM, the entry point on the Rust side is wrapped with
panic::catch_unwindto safely isolate exception situations.
Encryption Operation Pipeline
The operation flow upon encryption request is as follows:
- Strategy Pattern Algorithm Call: The user calls a Java method such as
AESStrategy. - Pointer Passing: Java passes the
MemorySegmentaddresses of input data, output buffer, key, andIVto native code. - SIMD Accelerated Operation: Rust accesses data through the passed pointer and performs parallel operations utilizing SIMD instructions such as AVX2 and NEON.
- Direct Write: The operation result (ciphertext, etc.) is directly written to the output buffer pointer location pre-allocated by Java without a separate return process.
Currently, major PQC algorithms are implemented using the libcrux crate.
Verification of Directly Implemented Algorithms
The entlib-native library directly implements major PQC algorithms according to the latest FIPS standardization contents, and has decided as its primary goal to pass major verification tasks such as NIST ACVP (Automated Cryptographic Validation Protocol) verification and strict and complex private verification. Once this goal is achieved, additional work will be performed to perfect the algorithms, such as optimization and stabilization, additional security verification, and introduction to test production.
Currently, in the case of the key generation (keygen) logic of the Stateless Hash-based Digital Signature Algorithm (SLH-DSA), it has passed NIST ACVP verification, and the remaining logic is also scheduled to be verified in a consistent format.
Details regarding this are organized in another document.