随笔 - 118  文章 - 0 评论 - 341 阅读 - 299万
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

1. 场景

浏览器原生支持了AES-GCM。

参考资料:https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt

 

2. 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/**
 * AES-GCM helper
 */
var aesGcmHelper = {
  _keyMap: new Map(),
 
  getIv(keyRaw) {
    if (this._keyMap.has(keyRaw)) {
      return this._keyMap.get(keyRaw).iv;
    }
    let iv = crypto.getRandomValues(new Uint8Array(12));
    this._keyMap.set(keyRaw, Object.assign({}, this._keyMap.get(keyRaw), { iv }));
    return iv;
  },
 
  /**
   * hex to ArrayBuffer
   * @param {String} hex
   */
  hex2Buf(hex) {
    let buf = new Uint8Array(
      hex.match(/[\da-f]{2}/gi).map(function (h) {
        return parseInt(h, 16);
      })
    );
    return buf;
  },
 
  /**
   * base64 to ArrayBuffer
   * @param {String} hex
   */
  base64ToBuf(base64) {
    var binaryString = window.atob(base64);
    var bytes = new Uint8Array(binaryString.length);
    for (var i = 0; i < binaryString.length; i++) {
      bytes[i] = binaryString.charCodeAt(i);
    }
    return bytes.buffer;
  },
  /** * ArrayBuffer to hex * @param {ArrayBuffer} buffer */ buf2Hex(buffer) {
    let binary = [...new Uint8Array(buffer)].map((x) => x.toString(16).padStart(2, '0')).join('');
    return binary;
  },
 
  /**
   * ArrayBuffer to base64
   * @param {ArrayBuffer} buffer
   */
  buf2Base64(buffer) {
    let binary = [...new Uint8Array(buffer)].map((x) => String.fromCharCode(x)).join('');
    return window.btoa(binary);
  },
 
  /**
   * encrypt
   * @param {String} data data
   * @param {String} keyRaw key raw
   * @param {Uint8Array} iv iv
   * @return {Promise}
   */
  async encrypt(data, keyRaw, iv = null) {
    if (iv == null) {
      iv = this.getIv(keyRaw);
    } else {
      this._keyMap.set(keyRaw, Object.assign({}, this._keyMap.get(keyRaw), { iv }));
    }
 
    let encoded = new TextEncoder().encode(data);
    let key = await crypto.subtle.importKey('raw', new TextEncoder().encode(keyRaw), 'AES-GCM', true, ['encrypt', 'decrypt']);
    let ciphertext = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encoded);
    return ciphertext;
  },
 
  /**
   * decrypt
   * @param {ArrayBuffer} encrypted encrypted data
   * @param {String} keyRaw key raw
   * @param {Uint8Array} iv iv
   * @return {Promise}
   */
  async decrypt(encrypted, keyRaw, iv = null) {
    if (iv == null) {
      iv = this.getIv(keyRaw);
    }
    if (!ArrayBuffer.isView(encrypted) && toString.apply(encrypted) != '[object ArrayBuffer]') {
      throw new Error('encrypted must is ArrayBuffer');
    }
 
    let key = await crypto.subtle.importKey('raw', new TextEncoder().encode(keyRaw), 'AES-GCM', true, ['encrypt', 'decrypt']);
    let decrypted = '';
    try {
      decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, encrypted);
    } catch (error) {
      throw new Error(error);
      return '';
    }
    let decoded = new TextDecoder().decode(decrypted);
    return decoded;
  }
};

 

3. 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(async () => {
  let iv = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
  let keyRaw = 'IHieUI!%9awQqszp';
 
  // 1.encrypt test
  let ciphertext = await aesGcmHelper.encrypt('hello, Tom', keyRaw, iv);
  // - hex
  let ciphertextOfHex = aesGcmHelper.buf2Hex(ciphertext);
  console.log(ciphertextOfHex); // => b85320c50c256bc27dc1113a92a83614d60161f6af4d1ce237b0
  // - base64
  let ciphertextOfBase64 = aesGcmHelper.buf2Base64(ciphertext);
  console.log(ciphertextOfBase64); // => uFMgxQwla8J9wRE6kqg2FNYBYfavTRziN7A=
 
  // 2.decrypt test
  // - hex
  let decodedData = await aesGcmHelper.decrypt(aesGcmHelper.hex2Buf(ciphertextOfHex), keyRaw, iv);
  console.log(decodedData); // => hello, Tom
  // - base64
  decodedData = await aesGcmHelper.decrypt(aesGcmHelper.base64ToBuf(ciphertextOfBase64), keyRaw, iv);
  console.log(decodedData); // => hello, Tom
})();

  

 

posted on   FangMu  阅读(1454)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示