一、依赖
国密2 | 国密3 | 国密4 | |
---|---|---|---|
安装依赖 | 1.gm-crypto 优选 2.sm-crypto | 1.gm-crypto 优选 2.sm-crypto | 1.gm-crypto 优选 2.sm-crypto 3.gm-crypt |
支持解密 | 是 | 否 | 是 |
加密模式 | 1 - C1C3C2、0 - C1C2C3 | - | cbc(优选)、ecb |
所需key | 公钥(加密)、私钥(解密) | - | key、iv(cbc模式) |
依赖 | 安装指令 | API |
---|---|---|
gm-crypto | npm install gm-crypto 或 yarn add gm-crypto | https://gitcode.net/mirrors/byte-fe/gm-crypto?utm_source=csdn_github_accelerator |
sm-crypto | npm install --save sm-crypto ts若不能正常运行需执行: npm i --save-dev @types/sm-crypto | https://www.npmjs.com/package/sm-crypto |
gm-crypt | npm install gm-crypt | https://www.npmjs.com/package/gm-crypt |
二、国密4/3/2加解密
1、国密4
(1)gm-crypto
/**
* 加密解密方法
*/
import { SM4 } from 'gm-crypto'
export class EncryptionUtil {
key: string // 密钥
constructor({ keys = '' } = {}) {
// 任意32位十六进制字符串 || 示例密钥
this.key = keys || '0123456789abcdeffedcba9876543210'
}
// 国密4加密(明文,密钥)
smEncrypt(text: any, k: string) {
const k1 = k || this.key // key值与后端一致
// CBC(cipher block chaining)模式,cbc比ecb模式多加一个iv的参数同key
const sm4Encrypt = SM4.encrypt(text, k1, {
iv: k1,
mode: SM4.constants.CBC,
inputEncoding: 'utf8',
outputEncoding: 'hex'
})
// ECB(electronic codebook)模式
// const sm4Encrypt = SM4.encrypt(text, k1, {
// inputEncoding: 'utf8',
// outputEncoding: 'hex'
// })
return sm4Encrypt
}
// 国密4解密(密文,密钥)
smDecrypt(text: any, k: string) {
const k1 = k || this.key // key值与后端一致
// CBC
const sm4Decrypt = SM4.decrypt(text, k1, {
iv: k,
mode: SM4.constants.CBC,
inputEncoding: 'base64',
outputEncoding: 'utf8'
})
// ECB
// const sm4Decrypt = SM4.decrypt(text, k1, {
// inputEncoding: 'base64',
// outputEncoding: 'utf8'
// })
return sm4Decrypt
}
}
// 明文示例: SM4 国标对称加密
// ECB示例密文: A9TLmWvl16D5xheKUxlINfhkGRQjPrHDukbYnKI82QI=
// CBC示例密文: 62f78c8c19c7f9fee800ca4f3c31cb261a4e68634fd76280faf292f1dd739665
(2)sm-crypto(加密可行,解密不适配后端)
/**
* 加密解密方法
*/
const sm4 = require('sm-crypto').sm4
export class EncryptionUtil {
key: string
constructor({ keys = '' } = {}) {
// 可以为16进制串或字节数组,要求为128比特 || 示例密钥
this.key = keys || '3961794a786e7a78512a4544712a396b'
}
// 国密4加密
smEncrypt(text: any, k: string) {
// cbc模式
const sm4Encrypt = sm4.encrypt(text, k || this.key, {
mode: 'cbc',
iv: k || this.key
})
// ecb模式
// const sm4Encrypt = sm4.encrypt(text, k || this.key)
// 示例明文:SM4 加密,sm-crypto依赖
// 示例密文:9bf9fbb5132b4843e54659dc5dd659559c338a85f7e7ca7e0041fcb02d666b79
return sm4Encrypt
}
// 国密4解密 (此依赖国密4解密输出为UTF8,而后端都是base64,故不能解密)
smDecrypt(text: any, k: string) {
// cbc模式
const sm4Decrypt = sm4.decrypt(text, k || this.key, {
mode: 'cbc',
iv: k || this.key
})
// ecb模式
// const sm4Decrypt = sm4.decrypt(text, k || this.key)
return sm4Decrypt
}
}
(3)gm-crypt(只支持国密4加密,秘钥为16位字符串)
/**
* 加密解密方法
*/
import { sm4 } from 'gm-crypt'
export class EncryptionUtil {
key: string
constructor({ keys = '' } = {}) {
// 密钥16位
this.key = keys || 'jhmyApp202072ymt'
}
// 国密4加密
smEncrypt(text: any, k: string) {
// k:例 2023Z07@14a15!00 16个字符
// eslint-disable-next-line new-cap
// cbc模式
const sm4Instance = new sm4({
key: k || this.key, // key值与后端一致
mode: 'cbc',
iv: k || this.key,
cipherType: 'base64'
})
// ecb模式
// const sm4Instance = new sm4({
// key: k || this.key, // key值与后端一致
// mode: 'ecb', // 加密的方式有两种,ecb和cbc两种,这里使用的是ecb,cbc模式还要加一个iv的参数,ecb不用
// cipherType: 'base64' // 密码数据的类型;可以是“base64”或“text”,代表TextEncoder和Base64.js
// })
return sm4Instance.encrypt(text)
// 密文cbc:J2IMKFP9NZfbiH5ofW8ZIIbS6OSVFbmwt+pyw3jeX3Zh+JICZlarkplAQ//WaunH
// 密文ecb:djN+QRtD9T27fJ1K1gcryFg/DwZUkJmrgWdEDBg0xqc=
}
// 国密4解密
smDecrypt(text: any, k: string) {
// cbc模式
// eslint-disable-next-line new-cap
const sm4Instance = new sm4({
key: k || this.key, // key值与后端一致
mode: 'cbc',
iv: k || this.key,
cipherType: 'base64'
})
// ecb模式
// const sm4Instance = new sm4({
// key: k || this.key, // key值与后端一致
// mode: 'ecb', // 加密的方式有两种,ecb和cbc两种,这里使用的是ecb,cbc模式还要加一个iv的参数,ecb不用
// cipherType: 'base64'
// })
return sm4Instance.decrypt(text)
// 明文cbc:中国国密4-cbc 加解密算法
// 明文ecb:中国国密加解密算法
}
}
备注:(3)gm-crypt的国密4加密,需要修改文件 node_modules\gm-crypt\src\crypt.js 如下
改1:return unescape(encodeURIComponent(str)).split(‘’).map(function(val) {return val.charCodeAt();});
改2:return decodeURIComponent(escape(String.fromCharCode.apply(null, strBuffer)));
2、国密3(仅支持加密,不能解密)
(1)gm-crypto
import { SM3 } from 'gm-crypto'
export class EncryptionUtil {
// 国密3加密
smEncrypt() {
// eslint-disable-next-line new-cap
const sm3Encrypt = SM3.digest('国密3加密,不可解密', 'utf8', 'hex')
return sm3Encrypt
}
}
(2)sm-crypto(后端仅适配杂凑加密,hmac加密后台不支持)
export class EncryptionUtil {
// 国密3加密
smEncrypt() {
const sm3Encrypt0 = sm3('abc') // 杂凑加密,示例密文:66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0
return sm3Encrypt
}
}
3、国密2
(1)gm-crypto
import { SM2 } from 'gm-crypto'
export class EncryptionUtil {
// 前端密钥
keyClass: any = {
publicKey: '', // 公钥加密
privateKey: '' // 私钥解密
};
constructor(/* 亦可后端传参密钥 */) {
// 前端随机生成密钥
this.keyClass = SM2.generateKeyPair()
}
// 国密2加密
smEncrypt(text: any/* , k: string 后端传公钥 */) {
// eslint-disable-next-line new-cap
// 公钥加密
const sm2Encrypt = SM2.encrypt(text, this.keyClass.publicKey, {
inputEncoding: 'utf8',
outputEncoding: 'hex',
pc: true
})
// 示例公钥:"publicKey":"04a8d6bff96d3a7d1352ab69d10e35d93b7a9cc9bd69aff3d5946a0a5b1c2a454f94f06e99aa080088a27f49d7407ca930069274e21f1923f6a537ae8a9e62e85a"
// 示例明文:SM2 椭圆曲线公钥密码算法
// 示例密文:04bc77866178b842cb8fc0242cf359416c57b95a991d2a0cebca15fe9f2484c0c99f8b6c4f4f0856160a0f053de0acf1a205935e43c45cff35ec2b5e464f271b0ccb2fec37cdb5b6e71e7528205d6a08b1040ae6069a25b7e575053185e7b2ab00f423c7ed79fb06d1baeab4f4ad780521d93dedca96a5ebd0d70a239d7969244ced68
return sm2Encrypt
}
// 国密2解密
smDecrypt(text: any/* , k: string 后端传私钥 */) {
// eslint-disable-next-line new-cap
// 私钥解密
const sm2Decrypt = SM2.decrypt(text, this.keyClass.privateKey, {
inputEncoding: 'base64',
outputEncoding: 'utf8',
pc: true
})
// 示例私钥:71542a6cc09d9e06e9f1e1c305fc24dc51b0ee91b5b1fe0ed7b31e5d6f71d6e1
// 示例密文:BDLfCL0Ds0ohVBjcraUxPhf/GrWCXmoRoBfrjEID7siTLu+EiTqKY3da6oRkKfICJvk0sxS/dnm4k/MEp9CAsGWUOFbOsidbp37Jn4h8PRhyVPMKSDD/e1j+ntC+BpTBlOrC0Vd02Wod61IfpDAcl0XepD5uIIsn1Enf5G/6RQlLfFnBjT4uozgoU0cSVP6LNJrv3FyKhKpd2bxM1CvSFXWPwyAP/DGGcg==
// 示例明文: { "zoneCode":3202000000, "orderType":4, "curdepartment":"3202810201"}
return sm2Decrypt
}
}
备注:(1)gm-crypto的国密2需修改文件 node_modules\gm-crypto\types\index.d.ts 如下
(2)sm-crypto
const sm2 = require('sm-crypto').sm2
export class EncryptionUtil {
// 前端密钥
keyClass: any = {
publicKey: '',
privateKey: ''
};
constructor() {
// 前端生成密钥
this.keyClass = sm2.generateKeyPairHex()
// 示例密钥
// this.keyClass.publicKey = '04799a2643d99ed67ef52b196c56d79feecf2b2cad229be4ff5516b3eba0bbb80443f865cb1bd58c3df56112eb67ee88d60c6a513c6a3db9d4f0f9a2f9741004f4'
// this.keyClass.privateKey = '47ec13b27eb05008e7afe8d86ef61addbad779192e7846291b64bfb3b321c5f1'
}
// 国密2加密
smEncrypt(text: any/* , k: string */) {
const cipherMode = 1 // 1 - C1C3C2,0 - C1C2C3,默认为1
// 示例明文'hello sm2 by sm-crypto~'
// 公钥加密
const sm2Encrypt = sm2.doEncrypt(text, this.keyClass.publicKey, cipherMode)
return sm2Encrypt
}
// 国密2解密(传给后端时,密文前+'04')
smDecrypt(text: any/* , k: string */) {
const cipherMode = 1 // 1 - C1C3C2,0 - C1C2C3,默认为1
// 私钥解密
const sm2Decrypt = sm2.doDecrypt('04' + text, this.keyClass.privateKey, cipherMode)
// 示例密文
// text = '04' + '25d4d19fcc23750a7b470824780e84dc0ae0af5e44d9aa667c0096df9be6deb6ce36ae27142523270080b9a2916bd1316740ac65c6591b4906f0c2dc68dba29a07b10e867a050cabca65c0c054d3408cbd549a684b39dd556a7904822035b8bdc7b7021366324d47f673a337e3b453a0f28bec47891f3b'
// 示例明文 hello sm4 by sm-crypto~
return sm2Decrypt
}
}
三、其他
1、AES
配合后端加解密改造,AES(mode:GCM;padding:nopadding)
公众号/平台端无需安装新依赖,小程序需安装新依赖
(1)公众号js代码:
import crypto from 'crypto'
export class EncryptionUtil {
constructor({ key } = {}) {
this.key = key || 'Q6PL3a64b2*%%fcb' // 后台提供的aes密钥
}
// 加密
smEncrypt(text, k) {
const key = k || this.key
// 加密
const cipher = crypto.createCipheriv('aes-128-gcm', key, key)
const encrypted = cipher.update(text, 'utf8')
cipher.final()
const tag = cipher.getAuthTag()
const res = Buffer.concat([encrypted, tag])
return res.toString('base64')
// text = 'aes加密测试' 示例明文
// k = 'Q6PL3a64b2*%%fcb' 示例密钥
// aes加密结果示例: 4S5Q6zDDmywND2XboytC1YWAgqk9d5InliXFmwsftg==
}
// 解密
smDecrypt(text, k) {
const key = k || this.key
// 解密
var bData = Buffer.from(text, 'base64')
const tag1 = bData.slice(-16)
const cdata = bData.slice(0, bData.length - 16)
const decipher = crypto.createDecipheriv('aes-128-gcm', key, key)
decipher.setAuthTag(tag1)
var msg = decipher.update(cdata)
const fin = decipher.final()
const decryptedStr = new TextDecoder('utf8').decode(Buffer.concat([msg, fin]))
return decryptedStr
// 示例密文:text='4S5QLtACCOKrDFrwritRC9kYmxsqbOi2NSX2K2PGoV1aAq+2AQ=='
// k = 'Q6PL3a64b2*%%fcb' 示例密钥
// aes解密结果示例: aes java 加密测试
}
}
(2)小程序ts代码:
安装依赖:npm install crypto
npm install --save vue-buffer
/**
* AES-GCM-nopadding
*/
const crypto = require('crypto')
const Buffer = require('vue-buffer')
export class EncryptionUtil {
key: string
constructor({ key } = {}) {
this.key = key || 'Q6PL3a64b2*%%fcb'
}
// 加密(明文,密钥)
smEncrypt(text: any, k:string) {
k = k || this.key
const cipher = crypto.createCipheriv('aes-128-gcm', k, k)
const encrypted = cipher.update(text, 'utf8')
cipher.final()
const tag = cipher.getAuthTag()
const res = Buffer.concat([encrypted, tag])
const r = res.toString('base64')
return r
}
// 解密(密文,密钥)
smDecrypt(text: any, k:string) {
k = k || this.key
var bData = Buffer.from(text, 'base64')
const tag1 = bData.slice(-16)
const cdata = bData.slice(0, bData.length - 16)
const decipher = crypto.createDecipheriv('aes-128-gcm', k, k)
decipher.setAuthTag(tag1)
var msg = decipher.update(cdata)
const fin = decipher.final()
const decrypted = new TextDecoder('utf8').decode(Buffer.concat([msg, fin]))
return decrypted
}
}
2、RSA
配合后端加解密改造,RSA(mode:ECB;padding:OAEPWITHSHA-256ANDMGF1PADDING)
安装依赖:npm install node-forge
/**
* RSA-ECB-padding: OAEPWITHSHA-256ANDMGF1PADDING
*/
const forge = require('node-forge')
export class EncryptionUtil {
publicKey: string // 公钥
privateKey: string // 私钥
constructor() {
// 示例公钥、私钥
this.publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFJw1dxTTWtuztr6eXLPPvIo2zWVPioJ4x3NKw0RD0YhxYe2r5XjKAIVqwxDKwpQv6+GImbI41rjUEmgkGQhtp+zgAJj2ANrFXKdAbgXnUHYhpT/h4UoemF8uTEVmA826Zex//xkjeMdXsLb9aYAqutseQaMra51T+sbjLElUV2wIDAQAB'
this.privateKey = 'MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMUnDV3FNNa27O2vp5cs8+8ijbNZU+KgnjHc0rDREPRiHFh7avleMoAhWrDEMrClC/r4YiZsjjWuNQSaCQZCG2n7OAAmPYA2sVcp0BuBedQdiGlP+HhSh6YXy5MRWYDzbpl7H//GSN4x1ewtv1pgCq62x5BoytrnVP6xuMsSVRXbAgMBAAECfxuphVQD9nHAEpjFgl0pfsQAI9vLbBQuQC06c2oPQNYpqkBQK0hcMtcuh3CMjH6O5LKP1N1mHSEeiyuVtPgCoOprfV8G+JNRMYfaNYErtN/WCj2SfIZ9FiPckaOFwaBqUISk5p3qqZu3mSkjfMCjJPUb1hm15IIEYg1Tl5CoEIkCQQD0cn/Ml1lJ/VGXSHW/ME+noTU2a2G5iOLd2koqMipOXKF0m6bJY1sA+uu+j/UpsecIrCDIJJRfk07fgtAg87V1AkEAznhY3eL7qkZEu8nqkZi9iqpyQW0ZepWFLF6vt3INP/2itrCbvh7iNxV2Oef/+OeWcc8m/87oZGhPgVpOXkUkDwJAFFuczRslsoXIT8MXG08Ysys31UpoHx2JV1SgrJb08wW/5Ig6AbemkpRTIdG3ZzuLtCsxp7l0KemIvhCU6MmjKQJBAKfz7943KR8e4ASeQKjFRdIJyr18ARDdliI8t9WS+kJGkVjpGxexybSjSbPbDDcuNAxKRWArsJEU5S/FBSDcP3MCQQDPPcnjEWCSmI6lKmaCUfYblCEzySEeyr2V4eXzJEGK4GbZQ6ESd7MhITsgDwaZbt/Eb8ai+QMqXTmK4qnLOcIl'
}
// 加密(明文,公钥)
smEncrypt(text: any, k:string) {
// text = 'ceshi测试' 示例明文
k = this.publicKey // 示例公钥
const publicKeyAll = '-----BEGIN PUBLIC KEY-----\n' + k + '\n-----END PUBLIC KEY-----'
const pKey = forge.pki.publicKeyFromPem(publicKeyAll)
const buffer = forge.util.createBuffer(text, 'utf8')
const bytes = buffer.getBytes()
// 使用公钥加密
const encrypted = forge.util.encode64(pKey.encrypt(bytes, 'RSA-OAEP', {
md: forge.md.sha256.create(),
mgf1: {
md: forge.md.sha256.create()
}
}))
return encrypted
// 示例密文:FGFTjGb7D9uWIP0R5hCbTVeqqJJIt4FUlrVvtVg7QIYcL3gABS5dqw4KHeq8rJU2mtTq2t965kuk7OUWLPjUxvQ300nhhtbUsH/gI7XrCZuYv8xOylgVq0L1Wk5kSXxLqf27jvPShcS1KkGOfk9eO9Grgoq1+dD8Hi0XIh6DXts=
}
// 解密(密文,私钥)
smDecrypt(text: any, k:string) {
// text = 'jNxkgLRjsp9Nh8L4kJwRDUcoNGQxdYC0LPX0Ml7aVVE/rMH/kEDWgMXDtVDuqnxqRQbxH1v6BQuQWNlV9y/KCKo+ont5lopWS9xyiKdNmJdZvAOJogVy34E9QFJLBxHvpBFodRhcyyNgWfzxtnHFbfyF8cRLYPgkeSacVP5hfzc=' 示例密文
k = this.privateKey // 示例私钥
const priveKeyAll = '-----BEGIN PRIVATE KEY-----\n' + k + '\n-----END PRIVATE KEY-----'
const privateKey = forge.pki.privateKeyFromPem(priveKeyAll)
const b = forge.util.decode64(text, 'base64')
// 使用私钥解密
const decrypted = forge.util.decodeUtf8(privateKey.decrypt(b, 'RSA-OAEP', {
md: forge.md.sha256.create(),
mgf1: {
md: forge.md.sha256.create()
}
}))
return decrypted
}
}
3、MD5(不可解密)
安装依赖:npm install crypto-js
const CryptoJS = require('crypto-js')
export class EncryptionUtil {
// 加密
smEncrypt(text: any) {
text = 'MD5加密'
const encrypted = CryptoJS.MD5(text).toString()
console.log(encrypted)
return encrypted
}
}