Master Encryption: Symmetric, Asymmetric, Certificates & Code Samples Explained
This article explains common encryption and signing algorithms—including AES, SM4, RSA2, and SM2—covers key representations in hex and Base64, details digital certificate structures, CSR application, TLS usage scenarios, OpenSSL commands for PEM conversion, and provides Java and JavaScript code examples for secure communication.
Encryption Algorithms
In API integration, common encryption and signature algorithms include symmetric encryption (AES, SM4) where both parties share the same key, and asymmetric encryption (RSA2, SM2) where each party has a public‑private key pair.
Symmetric encryption algorithms such as AES and SM4 provide high efficiency for data encryption and masking. Asymmetric encryption algorithms like RSA2 and SM2 use a pair of keys; the private key signs the plaintext, then the plaintext and signature are encrypted with the counterpart’s public key. The receiver decrypts with its private key, verifies the signature with the sender’s public key.
Public‑private keys are binary data stored in certificate files, but for convenience they are often represented in hexadecimal or Base64 format, so the same algorithm may have different key representations.
16-bit format:
Public key: 04A5C65A40B977D4F909833722EF950374D0B8791B9E7B9F5712D573F964706879E4AFD1DA142DBDD5B305824EDFC02B73CEB6F50B71DB2089E214C58230A0875F
Private key: 00FD954A8820A25A406396DBEAC9CEE9AD7F1FEA29D22EEBA9682647D482FDA32E
Base64 format:
Public key: BEViYfuleJ4ZCczcVVx6UY38IgGi0C/++EW72YMKff3uSNownfWnzy5AFLIuGce1ig3zjMITJt1xvPXTYax+NdA=
Private key: AJw7Dn/tBoNhtyGmmXc8S0DxWBXKIWe5iZD4dMZ1GebDUsage Methods
In practice, keys appear as either string keys or certificate files.
String Keys
String keys are used for simple encryption or signature tasks when strong identity verification is not required.
In asymmetric encryption, the private key is stored locally while the public key is sent to the counterpart. If the public key string is tampered with, the encryption and signature become untrustworthy, so public key certificates are introduced to ensure authenticity.
Digital Certificates
The main purpose of digital certificates is to solve the public‑key authenticity problem in asymmetric encryption. They provide higher security and trust, especially in scenarios involving public‑key encryption and identity verification. A certificate contains the public key, validity period, issuer information, and is signed by a trusted Certificate Authority (CA) to prevent man‑in‑the‑middle attacks.
The issuance logic uses the CA’s private key to sign the public key, domain name, organization name, etc. Verification only requires the CA’s public key.
Certificate structure : X.509 format includes the public key and signer’s identity, issued by a trusted CA.
Identity verification : The certificate binds the signer’s identity, which is authenticated by the CA.
Trust chain : Root certificate → intermediate certificates → user certificate.
Management : Certificates must be kept valid and trusted; they may expire or be revoked and need periodic renewal.
Signature verification : The receiver verifies both the signature and the certificate’s validity and trust.
How Merchants Apply for Certificates
Merchants generate a Certificate Signing Request (CSR) file, which is the standard step in digital certificate creation.
The CSR contains the public key, organization information, subject name, and the signature algorithm. It is generated locally with the private key, then uploaded to the platform for signing.
Alipay Application Public Key
The process: generate a public‑private key pair locally, create a CSR, upload to Alipay, and download the public key certificate. Three certificates are involved: the application public key certificate (signed with its private key), Alipay’s public key certificate (signed by Alipay’s root key), and Alipay’s root certificate (used to verify Alipay’s public key certificate).
Three Certificate Usage Scenarios
1. HTTP request signing and encryption (mutual authentication)
Commonly used for API integration, where the request data is signed with a certificate.
2. SSL/TLS one‑way authentication
The client validates the server’s certificate; the server does not validate the client. This is typical for most HTTPS sites.
3. SSL/TLS two‑way authentication
Both client and server verify each other’s certificates, used in banking, internal services, and payment systems for the highest security level.
OpenSSL Self‑Signed Certificate Example
# 1. Generate a 2048‑bit RSA private key
openssl genrsa -out own-private.key 2048
# 2. Generate a self‑signed certificate (valid for 1825 days)
openssl req -x509 -new -key own-private.key -out own-certificate.crt -days 1825
# 3. Package the certificate and private key into a PKCS#12 file
openssl pkcs12 -export -in own-certificate.crt -inkey own-private.key -out own.p12The self‑signed process skips CSR generation and is suitable only for internal use. The resulting PKCS#12 file (extension .p12 or .pfx) contains the public key, private key, and personal information.
For mutual authentication, import the .p12 file directly.
Extracting Keys and Converting to PEM
# Extract client certificate (no private key) from .p12
openssl pkcs12 -in own.p12 -clcerts -nokeys -out certificate.crt
# Extract private key from .p12 (enter password, then set a new password for the key)
openssl pkcs12 -in own.p12 -nocerts -out private.key
# Convert encrypted private key to an unencrypted one
openssl rsa -in private.key -out private_no_password.keyTo obtain the public key from the private key:
openssl rsa -in own-private.key -pubout -out own-public.keyJava SSLContext Configuration (Spring RestTemplate)
import lombok.extern.slf4j.Slf4j;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@Slf4j
@Configuration
public class SSLContextConfig {
@Bean(name = "restTemplate")
public RestTemplate restTemplate() {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(100);
cm.setDefaultMaxPerRoute(20);
RestTemplate restTemplate = null;
try {
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
KeyStore clientStore = KeyStore.getInstance("PKCS12");
InputStream keyStream = new FileInputStream("/User/own.p12");
String pwd = "own";
clientStore.load(keyStream, pwd.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientStore, pwd.toCharArray());
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream certStream = new FileInputStream("/User/对放的公钥.crt");
trustStore.setCertificateEntry("server", cf.generateCertificate(certStream));
trustManagerFactory.init(trustStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, new SecureRandom());
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslConnectionSocketFactory)
.setSSLHostnameVerifier(new NoopHostnameVerifier())
.build();
requestFactory.setHttpClient(httpclient);
requestFactory.setConnectTimeout(5000);
requestFactory.setReadTimeout(65000);
requestFactory.setConnectionRequestTimeout(50000);
restTemplate = new RestTemplate(requestFactory);
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException | CertificateException | UnrecoverableKeyException | java.io.IOException e) {
log.warn("初始化证书异常", e);
restTemplate = new RestTemplate();
}
return restTemplate;
}
}Sending a POST request with the configured RestTemplate:
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplate();
String reqUrl = "请求的URL";
Map<String, Object> param = new HashMap<>(2);
param.put("param", "value");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> requestEntity = new HttpEntity<>(JSON.toJSONString(param), headers);
ResponseEntity<String> response = restTemplate.postForEntity(reqUrl, requestEntity, String.class);
HttpStatus statusCode = response.getStatusCode();
String body = response.getBody();
}Nginx Server Deployment
Nginx (or other web servers) requires PEM‑format certificate and key files. A .p12 file can be converted to PEM using OpenSSL:
# Extract client certificate (public key) without private key
openssl pkcs12 -in own.p12 -clcerts -nokeys -out certificate.crt
# Extract private key (enter .p12 password)
openssl pkcs12 -in own.p12 -nocerts -out private.key
# Convert encrypted private key to an unencrypted one
openssl rsa -in private.key -out private_no_password.keyExample Nginx configuration:
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /path/to/certificate.crt; # certificate
ssl_certificate_key /path/to/private.key; # private key
# Optional: ssl_certificate_chain_file for intermediate chain
ssl_trusted_certificate /path/to/chain.pem;
}Code Samples
Asymmetric Encryption (SM2)
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
@Slf4j
public class Sm2Util {
// ... (methods for key generation, encryption, decryption, hex/base64 conversion) ...
public static void main(String[] args) {
// Example usage
}
}Asymmetric Encryption (RSA)
import java.security.*;
import java.util.Base64;
public class AsymmetricEncryptionUtils {
public static String encryptRSA(String content, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encrypted = cipher.doFinal(content.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
}
public static String decryptRSA(String encryptedContent, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedContent));
return new String(decrypted);
}
public static KeyPair generateRSAKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
return keyPairGenerator.generateKeyPair();
}
}Symmetric Encryption (AES/DES)
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class SymmetricEncryptionUtils {
public static String encryptAES(String content, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encrypted = cipher.doFinal(content.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
}
public static String decryptAES(String encryptedContent, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedContent));
return new String(decrypted);
}
// Similar methods for DES encryption/decryption
}SM4 Encryption
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.engines.SM4Engine;
import org.bouncycastle.crypto.modes.ECBBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Hex;
public class SM4Utils {
public static byte[] sm4Encrypt(byte[] key, byte[] data) throws CryptoException {
return sm4Process(key, data, true);
}
public static byte[] sm4Decrypt(byte[] key, byte[] data) throws CryptoException {
return sm4Process(key, data, false);
}
private static byte[] sm4Process(byte[] key, byte[] data, boolean isEncrypt) throws CryptoException {
SM4Engine engine = new SM4Engine();
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new ECBBlockCipher(engine));
KeyParameter keyParam = new KeyParameter(key);
cipher.init(isEncrypt, keyParam);
byte[] output = new byte[cipher.getOutputSize(data.length)];
int len = cipher.processBytes(data, 0, data.length, output, 0);
cipher.doFinal(output, len);
return output;
}
public static String bytesToHex(byte[] bytes) { return Hex.toHexString(bytes); }
public static byte[] hexToBytes(String hex) { return Hex.decode(hex); }
public static void main(String[] args) throws CryptoException {
String key = "1234567890abcdef1234567890abcdef"; // 128‑bit key
String plainText = "Hello SM4 Encryption!";
byte[] encrypted = sm4Encrypt(key.getBytes(), plainText.getBytes());
System.out.println("Encrypted (Hex): " + bytesToHex(encrypted));
byte[] decrypted = sm4Decrypt(key.getBytes(), encrypted);
System.out.println("Decrypted: " + new String(decrypted));
}
}Hash Algorithms
import java.security.*;
import java.util.Base64;
public class SignatureUtils {
public static String signMD5(String content) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hash = md.digest(content.getBytes());
return Base64.getEncoder().encodeToString(hash);
}
public static String signSHA256(String content) throws NoSuchAlgorithmException {
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
byte[] hash = sha256.digest(content.getBytes());
return Base64.getEncoder().encodeToString(hash);
}
}The article ends here.
Lin is Dream
Sharing Java developer knowledge, practical articles, and continuous insights into computer engineering.
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.
