前言
最近看到一些项目里边有用到sm2/3/4国密加密算法,这里给大家简单介绍一下。
知识科普
SM2(国密算法)是一种非对称加密算法,由中国国家密码管理局(NCC)制定,并被广泛应用于中国的信息安全领域。它基于椭圆曲线密码学,主要用于数字签名和数据加密。以下是SM2国密算法的一些关键特点:
- 安全性:SM2被设计为一种安全的非对称加密算法,基于椭圆曲线离散对数问题。目前,它被认为在经典计算机和量子计算机的攻击下都是安全的。
- 高效性:相对于传统的RSA算法,SM2在加解密和签名验证方面具有更高的性能和效率,特别适用于移动设备和资源受限的环境。
- 国家标准:SM2是中国国家密码管理局颁布的国家标准,作为中国政府机构和企业的信息安全标准,它在中国国内得到广泛应用。
- 数字签名:SM2可以用于生成数字签名,用于验证数据的完整性和身份认证。它在电子认证、电子合同等领域具有广泛应用。
- 数据加密:SM2也可用于数据加密,用于保护敏感信息的隐私性。在安全通信和数据保护方面具有重要作用。
- 密钥管理:SM2支持公钥和私钥的生成、存储和管理,确保密钥的安全性和可用性。
- 国际化:尽管SM2是中国的国家标准,但它也在一定程度上获得了国际认可,部分国际组织和标准化机构也开始考虑将其作为一种可选的加密算法。
总之,SM2国密算法在中国是一种重要的信息安全标准,具有强大的安全性和高效性,适用于多种应用场景,尤其在数字签名、数据加密、电子认证等领域有广泛的应用。
成熟的第三方开源地址
-
Bouncy Castle:Bouncy Castle是一个流行的Java加密库,提供了对SM2的支持。您可以使用Bouncy Castle库来进行SM2加密、签名和密钥管理等操作。
GitHub存储库:https://github.com/bcgit/bc-java
-
GMSSL:GMSSL是一个由中国国家密码管理局开发的密码库,提供了对国密算法(包括SM2)的支持。它提供了C语言和Java语言的接口。
GitHub存储库:https://github.com/guanzhi/GmSSL
-
jsrsasign:这是一个JavaScript库,提供了对SM2的支持,特别适用于前端开发。您可以使用它在浏览器中执行SM2加密和签名操作。
GitHub存储库:https://github.com/kjur/jsrsasign
代码案例
1. 使用Bouncy Castle(Java)
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
import java.security.Security;
public class SM2Example {
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
// 生成密钥对
ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
ECKeyGenerationParameters keyGenParams = new ECKeyGenerationParameters(
ECNamedCurveTable.getParameterSpec("sm2p256v1"), null);
keyPairGenerator.init(keyGenParams);
AsymmetricCipherKeyPair keyPair = keyPairGenerator.generateKeyPair();
// 明文
String plaintext = "Hello, SM2!";
// 加密
SM2Engine engine = new SM2Engine();
CipherParameters params = new ParametersWithRandom(keyPair.getPublic(), null);
engine.init(true, params);
byte[] ciphertext = engine.processBlock(plaintext.getBytes(), 0, plaintext.getBytes().length);
// 解密
engine.init(false, keyPair.getPrivate());
byte[] decryptedText = engine.processBlock(ciphertext, 0, ciphertext.length);
System.out.println("加密前: " + plaintext);
System.out.println("加密后: " + Base64.toBase64String(ciphertext));
System.out.println("解密后: " + new String(decryptedText));
}
}
2. 使用GMSSL(C语言)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/sm2.h>
int main() {
const char *plaintext = "Hello, SM2!";
size_t plaintext_len = strlen(plaintext);
// 生成密钥对
EC_KEY *ec_key = EC_KEY_new();
EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_sm2p256v1);
EC_KEY_set_group(ec_key, group);
EC_KEY_generate_key(ec_key);
// 加密
size_t ciphertext_len = plaintext_len + EVP_MAX_BLOCK_LENGTH;
unsigned char *ciphertext = (unsigned char *)malloc(ciphertext_len);
int len = SM2_encrypt(NID_sm2p256v1, NULL, NULL, EC_KEY_get0_public_key(ec_key),
plaintext, plaintext_len, ciphertext, &ciphertext_len);
// 解密
unsigned char *decrypted_text = (unsigned char *)malloc(ciphertext_len);
int decrypted_len = SM2_decrypt(NID_sm2p256v1, NULL, NULL, ec_key,
ciphertext, ciphertext_len, decrypted_text, &ciphertext_len);
printf("加密前: %s\n", plaintext);
printf("加密后: ");
for (int i = 0; i < len; i++) {
printf("%02x", ciphertext[i]);
}
printf("\n");
printf("解密后: %s\n", decrypted_text);
free(ciphertext);
free(decrypted_text);
EC_KEY_free(ec_key);
EC_GROUP_free(group);
return 0;
}
3. 使用jsrsasign(JavaScript)
<!DOCTYPE html>
<html>
<head>
<title>SM2 Encryption Example</title>
<script src="jsrsasign-all-min.js"></script>
</head>
<body>
<textarea id="plaintext" rows="4" cols="50">Hello, SM2!</textarea><br><br>
<button onclick="encryptText()">加密</button><br><br>
<div id="encryptedText"></div><br>
<div id="decryptedText"></div>
<script>
function encryptText() {
var plaintext = document.getElementById("plaintext").value;
var publicKeyHex = "公钥十六进制字符串"; // 替换成实际的公钥
var sm2 = new KJUR.crypto.SM2({ 'publicKeyHex': publicKeyHex });
var encryptedText = sm2.doEncrypt(plaintext);
document.getElementById("encryptedText").textContent = "加密后: " + encryptedText;
// 解密示例(仅供参考,实际解密需要私钥)
// var decryptedText = sm2.doDecrypt(encryptedText);
// document.getElementById("decryptedText").textContent = "解密后: " + decryptedText;
}
</script>
</body>
</html>
注意:上列示例中敏感数据都是虚假的哦,自己用的话建议替换成自己的。
收尾
一般来说前端保护方案一直都是有限的,我建议的是用jsjiami.v7/v6在线一键加密,配合aes/国密这种对接口安全进行保护。