SM2 Cryptographic Operations with Bouncy Castle on OpenEuler x86_64
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.jarbcprov-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.