UNPKG

wechatpay-axios-plugin

Version:

微信支付APIv2及v3 NodeJS SDK,支持CLI模式请求OpenAPI,支持v3证书下载,v2付款码支付、企业付款、退款,企业微信-企业支付-企业红包/向员工付款,v2&v3 Native支付、扫码支付、H5支付、JSAPI/小程序支付、合单支付...

220 lines (191 loc) 6.05 kB
/* eslint max-classes-per-file: ["error", 4], no-bitwise: ["error", { "allow": ["~"] }] */ const { createCipheriv, createDecipheriv } = require('crypto'); /** * @typedef {import('node:crypto').KeyLike} KeyLike * @typedef {import('node:crypto').BinaryLike} BinaryLike */ const utf8 = 'utf8'; const base64 = 'base64'; const hex = 'hex'; const BLOCK_SIZE = 16; const ALGO_AES_256_GCM = 'aes-256-gcm'; const ALGO_AES_256_ECB = 'aes-256-ecb'; const ALGO_AES_128_CBC = 'aes-128-CBC'; /** The PKCS#7 padding/unpadding implementation */ const PKCS7 = { /** * padding, 32 bytes/256 bits `secret key` may optional need the last block. * * @param {BinaryLike} thing - The input * @param {boolean} [optional = true] - The flag for the last padding, default `true` * * @return {Buffer} - The PADDING tailed payload */ padding(thing, optional = true) { const payload = Buffer.from(thing); const pad = BLOCK_SIZE - (payload.byteLength % BLOCK_SIZE); if (optional && pad === BLOCK_SIZE) { return payload; } return Buffer.concat([payload, Buffer.alloc(pad, pad)]); }, /** * unpadding * @memberof Aes.pkcs7# * * @param {BinaryLike} thing - The input * @return {Buffer} - The PADDING wiped payload */ unpadding(thing) { const byte = Buffer.alloc(1); const payload = Buffer.from(thing); payload.copy(byte, 0, payload.byteLength - 1); const pad = byte.readUInt8(); const len = payload.length; if (!~~Buffer.compare(Buffer.alloc(pad, pad), payload.subarray(len - pad, len))) { return payload.subarray(0, len - pad); } return payload; }, }; /** * Aes encrypt/decrypt using `aes-256-gcm` algorithm with `AAD`. */ class AesGcm { /** * Encrypts plaintext. * * @param {string} plaintext - Text to encode. * @param {KeyLike} key - The secret key. * @param {string} iv - The initialization vector. * @param {string} [aad = ''] - The additional authenticated data, maybe empty string. * * @returns {string} Base64-encoded ciphertext. */ static encrypt(plaintext, key, iv, aad = '') { const cipher = createCipheriv(ALGO_AES_256_GCM, key, iv).setAAD(Buffer.from(aad)); return Buffer.concat([ cipher.update(plaintext, utf8), cipher.final(), cipher.getAuthTag(), ]).toString(base64); } /** * Decrypts ciphertext. * * @param {string} ciphertext - Base64-encoded ciphertext. * @param {KeyLike} key - The secret key. * @param {string} iv - The initialization vector. * @param {string} [aad = ''] - The additional authenticated data, maybe empty string. * * @returns {string} Utf-8 plaintext. */ static decrypt(ciphertext, key, iv, aad = '') { const buf = Buffer.from(ciphertext, base64); const len = buf.length; const tag = buf.subarray(len - BLOCK_SIZE, len); const payload = buf.subarray(0, len - BLOCK_SIZE); const decipher = createDecipheriv(ALGO_AES_256_GCM, key, iv); // patches for Node < 18.0.0 // more @see https://github.com/nodejs/node/pull/20039 const tagLen = tag.length; if (tagLen > 16 || (tagLen < 12 && tagLen !== 8 && tagLen !== 4)) { const backport = new TypeError(`Invalid authentication tag length: ${tagLen}`); backport.code = 'ERR_CRYPTO_INVALID_AUTH_TAG'; throw backport; } decipher.setAuthTag(tag).setAAD(Buffer.from(aad)); return Buffer.concat([ decipher.update(payload, hex), decipher.final(), ]).toString(utf8); } } /** * Aes encrypt/decrypt using `aes-256-ecb` algorithm with pkcs7padding. */ class AesEcb { /** * Encrypts plaintext. * * @param {string} plaintext - Text to encode. * @param {KeyLike} key - The secret key. * * @returns {string} Base64-encoded ciphertext. */ static encrypt(plaintext, key) { const payload = PKCS7.padding(plaintext); const cipher = createCipheriv(ALGO_AES_256_ECB, key, null).setAutoPadding(false); return Buffer.concat([ cipher.update(payload, utf8), cipher.final(), ]).toString(base64); } /** * Decrypts ciphertext. * * @param {string} ciphertext - Base64-encoded ciphertext. * @param {KeyLike} key - The secret key. * * @returns {string} Utf-8 plaintext. */ static decrypt(ciphertext, key) { const payload = Buffer.from(ciphertext, base64); const decipher = createDecipheriv(ALGO_AES_256_ECB, key, null).setAutoPadding(false); return PKCS7.unpadding(Buffer.concat([ decipher.update(payload, hex), decipher.final(), ])).toString(utf8); } } /** * Aes encrypt/decrypt using `aes-128-cbc` algorithm with pkcs7padding. */ class AesCbc { /** * Encrypts plaintext. * * @param {string} plaintext - Text to encode. * @param {KeyLike} key - The secret key. * @param {string} iv - The initialization vector. * * @returns {string} Base64-encoded ciphertext. */ static encrypt(plaintext, key, iv) { const payload = PKCS7.padding(plaintext, false); const cipher = createCipheriv(ALGO_AES_128_CBC, key, iv).setAutoPadding(false); return Buffer.concat([ cipher.update(payload, utf8), cipher.final(), ]).toString(base64); } /** * Decrypts ciphertext. * * @param {string} ciphertext - Base64-encoded ciphertext. * @param {KeyLike} key - The secret key. * @param {string} iv - The initialization vector. * * @returns {string} Utf-8 plaintext. */ static decrypt(ciphertext, key, iv) { const payload = Buffer.from(ciphertext, base64); const decipher = createDecipheriv(ALGO_AES_128_CBC, key, iv).setAutoPadding(false); return PKCS7.unpadding(Buffer.concat([ decipher.update(payload, hex), decipher.final(), ])).toString(utf8); } } /** * Aes - Advanced Encryption Standard */ class Aes { static BLOCK_SIZE = BLOCK_SIZE static pkcs7 = PKCS7 static AesGcm = AesGcm static AesEcb = AesEcb static AesCbc = AesCbc static get default() { return this; } } module.exports = Aes;