初识sm3、sms4加密,以及登录密码加密
一、SM3 密码杂凑算法
SM3 是一种密码杂凑函数(Hash 函数),主要用于对消息进行摘要计算,生成固定长度的哈希值,可用于数据完整性校验、数字签名等场景。
Hash,一般翻译做散列、杂凑,或音译为哈希,是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
- 核心功能
- 消息摘要:将任意长度的输入消息(如文本、文件等)转换为固定长度(256 位)的输出值(哈希值)。
- 完整性校验:通过比对消息发送前后的哈希值,判断消息是否被篡改。
- 数字签名支持:与非对称加密算法(如
SM2)结合,用于生成和验证数字签名。
- 算法特点
- 高安全性:设计上能抵抗碰撞攻击(找到两个不同消息生成相同哈希值)等常见攻击,安全性与国际标准
SHA-256相当。 - 高效性:算法流程简洁,适合硬件和软件实现,在各类设备上(如服务器、嵌入式设备)均有较好的性能。
- 国密标准:由国家密码管理局发布(
GM/T 0004-2012),是我国金融、政务等关键领域的强制或推荐标准。
二、SM4 分组密码算法
SM4 是一种对称分组加密算法,主要用于对数据进行加密和解密,适用于存储加密、传输加密等场景。
- 核心功能
- 分组加密:将明文按固定长度(128 位)分组,通过密钥(128 位)对每组数据进行加密,输出 128 位密文;解密过程与加密类似,使用相同密钥反向运算。
- 密钥管理:对称加密特性决定了加密和解密使用同一密钥,需通过安全通道进行密钥分发。
- 算法特点
- 安全性:采用
Feistel结构,轮函数设计包含非线性变换和线性变换,能抵抗差分攻击、线性攻击等,安全性达到国际先进水平。 - 高效性:算法轮数为 32 轮,运算逻辑简单,硬件实现成本低,软件实现效率高,适合实时性要求高的场景。
- 灵活性:支持
ECB(电子密码本)、CBC(密码分组链接)、CTR(计数器)等多种工作模式,适应不同加密需求(如固定长度数据、流数据加密)。
Feistel 结构 由Horst Feistel 首创的密码结构,实现对称密码系统发基础结构
| 维度 | SM3 | SM4 |
|---|---|---|
| 算法类型 | 杂凑函数(Hash) | 对称分组加密算法 |
| 核心用途 | 消息摘要、完整性校验 | 数据加密、解密 |
| 输入输出长度 | 任意输入,256 位输出 | 128 位分组输入 / 输出 |
| 密钥需求 | 无需密钥 | 128 位对称密钥 |
| 典型应用 | 数字签名、防篡改 | 数据存储 / 传输加密 |
三、登录加密
js库 sm-crypto 0.3.13
node 版本 18.12.0
pnpm install sm-crypto
import { sm4, sm3 } from 'sm-crypto';
/**
* SM3哈希计算
* @param {string} text 待哈希的文本
* @param {boolean} isHexOutput 是否输出16进制格式,默认true
* @returns {string} 哈希结果
*/
sm3Hash(text: string, isHexOutput: boolean = true): string {
if (typeof text !== 'string') {
throw new Error('SM3哈希内容必须为字符串');
}
return sm3(text, isHexOutput);
}
/**
* SM3哈希计算(带盐值)
* @param {string} text 待哈希的文本
* @param {string} salt 盐值
* @param {boolean} isHexOutput 是否输出16进制格式,默认true
* @returns {string} 哈希结果
*/
sm3HashWithSalt(text: string, salt: string, isHexOutput: boolean = true): string {
if (typeof salt !== 'string') {
throw new Error('盐值必须为字符串');
}
// 将盐值与原始文本组合后计算哈希
return this.sm3Hash(`${text}${salt}`, isHexOutput);
}
// 使用示例
sm3Hash(pwd, false);// pwd 登录密码
sm4.encrypt(pwd, key)// pwd 登录密码 key密钥 注意:key 16位 与后端协商 使用的 ECB工作模式 PKCS#7填充模式
文档示例
sm3
const sm3 = require('sm-crypto').sm3
let hashData = sm3('abc') // 杂凑
// hmac
hashData = sm3('abc', {
key: 'daac25c1512fe50f79b0e4526b93f5c0e1460cef40b6dd44af13caec62e8c60e0d885f3c6d6fb51e530889e6fd4ac743a6d332e68a0f2a3923f42585dceb93e9', // 要求为 16 进制串或字节数组
})
sm4
加密
const sm4 = require('sm-crypto').sm4
const msg = 'hello world! 我是 juneandgreen.' // 可以为 utf8 串或字节数组
const key = '0123456789abcdeffedcba9876543210' // 可以为 16 进制串或字节数组,要求为 128 比特
let encryptData = sm4.encrypt(msg, key) // 加密,默认输出 16 进制字符串,默认使用 pkcs#7 填充(传 pkcs#5 也会走 pkcs#7 填充)
let encryptData = sm4.encrypt(msg, key, {padding: 'none'}) // 加密,不使用 padding
let encryptData = sm4.encrypt(msg, key, {padding: 'none', output: 'array'}) // 加密,不使用 padding,输出为字节数组
let encryptData = sm4.encrypt(msg, key, {mode: 'cbc', iv: 'fedcba98765432100123456789abcdef'}) // 加密,cbc 模式
解密
const sm4 = require('sm-crypto').sm4
const encryptData = '0e395deb10f6e8a17e17823e1fd9bd98a1bff1df508b5b8a1efb79ec633d1bb129432ac1b74972dbe97bab04f024e89c' // 可以为 16 进制串或字节数组
const key = '0123456789abcdeffedcba9876543210' // 可以为 16 进制串或字节数组,要求为 128 比特
let decryptData = sm4.decrypt(encryptData, key) // 解密,默认输出 utf8 字符串,默认使用 pkcs#7 填充(传 pkcs#5 也会走 pkcs#7 填充)
let decryptData = sm4.decrypt(encryptData, key, {padding: 'none'}) // 解密,不使用 padding
let decryptData = sm4.decrypt(encryptData, key, {padding: 'none', output: 'array'}) // 解密,不使用 padding,输出为字节数组
let decryptData = sm4.decrypt(encryptData, key, {mode: 'cbc', iv: 'fedcba98765432100123456789abcdef'}) // 解密,cbc 模式