Guía Completa de Cifrado SM2: Generación de Claves, Cifrado, Descifrado y Firmas Digitales en Práctica
¿Qué es SM2?
SM2 es un algoritmo de cifrado asimétrico publicado por la Administración Nacional de Criptografía de China, basado en criptografía de curva elíptica (ECC), que reemplaza a RSA como estándar nacional.
| Comparación | SM2 | RSA 2048 |
|---|---|---|
| Longitud de clave | 256 bit | 2048 bit |
| Intensidad de seguridad | 128 bit | 112 bit |
| Velocidad de firma | ~0.5ms | ~3ms |
| Velocidad de verificación | ~1ms | ~0.1ms |
| Ratio de longitud de clave | 1 | 8 |
| Estándar nacional | GM/T 0003 | PKCS#1 |
SM2 alcanza la intensidad de seguridad de RSA 2048 bit con una clave de 256 bit, clave más corta, velocidad más rápida.
Tres Usos de SM2
| Uso | Descripción | Herramienta Correspondiente |
|---|---|---|
| Cifrado/Descifrado | Cifrar con clave pública, descifrar con clave privada | Cifrado SM2 |
| Firma Digital | Firmar con clave privada, verificar con clave pública | Firma SM2 |
| Acuerdo de Claves | Ambas partes negocian una clave compartida | Protocolo ECDH |
Paso 1: Generar Par de Claves SM2
Usar la herramienta de ToolsKu
- Abrir Herramienta de Cifrado SM2
- Hacer clic en "Generar par de claves"
- Obtener la clave pública y la clave privada
Usar la línea de comandos
# Instalar gmssl
brew install gmssl # macOS
# O descargar desde https://github.com/guanzhi/GmSSL/releases
# Generar par de claves SM2
gmssl sm2 -genkey -out sm2.key
# Ver las claves
gmssl sm2 -in sm2.key -text
Usar JavaScript
import { sm2 } from 'sm-crypto';
// Generar par de claves
const keyPair = sm2.generateKeyPairHex();
// keyPair.privateKey → clave privada (64 hexadecimales)
// keyPair.publicKey → clave pública (128 hexadecimales, 04 + X + Y)
console.log('Clave privada:', keyPair.privateKey);
console.log('Clave pública:', keyPair.publicKey);
Formato de clave
Formato de clave pública SM2:
04 || X (32 bytes) || Y (32 bytes)
↓
04 + 64 hexadecimales X + 64 hexadecimales Y
Longitud total: 130 caracteres hexadecimales (65 bytes)
Formato de clave privada SM2:
Número aleatorio de 32 bytes
Longitud total: 64 caracteres hexadecimales (32 bytes)
Paso 2: Cifrado y Descifrado SM2
Flujo de Cifrado
Texto plano → Cifrado SM2 (clave pública) → Texto cifrado (C1 || C3 || C2)
- C1: Punto de curva elíptica (65 bytes)
- C3: Hash SM3 (32 bytes)
- C2: Datos cifrados
Usar la herramienta de ToolsKu
- Abrir Herramienta de Cifrado SM2
- Pegar la clave pública
- Ingresar el texto plano a cifrar
- Seleccionar formato de texto cifrado (C1C3C2 o C1C2C3)
- Hacer clic en "Cifrar" para obtener el texto cifrado
Usar JavaScript
import { sm2 } from 'sm-crypto';
const publicKey = '04...'; // 128 hexadecimales
const privateKey = '...'; // 64 hexadecimales
// Cifrar (formato C1C3C2 por defecto)
const cipherText = sm2.doEncrypt('Hola SM2', publicKey, 1);
// Parámetro 1 = formato C1C3C2 (recomendado por el estándar nacional)
// Parámetro 0 = formato C1C2C3 (compatibilidad con versiones anteriores)
console.log('Texto cifrado:', cipherText);
// Descifrar
const plainText = sm2.doDecrypt(cipherText, privateKey, 1);
console.log('Texto plano:', plainText); // "Hola SM2"
Formatos de codificación del texto cifrado
| Formato | Descripción | Escenario de uso |
|---|---|---|
| C1C3C2 | Formato recomendado por el estándar nacional | Proyectos nuevos (por defecto) |
| C1C2C3 | Formato de versión anterior | Compatibilidad con sistemas antiguos |
| ASN.1 | Codificación DER | Interoperabilidad Java/C# |
Paso 3: Firma Digital SM2
Flujo de Firma
Mensaje → Hash SM3 → Firma SM2 (clave privada) → Valor de firma (r, s)
Usar la herramienta de ToolsKu
- Abrir Herramienta de Cifrado SM2
- Cambiar a la pestaña "Firma"
- Ingresar la clave privada y el mensaje a firmar
- Hacer clic en "Firmar" para obtener el valor de la firma
Usar JavaScript
import { sm2 } from 'sm-crypto';
const privateKey = '...';
const publicKey = '04...';
// Firmar (aplica hash SM3 automáticamente al mensaje)
const signature = sm2.doSignature('Mensaje a firmar', privateKey);
console.log('Firma:', signature);
// Verificar firma
const verified = sm2.doVerifySignature(
'Mensaje a firmar',
signature,
publicKey
);
console.log('Resultado de verificación:', verified); // true
Firma con ID de usuario
La firma SM2 usa por defecto el ID de usuario 1234567812345678 (valor por defecto del estándar nacional), que se puede personalizar:
// Especificar ID de usuario al firmar
const sig = sm2.doSignature('Mensaje', privateKey, {
userId: 'customUserId'
});
// Usar el mismo ID de usuario al verificar
const valid = sm2.doVerifySignature('Mensaje', sig, publicKey, {
userId: 'customUserId'
});
SM2 vs RSA: ¿Cuándo elegir?
| Escenario | Recomendación | Razón |
|---|---|---|
| Sistemas gubernamentales nacionales | SM2 | Requisito de cumplimiento con estándar nacional |
| Sistemas financieros nacionales | SM2 | Requisito de UnionPay/Banco Popular |
| Sistemas de estándares internacionales | RSA | Compatibilidad internacional |
| Cifrado en dispositivos móviles | SM2 | Clave corta, cálculo rápido |
| Intercambio de datos transfronterizo | RSA | Estándar internacional |
Trío de Cifrado Nacional: SM2 + SM3 + SM4
| Algoritmo | Tipo | Uso | Herramienta |
|---|---|---|---|
| SM2 | Asimétrico | Cifrado/Firma/Acuerdo de claves | Herramienta SM2 |
| SM3 | Hash | Resumen de mensaje (similar a SHA-256) | Herramienta SM3 |
| SM4 | Simétrico | Cifrado de datos (similar a AES-128) | Herramienta SM4 |
Combinación típica: Cifrado híbrido SM2 + SM4
1. Generar clave SM4 aleatoria
2. Cifrar datos grandes con SM4 (rápido)
3. Cifrar la clave SM4 con la clave pública SM2 (transmisión segura)
4. Enviar: SM2(clave SM4) + SM4(datos)
import { sm2, sm4 } from 'sm-crypto';
// 1. Generar clave SM4 aleatoria
const sm4Key = crypto.getRandomValues(new Uint8Array(16));
const sm4KeyHex = Array.from(sm4Key).map(b => b.toString(16).padStart(2, '0')).join('');
// 2. Cifrar datos con SM4
const encryptedData = sm4.encrypt(plainText, sm4KeyHex);
// 3. Cifrar la clave SM4 con SM2
const encryptedKey = sm2.doEncrypt(sm4KeyHex, sm2PublicKey, 1);
// Enviar: encryptedKey + encryptedData
Preguntas Frecuentes
¿Por qué el texto cifrado SM2 es mucho más largo que el texto plano?
Texto cifrado SM2 = C1 (65 bytes) + C3 (32 bytes) + C2 (longitud del texto plano), por lo que el texto cifrado es 97 bytes más largo que el texto plano. Esta es una característica del cifrado asimétrico. Para datos grandes se recomienda cifrado híbrido SM2+SM4.
¿Cuál es la diferencia entre SM2 y ECDSA?
SM2 usa la curva elíptica especificada por el estándar nacional (sm2p256v1), ECDSA usa curvas NIST (P-256). La lógica del algoritmo es similar, pero los parámetros de la curva son diferentes, no son compatibles.
¿Cómo usar SM2 en Java?
// Usar Bouncy Castle + extensión de cifrado nacional
Security.addProvider(new BouncyCastleProvider());
// Generar par de claves
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");
kpg.initialize(new ECParameterSpec(...)); // Parámetros de curva SM2
KeyPair kp = kpg.generateKeyPair();
Resumen
SM2 es el algoritmo de cifrado asimétrico central del sistema de cifrado nacional, con una clave de 256 bit alcanza la intensidad de seguridad de RSA 2048 bit. Domine las tres operaciones principales: generación de claves, cifrado/descifrado y firma digital, junto con hash SM3 y cifrado simétrico SM4, para cumplir con los requisitos de cumplimiento del estándar nacional. ToolsKu ofrece tres herramientas en línea: SM2, SM3, SM4, procesamiento local en el navegador, datos sin carga.