Java

Java

Java

Topics on Semeru (Java) on IBM Z

 View Only

Complete Guide to OpenJCEPlus

By Farshad Rahimi Asl posted 4 days ago

  

1. Introduction

OpenJCEPlus [1] is a Java security provider that extends the Java Cryptography Architecture (JCA) and Java Cryptography Extension (JCE) APIs by providing core and additional cryptographic algorithms and functionalities. It aims to enhance the security and flexibility of Java applications by offering a wide range of cryptographic services, such as encryption, decryption, digital signatures, and key management.

OpenJCEPlus typically supports various algorithms and functionalities, allowing developers to implement more advanced security features in their applications. OpenJCEPlus can be particularly useful for developers looking to comply with specific security standards or requirements that necessitate using certain cryptographic methods.

1.1. Features

OpenJCEPlus offers several functionality, security, compliance, and performance features:

  • Comprehensive Algorithm Support: OpenJCEPlus offers comprehensive support for a wide range of cryptographic algorithms available in the Java JCA and JCE APIs. This includes advanced symmetric encryption algorithms such as AES and ChaCha20, asymmetric encryption algorithms like RSA and Elliptic Curve Cryptography (ECC), robust hashing functions including SHA-256 and SHA-3, as well as various digital signature schemes such as DSA and ECDSA, ensuring a versatile and secure cryptographic framework for diverse applications. OpenJCEPlus supports Post-Quantum Cryptography (PQC) algorithms, including NIST-approved ML-KEM (Module-Lattice-Based Key-Encapsulation Mechanism) and ML-DSA (Module-Lattice-Based Digital Signature Algorithm). This integration enhances security by safeguarding data against future quantum computing threats, aligning with contemporary cryptographic standards.

  • Compliance with Standards: OpenJCEPlus supports cryptographic standards, such as FIPS (Federal Information Processing Standards) 140-3, making it suitable for applications that require strict security guidelines.

  • Ease of Use: The library typically provides a straightforward API that allows developers to easily integrate cryptographic functions into their Java applications without requiring in-depth knowledge of cryptography.

  • Performance Optimization: OpenJCEPlus utilizes performance optimizations, ensuring that cryptographic operations are efficient and suitable for high-load applications.

  • Community and Support: Being an open-source project, OpenJCEPlus has an active community of developers who contribute to its development, provide support, and share best practices for using the component.

1.2. Use Cases

Some of the important OpenJCEPlus use-cases are as follows:

  • Secure Communication: Developers can use OpenJCEPlus to implement secure communication protocols, ensuring that data transmitted over networks is encrypted and protected from eavesdropping. In addition, OpenJCEPlus works seamlessly with Java's Java Secure Socket Extension (JSSE), providing enhanced cryptographic capabilities and secure communication features for Java applications. This integration allows developers to leverage advanced security protocols and algorithms, ensuring robust data protection and secure connections. 

  • Data Protection: Applications that handle sensitive data can leverage the OpenJCEPlus to encrypt data at rest, ensuring that unauthorized access is prevented.

  • Digital Signatures: OpenJCEPlus can be used to create and verify digital signatures, which are essential for ensuring the authenticity and integrity of messages and documents. 

  • Key Management: OpenJCEPlus provides key generation capabilities, allowing users to select appropriate cryptographic algorithms and utilize secure random number generators to create unpredictable keys.

 Overall, OpenJCEPlus is a valuable resource for Java developers looking to implement robust cryptographic solutions in their applications. It provides a flexible and powerful toolkit for addressing a wide range of security needs by extending the capabilities of the Java JCA and JCE APIs.

1.3. Resources

For the most accurate and up-to-date information, developers should refer to the official documentation and community resources associated with OpenJCEPlus.

OpenJCEPlus is included with the IBM Semeru Runtime Certified Edition [2] and the IBM Semeru Runtime Open Edition [3] for various platforms. More information regarding the latest features and algorithms is available in the Semeru SDK documents for version 11 [4], 17 [5], and 21 [6].

2. Architecture

In a Java user application, developers can use Java JCA and JCE APIs to implement secure cryptographic operations seamlessly. The application typically imports the necessary classes from the java.security and javax.crypto packages, which provide access to the various cryptographic functionalities. For instance, to generate a secure key, a developer might use the KeyPairGenerator class from JCA, while for encrypting data, they would utilize the CipherSpi class from JCE. The application can create instances of these classes, configure them with the desired algorithms and parameters, and then invoke methods to perform operations such as key generation, encryption, and decryption. By following this structured approach, the application can ensure robust security practices while benefiting from the flexibility of the provider model inherent in JCA and the advanced capabilities offered by JCE.

Figure 1: OpenJCEPlus architecture and flow diagram

Figure 1: OpenJCEPlus architecture and flow diagram

OpenJCEPlus is a security provider that implements the Java JCA and JCE APIs, offering comprehensive cryptographic services tailored for Java applications. By adhering to the JCA framework, OpenJCEPlus offers a range of cryptographic algorithms and functionalities, allowing developers to seamlessly integrate secure operations into their applications. It includes implementations for key generation, message digests, and digital signatures, ensuring compatibility with the standard JCA interfaces. Additionally, OpenJCEPlus enhances the JCE capabilities by offering robust encryption and decryption algorithms, supporting advanced features such as key management and secure communication protocols. Developers can easily configure OpenJCEPlus as a security provider in their Java applications, enabling them to utilize its cryptographic services through familiar JCA and JCE APIs, while benefiting from the flexibility and extensibility that the provider model offers. This integration allows for a secure and efficient implementation of cryptographic operations, meeting the diverse security needs of modern applications.

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.KeyGenerator;

public class OpenJCEPlusExample {
    public static void main(String[] args) {
        try {
            // Add OpenJCEPlus as a security provider
            Security.addProvider(new com.ibm.crypto.plus.provider.OpenJCEPlus());

            // Generate a key pair using KeyPairGenerator (JCA) with OpenJCEPlus
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA", "OpenJCEPlus");
            keyPairGen.initialize(2048); // Key size
            KeyPair keyPair = keyPairGen.generateKeyPair();
            System.out.println("Generated RSA Key Pair using OpenJCEPlus.");

            // Generate a symmetric key using KeyGenerator (JCE) with OpenJCEPlus
            KeyGenerator keyGen = KeyGenerator.getInstance("AES", "OpenJCEPlus");
            keyGen.init(256); // Key size
            SecretKey secretKey = keyGen.generateKey();
            System.out.println("Generated AES Secret Key using OpenJCEPlus.");

            // Create a message digest using MessageDigest (JCA) with OpenJCEPlus
            MessageDigest digest = MessageDigest.getInstance("SHA-256", "OpenJCEPlus");
            String message = "Hello, OpenJCEPlus!";
            byte[] hash = digest.digest(message.getBytes());
            System.out.println("Message Digest (SHA-256): " + java.util.Base64.getEncoder().encodeToString(hash));

            // Encrypt data using Cipher (JCE) with OpenJCEPlus
            Cipher cipher = Cipher.getInstance("AES", "OpenJCEPlus");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            String dataToEncrypt = "Sensitive Data";
            byte[] encryptedData = cipher.doFinal(dataToEncrypt.getBytes());
            System.out.println("Encrypted Data: " + java.util.Base64.getEncoder().encodeToString(encryptedData));

        } catch (NoSuchAlgorithmException | javax.crypto.NoSuchPaddingException | java.security.InvalidKeyException | javax.crypto.BadPaddingException | javax.crypto.IllegalBlockSizeException e) {
            e.printStackTrace();
        }
    }
}

OpenJCEPlus security provider is designed with a dual-layer architecture that combines both Java and native components to implement the Java JCA and JCE APIs effectively. The Java layer serves as the interface for developers, providing a familiar and user-friendly API that adheres to the standard JCA and JCE specifications. This layer handles high-level cryptographic operations, such as key management and data encryption, ensuring easy integration into Java applications. Beneath this, the native layer leverages optimized cryptographic libraries and algorithms implemented in lower-level languages like C or C++. This native layer enhances performance and security by utilizing hardware acceleration and platform-specific optimizations, which can be crucial for computationally intensive tasks. By combining these two layers, OpenJCEPlus maintains compatibility with Java's security framework and delivers improved efficiency and speed, making it a robust choice for developers seeking to implement secure cryptographic solutions in their applications.

OpenJCEPlus security provider connects to Open Cryptography Kit for C (OCKC) [7] through its native layer, enabling efficient and secure underlying cryptographic operations. This integration allows OpenJCEPlus to leverage the powerful cryptographic capabilities offered by OCKC, which is optimized for performance on IBM hardware platforms. When a Java application invokes cryptographic functions through the JCA and JCE APIs provided by OpenJCEPlus, the requests are processed by the Java layer and then seamlessly passed to the native layer. The native layer interfaces with OCKC, utilizing its high-performance libraries to execute complex cryptographic algorithms, such as encryption, decryption, and hashing. This architecture not only enhances the overall performance of cryptographic operations by taking advantage of OCKC's optimizations but also ensures that the security standards required by enterprise applications are met. As a result, developers can achieve robust security and efficiency in their applications while maintaining a straightforward Java interface.

OCKC utilizes OpenSSL as its foundational library for performing underlying cryptographic operations on all supported platforms, including z/OS, thereby benefiting from the extensive capabilities and optimizations that OpenSSL offers. By integrating OpenSSL, OCKC can access a wide range of well-established cryptographic algorithms, including symmetric and asymmetric encryption, hashing functions, and digital signatures, all critical for secure data processing. This integration allows OCKC to leverage OpenSSL's performance enhancements and security features, ensuring that cryptographic operations are executed efficiently and reliably. When OpenJCEPlus connects to OCKC through its native layer, it indirectly taps into OpenSSL's robust implementation, enabling high-performance cryptographic functions essential for enterprise applications. This layered approach enhances the overall security posture of applications using OpenJCEPlus and ensures compliance with industry standards, as OpenSSL is widely recognized and trusted in the cryptographic community.

OCKC on z/OS and zLinux takes advantage of the Central Processor Assist for Cryptographic Function (CPACF) [8] hardware acceleration features to enhance the performance of certain cryptographic algorithms, particularly Advanced Encryption Standard (AES). CPACF is a specialized hardware component designed to offload cryptographic processing from the main CPU, allowing for faster execution of encryption and decryption operations. When OCKC is invoked to perform AES operations, it can leverage CPACF to execute these tasks more efficiently, significantly reducing the time required for processing large volumes of data. This hardware acceleration not only improves throughput but also optimizes resource utilization on the z/OS platform, enabling applications to handle cryptographic workloads with greater speed and efficiency. By integrating CPACF capabilities, OCKC ensures that organizations can achieve high levels of security without compromising performance, making it an ideal choice for enterprise environments that demand robust encryption and rapid processing times.

3. Installation

OpenJCEPlus is included by default in the IBM Semeru Runtime Certified Edition and the IBM Semeru Runtime Open Edition for various platforms. This integration allows developers to leverage enhanced cryptographic functionalities seamlessly within their applications. To utilize OpenJCEPlus as the primary cryptographic provider, users can modify the java.security file, typically located in the JDK's conf/security directory. By adding OpenJCEPlus as the first provider in the list of security providers within this file, developers can ensure that their applications prioritize the cryptographic algorithms and features offered by OpenJCEPlus, thereby enhancing security and performance in cryptographic operations.

OpenJCEPlus is the default and first security provider in the JDK java.security file on z/OS for the IBM Semeru Runtime Certified Edition 11+, which is as follows:


#
# List of providers and their preference orders in java.security file:
#
security.provider.1=OpenJCEPlus
security.provider.2=IBMZSecurity
security.provider.3=SUN
security.provider.4=SunRsaSign
security.provider.5=SunEC
security.provider.6=SunJSSE
security.provider.7=SunJCE
security.provider.8=SunJGSS
security.provider.9=SunSASL
security.provider.10=XMLDSig
security.provider.11=SunPCSC
security.provider.12=JdkLDAP
security.provider.13=JdkSASL
security.provider.14=SunPKCS11

Another way to install the OpenJCEPlus provider is through Java code, which offers a programmatic approach to adding the provider at runtime. This can be accomplished using the Security.insertProviderAt() and Security.addProvider() methods. By invoking this method and passing an instance of the OpenJCEPlus provider, developers can dynamically register it as a security provider during the execution of their application. This approach is useful for applications that require flexibility in managing security providers or for those that may not have access to modify java.security file. By adding OpenJCEPlus programmatically, developers can ensure that their applications utilize cryptographic capabilities without altering the underlying configuration files. The following code snippet shows how to insert OpenJCEPlus as the first provider.

// Insert OpenJCEPlus as the first provider
Security.removeProvider("OpenJCEPlus");
Security.insertProviderAt(new com.ibm.crypto.plus.provider.OpenJCEPlus(), 1);

Users of z/OS can also configure java.security file to utilize the IBMJCEHYBRID [9] as a failover provider and IBMJCECCA [10] as a hardware-based security provider in conjunction with OpenJCEPlus as a software-based security provider to access both software and hardware-based cryptographic operations with built-in failover capabilities. This configuration ensures reliable and robust security solutions, enabling seamless transitions between different cryptographic implementations while maintaining high availability and performance for sensitive operations.


#
# List of providers and their preference orders in java.security file on z/OS:
#
security.provider.1=IBMJCEHYBRID
security.provider.2=IBMJCECCA
security.provider.3=IBMZSecurity
security.provider.4=OpenJCEPlus
security.provider.5=SUN
security.provider.6=SunRsaSign
security.provider.7=SunEC
security.provider.8=SunJSSE
security.provider.9=SunJCE
security.provider.10=SunJGSS
security.provider.11=SunSASL
security.provider.12=XMLDSig
security.provider.13=SunPCSC
security.provider.14=JdkLDAP
security.provider.15=JdkSASL
security.provider.16=SunPKCS11

4. Performance

To evaluate performance, we conducted a comparative analysis of OpenJCEPlus against IBMJCECCA in Java 17.0.16.0 and IBMJCE in Java 8.0.8.50 on z/OS. This comparison focused on the AES cipher in Galois/Counter Mode (AES-GCM) and ECDSA signature (SHA256withECDSA-secp256r1) algorithms. By assessing the efficiency and speed of these implementations, we aimed to provide insights into the performance characteristics under various encryption, signing, and verification scenarios for each cryptographic provider in different Java versions. To run the methods for each provider, the provider must be installed as the first provider, as described in the previous section, to be picked as the default provider for all the required crypto operations.

We used the following methods to run the AES/GCM encryption, ECDSA sign, and verify operations:

private static void encryptAesGcm(int iteration, int payloadSize) throws Exception {
        SecureRandom random = new SecureRandom();

        // Create the AES cipher in GCM mode
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

        // Generate random plaintext data
        byte[] plainData = new byte[payloadSize];
        random.nextBytes(plainData);

        // Generate a random initialization vector (IV)
        byte[] iv = new byte[16];
        random.nextBytes(iv);

        // Create Secret Key
        SecretKeySpec keySpec = new SecretKeySpec(new byte[16], "AES");

        // Encrypt data
        for (int i = 0; i < iteration; i++) {
            // Modify IV for each iteration
            byte temp = iv[1];
            iv[1] = iv[0];
            iv[0] = temp;

            // Initialize the cipher for encryption
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, new GCMParameterSpec(128, iv));

            // Perform encryption
            cipher.doFinal(plainData);
        }
}

private static void signEcDsa(int iteration, int payloadSize) throws Exception {
        SecureRandom random = new SecureRandom();

        // Generate EC key pair
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
        keyPairGenerator.initialize(new ECGenParameterSpec("secp256r1"));
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        // Generate random plaintext data
        byte[] data = new byte[payloadSize];
        random.nextBytes(data);

        // Create signature instance
        Signature signature = Signature.getInstance("SHA256withECDSA");

        // Initialize the signature object for signing
        signature.initSign(keyPair.getPrivate());

        // Update the signature object with the original data for signing
        for (int i = 0; i < iteration; i++) {
            signature.update(data); // Update with data for each iteration
            signature.sign();
        }
}

private static void verifyEcDsa(int iteration, int payloadSize) throws Exception {
        SecureRandom random = new SecureRandom();

        // Generate EC key pair
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
        keyPairGenerator.initialize(new ECGenParameterSpec("secp256r1"));
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        // Generate random plaintext data
        byte[] data = new byte[payloadSize];
        random.nextBytes(data);

        // Create signature instance
        Signature signature = Signature.getInstance("SHA256withECDSA");

        // Sign the data
        signature.initSign(keyPair.getPrivate());         
        signature.update(data);
        byte[] sigBytes = signature.sign();

        // Verify the signature
        signature.initVerify(keyPair.getPublic());

        // Update the signature object with the original data for verification
        for (int i = 0; i < iteration; i++) {
            signature.update(data); // Update with data for each iteration
            signature.verify(sigBytes);
        }
}

Figure 2 shows the performance results for AES/GCM/NoPadding encryption, evaluated over 1 million iterations using a 128-bit key on the z/OS s390x platform. At a payload size of 32 bytes, OpenJCEPlus achieved the fastest time of 1080 ms, representing an improvement of approximately 21.2% compared to IBMJCE at 1370 ms and about 6.1% faster than IBMJCECCA at 1150 ms. For a payload size of 128 bytes, OpenJCEPlus performed admirably with a time of 1090 ms, showing a 21.5% improvement over IBMJCE at 1390 ms and 7.6% faster than IBMJCECCA at 1180 ms. When evaluating the 512-byte payload, OpenJCEPlus recorded 1100 ms, indicating a 22.3% enhancement over IBMJCE at 1415 ms and approximately 8.7% quicker than IBMJCECCA at 1205 ms. Overall, these results suggest that utilizing the newer Java version (17+) enhances performance, particularly with OpenJCEPlus, which consistently outperformed the other options across all tested payload sizes.

Considering the geometric mean of 1386.22 for IBMJCE, 1185.45 for IBMJCECCA, and 1094.25 for OpenJCEPlus over different payload sizes, OpenJCEPlus delivers approximately 21.1% faster average throughput for AES/GCM encryption compared to IBMJCE and around 7.7% faster compared to IBMJCECCA.

Figure 2. Performance comparison for AES/GCM/NoPadding

Figure 2. Performance comparison for AES/GCM/NoPadding

Figure 3 shows the performance comparison of SHA256WithECDSA Sign, executed over 10,000 iterations on z/OS s390x. For a 32B payload, IBMJCE took 7525 ms, while IBMJCECCA performed marginally better at 5706 ms with a 24.36% improvement. However, OpenJCEPlus excelled with an extraordinary time of 304 ms, demonstrating a remarkable 95.95% improvement compared to IBMJCE. In the 128B category, IBMJCE again lagged at 7450 ms, while IBMJCECCA achieved 5672 ms, marking a 23.83% improvement. OpenJCEPlus continued its leading performance at just 301 ms, representing a 95.96% improvement over IBMJCE. Similar trends were observed with the 512B payload, where IBMJCE took 7290 ms, and IBMJCECCA improved slightly to 5695 ms at 21.79% better performance. Once more, OpenJCEPlus dominated with 302 ms, resulting in a 95.86% improvement over IBMJCE. Overall, OpenJCEPlus showcased exceptional efficiency across all payload sizes, underscoring its superiority in cryptographic operations compared to both IBMJCE and IBMJCECCA.

Considering the geometric mean of 7425.65 for IBMJCE, 5691.60 for IBMJCECCA, and 302.00 for OpenJCEPlus over different payload sizes, OpenJCEPlus delivers approximately 95.9% faster average throughput for ECDSA sign compared to IBMJCE and around 94.7% faster compared to IBMJCECCA.

Figure 3. Performance comparison for SHA256WithECDSA Sign

Figure 3. Performance comparison for SHA256WithECDSA Sign

Figure 4 shows the performance comparison of SHA256WithECDSA Verify, executed over 10,000 iterations on z/OS s390x. For a 32B payload, OpenJCEPlus completed the verification in 622 ms, which is approximately 6.6% faster than IBMJCECCA's 670 ms and 95.1% faster than IBMJCE's 12650 ms. In the 128B category, OpenJCEPlus maintained its leading position with a time of 620 ms, making it 6.7% faster than IBMJCECCA's 664 ms and 95.1% faster than IBMJCE's 12680 ms. Similarly, for a 512B payload, OpenJCEPlus clocked in at 624 ms, outperforming IBMJCECCA by about 6.6% and IBMJCE by an impressive 95.2%.

Considering the geometric mean of 12660.9 for IBMJCE, 667.7 for IBMJCECCA, and 622.2 for OpenJCEPlus over different payload sizes, OpenJCEPlus delivers approximately 95.1% faster average throughput for ECDSA verify compared to IBMJCE and around 6.8% faster compared to IBMJCECCA.

Figure 4. Performance comparison for SHA256WithECDSA Verify

Figure 4. Performance comparison for SHA256WithECDSA Verify

OpenJCEPlus's remarkable performance is largely attributed to its optimized algorithms and effective utilization of hardware acceleration for software/clear keys, specifically designed for the z/OS environment. Available on IBM Semeru Runtime 11+, OpenJCEPlus leverages the latest enhancements in the Java platform, enabling it to execute cryptographic operations with exceptional speed and responsiveness, making it an ideal choice for high-demand applications.

Disclaimer:

The performance benchmarks for AES/GCM encryption and ECDSA sign/verify were performed on an IBM z15 (8561-T01) (z/OS v2r5 OS/390), with 5 GCPs, IBM Semeru Runtime Certified Edition 17.0.16.0, IBM JDK 8.0.8.50. Results may vary.

5. References

[1] https://github.com/IBM/OpenJCEPlus

[2] https://www.ibm.com/support/pages/java-sdk-products-zos

[3] https://developer.ibm.com/languages/java/semeru-runtimes

[4] https://www.ibm.com/docs/en/semeru-runtime-ce-z/11.0.0?topic=guide-openjceplus-provider

[5] https://www.ibm.com/docs/en/semeru-runtime-ce-z/17.0.0?topic=guide-openjceplus-provider

[6] https://www.ibm.com/docs/en/semeru-runtime-ce-z/21.0.0?topic=guide-openjceplus-provider

0 comments
21 views

Permalink