crypto.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import * as crypto from 'crypto'
  2. import * as https from 'https'
  3. import * as http from 'http'
  4. import { URL } from 'url'
  5. /**
  6. * 鉴权加密
  7. * @param {*} params
  8. * @returns
  9. */
  10. export function getEncodeHeader(params = {}, appKey, appSecret) {
  11. const timestamp = parseInt(Date.now() / 1000 + '')
  12. const nonce = parseInt(Math.random() * 100000 + '') + timestamp
  13. const header = {
  14. 'x-bili-accesskeyid': appKey,
  15. 'x-bili-content-md5': getMd5Content(JSON.stringify(params)),
  16. 'x-bili-signature-method': 'HMAC-SHA256',
  17. 'x-bili-signature-nonce': nonce + '',
  18. 'x-bili-signature-version': '1.0',
  19. 'x-bili-timestamp': timestamp
  20. }
  21. const data = []
  22. for (const key in header) {
  23. data.push(`${key}:${header[key]}`)
  24. }
  25. const signature = crypto.createHmac('sha256', appSecret).update(data.join('\n')).digest('hex')
  26. return {
  27. Accept: 'application/json',
  28. 'Content-Type': 'application/json',
  29. ...header,
  30. Authorization: signature
  31. }
  32. }
  33. /**
  34. * MD5加密
  35. * @param {*} str
  36. * @returns
  37. */
  38. export function getMd5Content(str) {
  39. return crypto.createHash('md5').update(str).digest('hex')
  40. }
  41. /**
  42. * MD5 加密
  43. * @param str 待加密的字符串
  44. * @param length 输出长度(16 或 32,默认 32 位)
  45. * @param isUpperCase 是否返回大写字母(默认小写)
  46. * @returns 加密后的 MD5 字符串
  47. */
  48. export function getMd5DetailContent(str: string, length: 16 | 32 = 32, isUpperCase: boolean = false): string {
  49. const hash = crypto.createHash('md5').update(str).digest('hex')
  50. const result = length === 16 ? hash.substring(8, 24) : hash
  51. return isUpperCase ? result.toUpperCase() : result
  52. }
  53. /**
  54. * 根据 URL 获取文件并计算 MD5 值
  55. * @param fileUrl 文件的网络地址
  56. * @returns 文件的 MD5 值(32 位字符串)
  57. */
  58. export function getFileMd5FromUrl(fileUrl: string): Promise<string> {
  59. return new Promise((resolve, reject) => {
  60. try {
  61. const url = new URL(fileUrl);
  62. // 根据协议选择模块
  63. const client = url.protocol === 'https:' ? https : http;
  64. const request = client.get(url, (response) => {
  65. if (response.statusCode !== 200) {
  66. reject(new Error(`请求失败,状态码: ${response.statusCode}`));
  67. response.resume(); // 消耗响应数据以释放内存
  68. return;
  69. }
  70. const hash = crypto.createHash('md5'); // 创建 MD5 哈希对象
  71. response.on('data', (chunk) => hash.update(chunk)); // 更新哈希
  72. response.on('end', () => resolve(hash.digest('hex'))); // 返回 32 位 MD5 字符串
  73. });
  74. request.on('error', (error) => {
  75. reject(new Error(`网络请求出错: ${error.message}`));
  76. });
  77. } catch (error) {
  78. reject(new Error(`解析 URL 出错: ${error.message}`));
  79. }
  80. });
  81. }
  82. /**
  83. * RSA 加密,支持大数据分块加密
  84. * @param data 待加密的数据
  85. * @param publicKey 公钥字符串
  86. * @param maxEncryptBlock RSA 最大加密块大小(默认 53 字节,适用于 512 位 RSA 密钥)
  87. * @returns Base64 编码的加密结果
  88. */
  89. export function encryptData(data: string, publicKey: string, maxEncryptBlock: number = 53): string {
  90. try {
  91. const buffer = Buffer.from(data, 'utf8')
  92. const dataLength = buffer.length
  93. let offset = 0
  94. const encryptedBuffers: Buffer[] = []
  95. while (offset < dataLength) {
  96. const chunkSize = Math.min(maxEncryptBlock, dataLength - offset)
  97. const chunk = buffer.subarray(offset, offset + chunkSize)
  98. const encryptedChunk = crypto.publicEncrypt(
  99. {
  100. key: publicKey,
  101. padding: crypto.constants.RSA_PKCS1_PADDING
  102. },
  103. chunk
  104. )
  105. encryptedBuffers.push(encryptedChunk)
  106. offset += chunkSize
  107. }
  108. const encryptedBuffer = Buffer.concat(encryptedBuffers)
  109. return encryptedBuffer.toString('base64')
  110. } catch (error) {
  111. console.error('RSA 加密失败:', error)
  112. throw error
  113. }
  114. }