Using pycryptodome/pycryptodomex for SM2 Signature and Verification in Python and Interoperability with Java Bouncy Castle
This article explains how to install pycryptodome (or pycryptodomex) to perform SM2 signing and verification in Python, provides complete code examples, and offers guidance for ensuring compatibility with Java's Bouncy Castle SM2 implementation.
SM2 is a Chinese national standard public‑key encryption algorithm that supports encryption, signing, and key exchange. Python’s standard library does not include SM2, so third‑party libraries such as pycryptodome (or its fork pycryptodomex) are required.
Python signing example
First install the library:
pip install pycryptodomeThen use the following code to generate a key pair, sign a message, and verify the signature:
from Cryptodome.PublicKey import ECC
from Cryptodome.Hash import SHA256
from Cryptodome.Signature import DSS
def sm2_sign(message, private_key):
hash_obj = SHA256.new(message.encode('utf-8'))
signer = DSS.new(private_key, 'fips-186-3')
signature = signer.sign(hash_obj)
return signature
def sm2_verify(message, signature, public_key):
hash_obj = SHA256.new(message.encode('utf-8'))
verifier = DSS.new(public_key, 'fips-186-3')
try:
verifier.verify(hash_obj, signature)
return True
except ValueError:
return False
# Generate key pair
curve = ECC.generate(curve='P-256')
public_key = curve.public_key()
private_key = curve
message = "Hello, world!"
signature = sm2_sign(message, private_key)
is_signature_valid = sm2_verify(message, signature, public_key)
print(f"Signature is valid: {is_signature_valid}")Note that the key generation and signing shown here use Python’s ECC implementation; compatibility with Java’s Bouncy Castle may require matching curve parameters and handling differences in key encoding (DER vs PEM) and hash functions.
Ensuring Python‑Java interoperability
To achieve compatibility, both sides should use the same curve (e.g., P‑256 or sm2p256v1) and the same hash algorithm (SHA‑256). Pay attention to key and signature encoding formats; DER is used in the examples, but other formats may need conversion.
Java SM2 signing example (Bouncy Castle)
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.bouncycastle.util.encoders.Hex;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
public class SM2SignatureExample {
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", "BC");
ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
keyGen.initialize(sm2Spec);
KeyPair keyPair = keyGen.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
String message = "Hello, world!";
byte[] messageBytes = message.getBytes("UTF-8");
Signature signature = Signature.getInstance("SM3withSM2", "BC");
signature.initSign(privateKey);
signature.update(messageBytes);
byte[] signatureBytes = signature.sign();
System.out.println("Private key (hex): " + ByteUtils.toHexString(privateKey.getEncoded()));
System.out.println("Public key (hex): " + ByteUtils.toHexString(publicKey.getEncoded()));
System.out.println("Signature (hex): " + Hex.toHexString(signatureBytes));
}
}Python verification of Java‑generated SM2 signatures
Because pycryptodome does not natively support SM2, install the extended fork pycryptodomex:
pip install pycryptodomexUse the following code to import the Java‑generated keys and signature (provided as hex strings), convert them to bytes, and verify the signature:
from Cryptodome.PublicKey import ECC
from Cryptodome.Hash import SHA256
from Cryptodome.Signature import DSS
def sm2_verify(message, signature, public_key):
hash_obj = SHA256.new(message.encode('utf-8'))
verifier = DSS.new(public_key, 'fips-186-3')
try:
verifier.verify(hash_obj, signature)
return True
except ValueError:
return False
# Hex strings from Java side (replace "..." with actual values)
private_key_hex = "..." # DER‑encoded private key
public_key_hex = "..." # DER‑encoded public key
signature_hex = "..." # DER‑encoded signature
private_key_bytes = bytes.fromhex(private_key_hex)
public_key_bytes = bytes.fromhex(public_key_hex)
signature_bytes = bytes.fromhex(signature_hex)
public_key = ECC.import_key(public_key_bytes)
message = "Hello, world!"
is_signature_valid = sm2_verify(message, signature_bytes, public_key)
print(f"Signature is valid: {is_signature_valid}")When troubleshooting, ensure that both platforms use identical curve parameters (e.g., sm2p256v1), the same hash function (SHA‑256), and compatible key/signature encodings. If mismatches persist, consider using the same library on both sides or adding explicit conversion steps for DER/PEM formats.
Test Development Learning Exchange
Test Development Learning Exchange
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.