|
| 1 | +import pki from 'node-forge/lib/pki'; |
| 2 | +import md from 'node-forge/lib/md'; |
| 3 | +import cipher from 'node-forge/lib/cipher'; |
| 4 | +import util from 'node-forge/lib/util'; |
| 5 | + |
| 6 | +/** |
| 7 | + * @private |
| 8 | + * @function RSAEncrypt |
| 9 | + * @description RSAES-OAEP/SHA-256/MGF1-SHA-1加密,对应java的RSA/ECB/OAEPWithSHA-256AndMGF1Padding |
| 10 | + * @param publicKeyStr - RSA 公钥 |
| 11 | + * @param message - 需要加密的信息 |
| 12 | + * @returns {string|boolean} 加密成功返回base64编码的密文,加密失败返回false |
| 13 | + */ |
| 14 | +export function RSAEncrypt (publicKeyStr, message) { |
| 15 | + if (publicKeyStr && publicKeyStr.indexOf('BEGIN PUBLIC KEY') === -1) { // 转为PEM格式 |
| 16 | + publicKeyStr = `-----BEGIN PUBLIC KEY-----\n${publicKeyStr}\n-----END PUBLIC KEY-----`; |
| 17 | + } |
| 18 | + const publicKey = pki.publicKeyFromPem(publicKeyStr); |
| 19 | + const obj = { |
| 20 | + md: md.sha256.create(), |
| 21 | + mgf1: { |
| 22 | + md: md.sha1.create() |
| 23 | + } |
| 24 | + }; |
| 25 | + const encrypted = publicKey.encrypt(message, 'RSA-OAEP', obj); |
| 26 | + if (!encrypted) { |
| 27 | + return false; // 加密失败 |
| 28 | + } |
| 29 | + return window.btoa(encrypted); |
| 30 | +} |
| 31 | + |
| 32 | +/** |
| 33 | + * @private |
| 34 | + * @function AESGCMDecrypt |
| 35 | + * @description AES/GCM解密 |
| 36 | + * @param key - 16位 |
| 37 | + * @param iv - 12位 |
| 38 | + * @param cipherText - 密文 = base64转码(加密内容 + 16位的mac值) |
| 39 | + * @returns {boolean|string} 解密成功返回明文,解密失败返回false |
| 40 | + */ |
| 41 | +export function AESGCMDecrypt (key, iv, cipherText) { |
| 42 | + const cipherStrAndMac = window.atob(cipherText); |
| 43 | + const cipherStr = cipherStrAndMac.substring(0, cipherStrAndMac.length - 16); |
| 44 | + const mac = cipherStrAndMac.substring(cipherStrAndMac.length - 16); |
| 45 | + const decipher = cipher.createDecipher('AES-GCM', util.createBuffer(key)); |
| 46 | + decipher.start({ |
| 47 | + iv: util.createBuffer(iv), |
| 48 | + additionalData: '', // optional |
| 49 | + tagLength: 128, // optional, defaults to 128 bits |
| 50 | + tag: mac // authentication tag from encryption |
| 51 | + }); |
| 52 | + decipher.update(util.createBuffer(cipherStr)); |
| 53 | + const pass = decipher.finish(); |
| 54 | + if (pass) { |
| 55 | + return util.decodeUtf8(decipher.output.data); |
| 56 | + } |
| 57 | + return false; |
| 58 | +} |
| 59 | + |
| 60 | +/** |
| 61 | + * @private |
| 62 | + * @function AESGCMEncrypt |
| 63 | + * @description AES/GCM加密 |
| 64 | + * @param key - 16位 |
| 65 | + * @param iv - 12位 |
| 66 | + * @param msg - 明文 |
| 67 | + * @returns {boolean|string} 加密成功返回明文,加密失败返回false |
| 68 | + */ |
| 69 | +export function AESGCMEncrypt (key, iv, msg) { |
| 70 | + msg = util.encodeUtf8(msg); |
| 71 | + const cipherInstance = cipher.createCipher('AES-GCM', key); |
| 72 | + cipherInstance.start({ |
| 73 | + iv: iv, |
| 74 | + additionalData: '', // 'binary-encoded string', // optional |
| 75 | + tagLength: 128 // optional, defaults to 128 bits |
| 76 | + }); |
| 77 | + cipherInstance.update(util.createBuffer(msg)); |
| 78 | + const pass = cipherInstance.finish(); |
| 79 | + if (pass) { |
| 80 | + const encrypted = cipherInstance.output; |
| 81 | + const tag = cipherInstance.mode.tag; |
| 82 | + return window.btoa(encrypted.data + tag.data); |
| 83 | + } |
| 84 | + return false; |
| 85 | +} |
| 86 | + |
| 87 | +/** |
| 88 | + * @private |
| 89 | + * @function generateAESRandomKey |
| 90 | + * @description 生成随机的16位 AES key |
| 91 | + * @returns {string} |
| 92 | + */ |
| 93 | +export function generateAESRandomKey () { |
| 94 | + return randomString(16); |
| 95 | +} |
| 96 | + |
| 97 | +/** |
| 98 | + * @private |
| 99 | + * @function generateAESRandomIV |
| 100 | + * @description 生成随机的12位 AES iv |
| 101 | + * @returns {string} |
| 102 | + */ |
| 103 | +export function generateAESRandomIV () { |
| 104 | + return randomString(12); |
| 105 | +} |
| 106 | + |
| 107 | +/** |
| 108 | + * @private |
| 109 | + * @function randomString |
| 110 | + * @description 生成指定长度的随机字符串 |
| 111 | + * @param length - 随机字符串长度 |
| 112 | + * @returns {string} |
| 113 | + */ |
| 114 | +function randomString (length) { |
| 115 | + const str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; |
| 116 | + let result = ''; |
| 117 | + for (let i = length; i > 0; --i) { result += str[Math.floor(Math.random() * str.length)]; } |
| 118 | + return result; |
| 119 | +} |
0 commit comments