日常开发偶尔会涉及到加解密的需求,比如对登录密码加密、解密接口返回的敏感数据,这里简单总结 CryptoJS、JSEncrypt 等第三方库、crypto
和 Web Crypto API 使用。
CryptoJS (crypto-js)
CryptoJS (crypto-js),实现了 DES
/AES
/SHA256
/HMAC-SHA512
等算法(没有实现 RSA
算法),支持浏览器和 Node.js,作者 Jeff Mott,最初开源在 Google Code https://code.google.com/p/crypto-js/,最后一版为 v3.1.2。
目前 npm 上的 crypto-js 包由 Evan Vosberg 维护,GitHub 地址为 https://github.com/brix/crypto-js,文档地址 https://cryptojs.gitbook.io/docs/。
使用 crypto-js
进行简单的 3DES 加解密:
import Base64 from 'crypto-js/enc-base64';
import Hex from 'crypto-js/enc-hex';
import Utf8 from 'crypto-js/enc-utf8';
import TripleDES from 'crypto-js/tripledes';
import ECB from 'crypto-js/mode-ecb';
import Pkcs7Pad from 'crypto-js/pad-pkcs7';
import HexFormat from 'crypto-js/format-hex';
/**
* 3DES 加密
* @param content 明文
* @param key 密钥
* @returns
*/
const encrypt = (content: string, key: string) => {
return TripleDES.encrypt(content, Utf8.parse(key), {
mode: ECB,
padding: Pkcs7Pad
}).toString(HexFormat);
};
/**
* 3DES 解密
* @param content 密文
* @param key 密钥
* @returns
*/
const decrypt = (content: string, key: string) => {
const encrypted = Base64.stringify(Hex.parse(content));
return TripleDES.decrypt(encrypted, Utf8.parse(key), {
mode: ECB,
padding: Pkcs7Pad
}).toString(Utf8);
};
const privateKey = '123456789012345678901234';
const plaintext = 'keqingrong@outlook.com';
const ciphertext = 'f5acc6d5a16c4ed1409c1d802809078f7632e10aa8b98aba';
const encrypted = encrypt(plaintext, privateKey);
console.assert(encrypted === ciphertext);
const decrypted = decrypt(ciphertext, privateKey);
console.assert(decrypted === plaintext);
JSEncrypt (jsencrypt)
JSEncrypt 实现了 RSA
加密算法,由 Travis Tidwell 在 Tom Wu 的 jsbn http://www-cs-students.stanford.edu/~tjw/jsbn/ 基础上开发。JSEncrypt 目前只支持浏览器,不支持 Node,见 https://github.com/travist/jsencrypt/issues/56。
在使用 RSA 加密算法之前,需要使用 OpenSSL 生成私钥,再根据私钥生成公钥。
openssl genrsa -out rsa_1024_priv.pem 1024
openssl rsa -pubout -in rsa_1024_priv.pem -out rsa_1024_pub.pem
这样我们便得到了私钥 rsa_1024_priv.pem
和公钥 rsa_1024_pub.pem
。
使用公钥加密:
import JSEncrypt from 'jsencrypt';
const publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKKqgnPzneyl2kz7G3yyBgeIKk
UPk17DHfvU0ElcZt1tJpqFgG8L6X4Xb3QyDagxqa/HKMSDrlpRakbzgJTs6kfFCo
fIvNhzQwQNfEnpKdWK7Im7dizPIzIi58ogFHToDAEWfOtpaXMiqY6pknvtVSJHMN
lbDJ3WDkPKj8KOUBGQIDAQAB
-----END PUBLIC KEY-----`;
const encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
const plaintext = 'keqingrong@outlook.com';
const encrypted = encrypt.encrypt(plaintext);
console.log(encrypted);
使用私钥解密:
import JSEncrypt from 'jsencrypt';
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDKKqgnPzneyl2kz7G3yyBgeIKkUPk17DHfvU0ElcZt1tJpqFgG
8L6X4Xb3QyDagxqa/HKMSDrlpRakbzgJTs6kfFCofIvNhzQwQNfEnpKdWK7Im7di
zPIzIi58ogFHToDAEWfOtpaXMiqY6pknvtVSJHMNlbDJ3WDkPKj8KOUBGQIDAQAB
AoGAYuj73DfS2G2p4zi6enGnJYvQXxQ+2WL2A8FaLSQaMSMpTwhOCRdAKI7m5ZKy
QDZkje91G607I5/htBG2GNe1wWUNMgJmuPMuI738wYFRVj/VhFgfoB2XiKgzvA3q
CFyrOPt1d4H8XXMdAFEYpqMCc2bgcFrKWB+kZMQ715pboAECQQDxqXdbMFaIhB4m
Tg+wWnrUVUtWq1RrKxkZaf46hMKLPpdVrWjzgMY9DvMob8s3wTLcDXFmtBUHD5Zb
SVLgCaqJAkEA1ilOpHsuvXtByIWffB7oo65HQKwN5KegbG/kljE6Gz7rnjtEneFy
DCV02PTL9Jxf2NhlCTeSxwQcgInZpne+EQJADvHxDLWnlFe/WZUYSUq/L+R6fUip
Ntt6eOTiMRJGyb+8MjNAO1bqa5pCFW0cfz02fP9j1PssFby0Cr81Hd/bKQJBALzu
RAqnAVz319jmyQPe4K1FmmZbYwZNOyFutOIrG2/d2k8FSkteEBbXFHYxv5xUN9o9
TSUMedhIsDxVYEWTbYECQFF4KoYq2iBud98xNZoaMUToUNaF9WJGNYqCXyOUMk3A
Hohxi0kf+Nx1/+AVGFEPR1+FJgqFHEAaimgEL53mfU8=
-----END RSA PRIVATE KEY-----`;
const encrypt = new JSEncrypt();
encrypt.setPrivateKey(privateKey);
const decrypted = encrypt.decrypt(encrypted);
console.log(decrypted === plaintext);
Node-RSA (node-rsa)
Node-RSA 是 RSA
加密算法的 Node 实现,同样基于 jsbn 开发。
使用公钥加密:
const NodeRSA = require('node-rsa');
const publicKey = `省略,同上`;
const publicKeyObj = new NodeRSA(publicKey);
const plaintext = 'keqingrong@outlook.com';
const encrypted = publicKeyObj.encrypt(plaintext, 'base64');
console.log(encrypted);
使用私钥解密:
const NodeRSA = require('node-rsa');
const privateKey = `省略,同上`;
const privateKeyObj = new NodeRSA(privateKey);
const decrypted = privateKeyObj.decrypt(encrypted, 'utf8');
console.log(decrypted);
Node crypto
除了使用第三方库,Node 环境可以直接使用内置的 crypto 模块,基于 OpenSSL 封装。
使用公钥进行 RSA 加密:
const crypto = require('crypto');
const publicKey = `省略,同上`;
const plaintext = 'keqingrong@outlook.com';
const encrypted = crypto
.publicEncrypt(
{
key: publicKey,
padding: crypto.constants.RSA_PKCS1_PADDING
},
Buffer.from(plaintext)
)
.toString('base64');
console.log(encrypted);
使用私钥进行 RSA 解密:
const crypto = require('crypto');
const privateKey = `省略,同上`;
const decrypted = crypto
.privateDecrypt(
{
key: privateKey,
padding: crypto.constants.RSA_PKCS1_PADDING
},
Buffer.from(encrypted, 'base64')
)
.toString();
console.log(decrypted === plaintext);
crypto
模块包含的类、方法、属性:
- 类
Certificate
Cipher
Decipher
DiffieHellman
DiffieHellmanGroup
ECDH
Hash
Hmac
KeyObject
Sign
Verify
X509Certificate
- 方法和属性
crypto.constants
crypto.createPrivateKey()
crypto.createPublicKey()
crypto.privateDecrypt()
crypto.privateEncrypt()
crypto.publicDecrypt()
crypto.publicEncrypt()
crypto.webcrypto
Web Cryptography API
Web Cryptography API 是 W3C 下属 Web 密码学工作组(Web Cryptography Working Group)为 Web 制定的密码学领域规范。包含以下 API:
- Crypto
crypto.subtle
crypto.getRandomValues()
crypto.randomUUID()
- CryptoKey
cryptoKey.type
cryptoKey.extractable
cryptoKey.algorithm
cryptoKey.usages
- CryptoKeyPair
cryptoKeyPair.privateKey
cryptoKeyPair.publicKey
- SubtleCrypto
subtle.encrypt()
subtle.decrypt()
subtle.sign()
subtle.verify()
subtle.digest()
subtle.generateKey()
subtle.deriveKey()
subtle.deriveBits()
subtle.importKey()
subtle.exportKey()
subtle.wrapKey()
subtle.unwrapKey()
Chrome、Safari、Firefox 等现代浏览器最新版和 Node.js v15 都已经实现 Web Cryptography 大部分 API,可以参考 Can I use。
相关链接
- CryptoJS
- npm https://www.npmjs.com/package/crypto-js
- Souce code (Google Code) https://code.google.com/p/crypto-js/
- Source code (GitHub) https://github.com/brix/crypto-js
- JSEncrypt
- Node-RSA
- Node
- Crypto https://nodejs.org/api/crypto.html
- Web Crypto API https://nodejs.org/api/webcrypto.html
- Web Cryptography API
- Specification Draft https://w3c.github.io/webcrypto/
- Specification https://www.w3.org/TR/WebCryptoAPI/
- Crypto interface https://developer.mozilla.org/en-US/docs/Web/API/Crypto
- Window.crypto https://developer.mozilla.org/en-US/docs/Web/API/Window/crypto