subtle.mjs raw

   1  // TinyJS Runtime — SubtleCrypto bridge (AES-CBC + random bytes)
   2  // Service worker version — identical to main app, SubtleCrypto available in SW scope.
   3  
   4  import { Slice } from './builtin.mjs';
   5  
   6  function sliceToU8(s) {
   7    if (s instanceof Uint8Array) return s;
   8    const u = new Uint8Array(s.$length);
   9    for (let i = 0; i < s.$length; i++) u[i] = s.$array[s.$offset + i];
  10    return u;
  11  }
  12  
  13  function u8ToSlice(u8) {
  14    const arr = new Array(u8.length);
  15    for (let i = 0; i < u8.length; i++) arr[i] = u8[i];
  16    return new Slice(arr, 0, u8.length, u8.length);
  17  }
  18  
  19  export function RandomBytes(dst) {
  20    const u8 = new Uint8Array(dst.$length);
  21    crypto.getRandomValues(u8);
  22    for (let i = 0; i < dst.$length; i++) dst.$array[dst.$offset + i] = u8[i];
  23  }
  24  
  25  export function AESCBCEncrypt(key, iv, plaintext, fn) {
  26    const k = sliceToU8(key), v = sliceToU8(iv), pt = sliceToU8(plaintext);
  27    crypto.subtle.importKey('raw', k, { name: 'AES-CBC' }, false, ['encrypt'])
  28      .then(ck => crypto.subtle.encrypt({ name: 'AES-CBC', iv: v }, ck, pt))
  29      .then(buf => fn(u8ToSlice(new Uint8Array(buf))));
  30  }
  31  
  32  export function AESCBCDecrypt(key, iv, ciphertext, fn) {
  33    const k = sliceToU8(key), v = sliceToU8(iv), ct = sliceToU8(ciphertext);
  34    crypto.subtle.importKey('raw', k, { name: 'AES-CBC' }, false, ['decrypt'])
  35      .then(ck => crypto.subtle.decrypt({ name: 'AES-CBC', iv: v }, ck, ct))
  36      .then(buf => fn(u8ToSlice(new Uint8Array(buf))));
  37  }
  38