Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

SM2 Cryptographic Operations with Bouncy Castle on OpenEuler x86_64

Tech 1

Environment Setup

Install Java 17 and Maven using the package manager:

sudo yum install java-17-openjdk
sudo yum install maven

These comands configure a complete Java development environment on OpenEuler for building cryptographic applications.

Project Configuration

Maven Dependencies

Create a pom.xml file in your project root directory:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.crypto.example</groupId>
    <artifactId>Sm2BouncyCastleDemo</artifactId>
    <version>1.0.0</version>
    
    <dependencies>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk18on</artifactId>
            <version>1.77</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-ext-jdk18on</artifactId>
            <version>1.77</version>
        </dependency>
    </dependencies>
    
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
</project>

Directory Structure

Organize your source files under src/main/java/crypto/example/:

Sm2Example.java:

package crypto.example;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.*;
import java.security.spec.ECGenParameterSpec;

public class Sm2Example {
    private static final String TEST_PAYLOAD = "sm2_encryption_test_2024";
    
    static {
        Security.addProvider(new BouncyCastleProvider());
    }
    
    public static void main(String[] args) {
        try {
            Sm2CipherService cipherService = new Sm2CipherService();
            KeyPair keyPair = generateKeyPair();
            
            String encryptedHex = cipherService.encrypt(keyPair.getPublic(), TEST_PAYLOAD);
            System.out.println("Encrypted output: " + encryptedHex);
            
            String decryptedText = cipherService.decrypt(keyPair.getPrivate(), encryptedHex);
            System.out.println("Decrypted output: " + decryptedText);
            
        } catch (Exception e) {
            System.err.println("Cryptographic operation error: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    private static KeyPair generateKeyPair() throws NoSuchAlgorithmException, 
            NoSuchProviderException, InvalidAlgorithmParameterException {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "BC");
        ECGenParameterSpec spec = new ECGenParameterSpec("sm2p256v1");
        generator.initialize(spec, new SecureRandom());
        return generator.generateKeyPair();
    }
}

Sm2CipherService.java:

package crypto.example;

import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.util.encoders.Hex;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;

public class Sm2CipherService {
    
    public String encrypt(PublicKey pubKey, String plaintext) {
        if (!(pubKey instanceof BCECPublicKey)) {
            throw new IllegalArgumentException("Invalid public key type");
        }
        
        BCECPublicKey bcPubKey = (BCECPublicKey) pubKey;
        ECParameterSpec params = bcPubKey.getParameters();
        ECDomainParameters domainParams = new ECDomainParameters(
            params.getCurve(), params.getG(), params.getN());
        
        ECPublicKeyParameters pubKeyParams = new ECPublicKeyParameters(
            bcPubKey.getQ(), domainParams);
        
        SM2Engine engine = new SM2Engine();
        engine.init(true, new ParametersWithRandom(pubKeyParams, new SecureRandom()));
        
        try {
            byte[] inputBytes = plaintext.getBytes("UTF-8");
            byte[] encrypted = engine.processBlock(inputBytes, 0, inputBytes.length);
            return Hex.toHexString(encrypted);
        } catch (Exception ex) {
            System.err.println("Encryption failed: " + ex.getMessage());
            throw new RuntimeException("SM2 encryption error", ex);
        }
    }
    
    public String decrypt(PrivateKey privKey, String hexCiphertext) {
        if (!(privKey instanceof BCECPrivateKey)) {
            throw new IllegalArgumentException("Invalid private key type");
        }
        
        byte[] cipherBytes = Hex.decode(hexCiphertext);
        BCECPrivateKey bcPrivKey = (BCECPrivateKey) privKey;
        ECParameterSpec params = bcPrivKey.getParameters();
        ECDomainParameters domainParams = new ECDomainParameters(
            params.getCurve(), params.getG(), params.getN());
        
        ECPrivateKeyParameters privKeyParams = new ECPrivateKeyParameters(
            bcPrivKey.getD(), domainParams);
        
        SM2Engine engine = new SM2Engine();
        engine.init(false, privKeyParams);
        
        try {
            byte[] decrypted = engine.processBlock(cipherBytes, 0, cipherBytes.length);
            return new String(decrypted, "UTF-8");
        } catch (Exception ex) {
            System.err.println("Decryption failed: " + ex.getMessage());
            throw new RuntimeException("SM2 decryption error", ex);
        }
    }
}

Local Library Setup

Create a lib/ directory and place the Bouncy Castle JAR files inside:

  • bcprov-jdk18on-1.77.jar
  • bcprov-ext-jdk18on-1.77.jar

Build and Execution

Compilation

Execute Maven build commands:

mvn clean compile package

This generates the compilde classes and packaged JAR in the target/ directory.

Running the Application

Execute the program with the proper classpath:

java -cp "target/classes:target/Sm2BouncyCastleDemo-1.0.0.jar:lib/*" crypto.example.Sm2Example

Expected Output

Encrypted output: 8b9c3a2d1e4f5c6b7a8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1
Decrypted output: sm2_encryption_test_2024

The encrypted value appears as a hexadecimal string, while the decrypted result matches the orgiinal test payload.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.