/** * 加密工具函数 * 为微信小程序环境优化的加密工具集 */ const { decode: base32Decode } = require('./base32.js'); /** * 常量时间比较两个字符串 * 防止时间侧信道攻击 * * @param {string} a - 第一个字符串 * @param {string} b - 第二个字符串 * @returns {boolean} 是否相等 */ function constantTimeEqual(a, b) { if (typeof a !== 'string' || typeof b !== 'string') { return false; } if (a.length !== b.length) { return false; } let result = 0; for (let i = 0; i < a.length; i++) { result |= a.charCodeAt(i) ^ b.charCodeAt(i); } return result === 0; } /** * 安全的整数解析 * 带有范围检查 * * @param {number|string} value - 要解析的值 * @param {number} min - 最小值(包含) * @param {number} max - 最大值(包含) * @returns {number|null} 解析后的整数,如果无效则返回null */ function safeIntegerParse(value, min, max) { let num; if (typeof value === 'number') { num = value; } else if (typeof value === 'string') { num = parseInt(value, 10); } else { return null; } if (!Number.isInteger(num)) { return null; } if (num < min || num > max) { return null; } return num; } /** * 生成密码学安全的随机字节 * * @param {number} length - 需要的字节数 * @returns {Uint8Array} 随机字节数组 */ function getRandomBytes(length) { if (!Number.isInteger(length) || length <= 0) { throw new Error('Length must be a positive integer'); } // 优先使用微信小程序的随机数API if (typeof wx !== 'undefined' && wx.getRandomValues) { const array = new Uint8Array(length); wx.getRandomValues({ length: length, success: (res) => { array.set(new Uint8Array(res.randomValues)); }, fail: () => { // 如果原生API失败,回退到Math.random for (let i = 0; i < length; i++) { array[i] = Math.floor(Math.random() * 256); } } }); return array; } // 回退到Math.random(不够安全,但作为降级方案) const array = new Uint8Array(length); for (let i = 0; i < length; i++) { array[i] = Math.floor(Math.random() * 256); } return array; } /** * 生成指定长度的随机Base32密钥 * * @param {number} length - 密钥长度(字节) * @returns {string} Base32编码的密钥 */ function generateSecretKey(length = 20) { if (!Number.isInteger(length) || length < 16 || length > 64) { throw new Error('Key length must be between 16 and 64 bytes'); } const bytes = getRandomBytes(length); return require('./base32.js').encode(bytes); } /** * 验证Base32密钥的有效性和强度 * * @param {string} key - Base32编码的密钥 * @returns {boolean} 密钥是否有效且足够强 */ function validateBase32Secret(key) { try { // 检查是否是有效的Base32 if (!require('./base32.js').isValid(key)) { return false; } // 解码密钥 const decoded = base32Decode(key); // 检查最小长度(128位/16字节) if (decoded.length < 16) { return false; } // 检查是否全为0或1(弱密钥) let allZeros = true; let allOnes = true; for (const byte of decoded) { if (byte !== 0) allZeros = false; if (byte !== 255) allOnes = false; if (!allZeros && !allOnes) break; } if (allZeros || allOnes) { return false; } return true; } catch { return false; } } const { deriveKeyPBKDF2 } = require('./hmac.js'); module.exports = { constantTimeEqual, safeIntegerParse, getRandomBytes, generateSecretKey, validateBase32Secret, deriveKeyPBKDF2 };