init
This commit is contained in:
commit
2b8870a40e
51 changed files with 5845 additions and 0 deletions
165
utils/crypto.js
Normal file
165
utils/crypto.js
Normal file
|
@ -0,0 +1,165 @@
|
|||
/**
|
||||
* 加密工具函数
|
||||
* 为微信小程序环境优化的加密工具集
|
||||
*/
|
||||
|
||||
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
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue