decrypt_pdf_wed.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. function arrayBufferToBase64(buffer: ArrayBuffer): string {
  2. let binary = '';
  3. const bytes = new Uint8Array(buffer);
  4. const len = bytes.byteLength;
  5. for (let i = 0; i < len; i++) {
  6. binary += String.fromCharCode(bytes[i]);
  7. }
  8. return btoa(binary);
  9. }
  10. async function getKey(password: string): Promise<ArrayBuffer> {
  11. const encoder = new TextEncoder()
  12. const data = encoder.encode(password)
  13. const hash = await crypto.subtle.digest('SHA-256', data)
  14. return hash
  15. }
  16. function readUint32BE(buffer: ArrayBuffer, offset: number = 0): number {
  17. const view = new DataView(buffer);
  18. return view.getUint32(offset, false); // false 表示使用大端(Big Endian)
  19. }
  20. /**
  21. * Web端 AES-256-GCM 解密
  22. * @param encrypted - 加密后的数据(不包含认证标签)
  23. * @param keyBuffer - 原始密钥(32 字节)
  24. * @param ivBuffer - 初始化向量(12 字节)
  25. * @param authTag - 认证标签(16 字节)
  26. * @returns 解密后的明文字符串
  27. */
  28. async function decryptAES_GCM(
  29. encrypted: ArrayBuffer,
  30. keyBuffer: ArrayBuffer,
  31. ivBuffer: ArrayBuffer,
  32. authTag: ArrayBuffer
  33. ): Promise<ArrayBuffer> {
  34. // 1. 导入密钥
  35. const key = await crypto.subtle.importKey(
  36. 'raw',
  37. keyBuffer,
  38. 'AES-GCM',
  39. false,
  40. ['decrypt']
  41. );
  42. // 2. 将认证标签附加到加密数据末尾
  43. const combinedData = new Uint8Array(encrypted.byteLength + authTag.byteLength);
  44. combinedData.set(new Uint8Array(encrypted), 0);
  45. combinedData.set(new Uint8Array(authTag), encrypted.byteLength);
  46. // 3. 解密操作
  47. try {
  48. const decrypted = await crypto.subtle.decrypt(
  49. {
  50. name: 'AES-GCM',
  51. iv: ivBuffer,
  52. tagLength: 128, // 默认的 GCM 标签长度
  53. },
  54. key,
  55. combinedData.buffer
  56. );
  57. // 将解密后的数据转换为字符串
  58. // return new TextDecoder().decode(decrypted);
  59. return decrypted
  60. } catch (error) {
  61. console.error('Decryption failed:', error);
  62. throw error;
  63. }
  64. }
  65. async function decryptGCM(url: string): Promise<Uint8Array | undefined> {
  66. const res = await fetch(url).catch((err) => {
  67. console.error('Error during fetch:', err)
  68. return undefined
  69. })
  70. if (!res) return undefined
  71. const buffer = await res.arrayBuffer().catch((err) => {
  72. console.error('Error during arrayBuffer:', err)
  73. return undefined
  74. })
  75. if (!buffer) return undefined
  76. const iv = buffer.slice(0, 12)
  77. const lenBuf = buffer.slice(buffer.byteLength - 4)
  78. const pLen = readUint32BE(lenBuf)
  79. const passwordBuffer = buffer.slice(buffer.byteLength - pLen - 4, buffer.byteLength - 4)
  80. const password = arrayBufferToBase64(passwordBuffer)
  81. const authTag = buffer.slice(buffer.byteLength - pLen - 4 - 16, buffer.byteLength - pLen - 4)
  82. const encrypted = buffer.slice(12, buffer.byteLength - pLen - 4 - 16)
  83. const key = await getKey(password).catch((err) => {
  84. console.error('Error during get key:', err)
  85. return undefined
  86. })
  87. if (!key) return undefined
  88. const decrypted = await decryptAES_GCM(encrypted, key, iv, authTag).catch((err) => {
  89. console.error('Error during decrypt:', err)
  90. return undefined
  91. })
  92. if (!decrypted) return undefined
  93. return new Uint8Array(decrypted)
  94. }
  95. // 解密示例
  96. const decryptedData = await decryptGCM(withBase(props.fileUrl)).catch((err) => {
  97. console.error('Error during decrypt GCM:', err)
  98. return undefined
  99. })
  100. if (!decryptedData) return