@shgysk8zer0/aes-gcm
Version:
A JWK-base crypto library using AES-GCM secret keys
3 lines (2 loc) • 10.2 kB
JavaScript
const e=new TextDecoder,t=new TextEncoder,r="AES-CTR",a="AES-GCM",n="AES-CBC",o="AES-KW",i=12,s=16,u=a,c=12,y=256,p="deriveKey",f="deriveBits",l=["encrypt","decrypt"],w=["wrapKey","unwrapKey"],g=[p,f],h="SHA-256",d="SHA-384",m="SHA-512",b=h,A="buffer",T="base64",E="base64url",U="ui8",B="hex",v="text",x=U,K=".enc",S=1,k=128,C=16,I="X-ENC-IV";function $(t,r){if(t instanceof ArrayBuffer)return $(new Uint8Array(t),r);switch(r){case A:return t.buffer;case U:return t;case B:return t.toHex();case T:return t.toBase64({alphabet:T});case E:return t.toBase64({alphabet:E});case v:return e.decode(t);default:throw new TypeError(`Invalid output: ${r}.`)}}function V(e,r){switch(r){case B:return Uint8Array.fromHex(e);case T:return Uint8Array.fromBase64(e,{alphabet:T});case E:return Uint8Array.fromBase64(e,{alphabet:E});case v:return t.encode(e);default:throw new TypeError(`Unspupported input format: ${r}.`)}}function R(e){if(!(e instanceof CryptoKey))throw new TypeError("Key must be a `CryptoKey.");switch(e.algorithm.name){case a:return 12;case n:return 16;default:throw new TypeError(`Unsupported key algorithm: ${e.algorithm.name}.`)}}function F(e){return crypto.getRandomValues(new Uint8Array(R(e)))}async function H({name:e=a,length:t=256,extractable:r=!0,usages:n=l}={}){return await crypto.subtle.generateKey({name:e,length:t},r,n)}async function N({extractable:e=!0}={}){return await H({name:o,extractable:e,usages:w})}async function j(e,{name:r=a,length:n=256,hash:o=h,iterations:i=1e5,extractable:s=!1,usages:u=l,salt:c}={}){if("string"!=typeof e||0===e.length)throw new TypeError("Key password must be a non-empty string.");if("string"==typeof c)return await j(e,{name:r,length:n,hash:_,iterations:i,extractable:s,usages:u,salt:Uint8Array.fromBase64(c)});if(c instanceof ArrayBuffer||ArrayBuffer.isView(c)){const a=t.encode(e),y=await crypto.subtle.importKey("raw",a,{name:"PBKDF2"},!1,[p]);return await crypto.subtle.deriveKey({name:"PBKDF2",salt:c,iterations:i,hash:o},y,{name:r,length:n},s,u)}return await j(e,{name:r,length:n,hash:o,iterations:i,extractable:s,usages:u,salt:await _(t.encode(`${r}:${o}:${e}`),h)})}async function q(e,{extractable:t=!1}={}){return await j(e,{name:o,extractable:t,usages:w})}async function J(t="SECRET_KEY"){const[r,a]=process.env[t].split(":"),n=Uint8Array.fromBase64(a),o=JSON.parse(e.decode(n));return await crypto.subtle.importKey("jwk",o,{name:r},o.ext,o.key_ops)}async function M(e,r,{iv:a,output:n=x}={}){if(e instanceof CryptoKey&&e.usages.includes("encrypt")){if(void 0===a)return await M(e,r,{iv:F(e),output:n});if(a instanceof Uint8Array){if("string"==typeof r)return await M(e,t.encode(r),{iv:a,output:n});if(r instanceof Blob)return await M(e,await r.arrayBuffer(),{iv:a,output:n});if(r instanceof ArrayBuffer||ArrayBuffer.isView(r)){const t=new Uint8Array(await crypto.subtle.encrypt({name:e.algorithm.name,iv:a},e,r)),o=new Uint8Array(a.length+t.length);return o.set(a,0),o.set(t,a.length),$(o,n)}throw new TypeError("Unsupported type/class to encrypt.")}throw new TypeError("Invalid IV.")}throw new TypeError("Invalid key.")}class O extends TransformStream{constructor(e,t){if(!(e instanceof CryptoKey&&e.usages.includes("encrypt")))throw new TypeError("Invalid key.");if(void 0===t)t=F(e);else if(!(t instanceof Uint8Array))throw new TypeError("Invalid IV.");super({async transform(r,a){try{const n=await crypto.subtle.encrypt({name:e.algorithm.name,iv:t},e,r);a.enqueue(new Uint8Array(n))}catch(e){a.error(e),a.terminate()}}})}}class D extends TransformStream{constructor(e,t){if(!(e instanceof CryptoKey&&e.usages.includes("decrypt")))throw new TypeError("Invalid key.");if(!(t instanceof Uint8Array))throw new TypeError("Invalid IV.");super({async transform(r,a){try{const n=await crypto.subtle.decrypt({name:e.algorithm.name,iv:t},e,r);a.enqueue(new Uint8Array(n))}catch(e){a.error(e),a.terminate()}}})}}function W(e,t,r,{signal:a}={}){if(e instanceof CryptoKey&&e.usages.includes("encrypt")){if(r instanceof Response){if(t instanceof Uint8Array||0===t.length){if(a instanceof AbortSignal&&a.aborted)throw a.reason;{const n=new Headers(r.headers),o=r.body.pipeThrough(new O(e,t),{signal:a});return n.set(I,t.toBase64({alphabet:"base64"})),new Response(o,{status:r.status,statusText:r.statusText,headers:n})}}throw new TypeError("IV must be a non-empty `Uint8Array`.")}throw new TypeError("Not a `Response`.")}throw new TypeError("Key is not a valid encryption key.")}function L(e,t,{signal:r}={}){if(e instanceof CryptoKey&&e.usages.includes("decrypt")){if(t instanceof Response){if(t.headers.has(I)){if(r instanceof AbortSignal&&r.aborted)throw r.reason;{const a=Uint8Array.fromBase64(t.headers.get(I),{alphabet:"base64"}),n=t.body.pipeThrough(new D(e,a),{signal:r}),o=new Headers(t.headers);return o.delete(I),new Response(n,{status:t.status,statusText:t.statusText,headers:o})}}throw new TypeError("Response is missing required IV header.")}throw new TypeError("Not a `Response`.")}throw new TypeError("Key is not a valid decryption key.")}async function P(e,t,{input:r=T,output:a=A}={}){if(e instanceof CryptoKey&&e.usages.includes("decrypt")){if("string"==typeof t)return $(await P(e,V(t,r)),a);if(t instanceof Blob)return await P(e,await t.arrayBuffer(),{output:a});if(t instanceof ArrayBuffer||ArrayBuffer.isView(t)){const r=R(e),n=t.slice(0,r),o=t.slice(r),i=await crypto.subtle.decrypt({...e.algorithm,iv:n},e,o);return a===A?i:$(new Uint8Array(i),a)}throw new TypeError("Unsupported type/class to decrypt.")}throw new TypeError("Invalid key.")}async function _(e,{algo:r=b,output:a=A}={}){if("string"==typeof e)return await _(t.encode(e),{algo:r,output:a});if(e instanceof Blob)return await _(await e.arrayBuffer(),{algo:r,output:a});if(e instanceof ArrayBuffer||ArrayBuffer.isView(e)){const t=await crypto.subtle.digest(r,e);return a===A?t:$(new Uint8Array(t),a)}throw new TypeError("Unsupported type/class to hash.")}async function G(e,t,{algo:r=b,iv:a,output:n=x}={}){const o=await _(t,{algo:r,output:A});return await M(e,o,{iv:a,output:n})}async function X(e,t,{algo:r=b,input:a=B}={}){if("string"==typeof t)return await X(e,V(t,a).buffer,{algo:r});if(t instanceof Uint8Array)return await X(e,t.buffer,{algo:r});return function(e,t){const r=new Uint8Array(e),a=new Uint8Array(t),n=Math.max(r.length,a.length);let o=r.length!==a.length?1:0;for(let e=0;e<n;e++)o|=(e<r.length?r[e]:0)^(e<a.length?a[e]:0);return 0===o}(await _(e,{algo:r,output:A}),t)}async function Y(e,t,r,{algo:a=b,input:n=B}={}){const o=await P(e,r,{output:U,input:n});return await X(t,o,{algo:a,input:A})}async function z(e,r,{name:a,metadata:n=null,iv:o}={}){if(void 0===o)return await z(e,r,{name:a,metadata:n,iv:F(e)});if(r instanceof File){const i=new Uint8Array(k),s=`${e.algorithm.name.toLowerCase()}-${e.algorithm.length} 1`.padEnd(16," "),u=t.encode(s);i.set(u,0),i.set([o.length],u.length),i.set(o,u.length+1),i.set(t.encode(JSON.stringify(n)),u.length+o.length+1);const c=t.encode(`${r.name},${r.type},${r.lastModified.toString()}`),y=await r.bytes(),p=new Uint8Array(c.length+y.length+1);p.set([c.length],0),p.set(c,1),p.set(y,c.length+1);const f=new Uint8Array(await crypto.subtle.encrypt({...e.algorithm,iv:o},e,p)),l=new Uint8Array(i.length+f.length);return l.set(i,0),l.set(f,i.length),new File([l],a??`${r.name}${K}`,{type:`application/x-${e.algorithm.name.toLowerCase()}-${e.algorithm.length}+encrypted`})}throw new TypeError("encryptFile requires a File object.")}async function Q(t,r){if(r instanceof Blob){const a=await r.bytes(),n=a.subarray(0,k),o=a.subarray(k),i=n.subarray(17,17+n[16]),s=new Uint8Array(await crypto.subtle.decrypt({...t.algorithm,iv:i},t,o)),u=e.decode(s.subarray(1,s[0]+1)),[c,y,p]=u.split(",");return new File([s.subarray(u.length+1)],c,{type:y,lastModified:parseInt(p)})}throw new TypeError("decryptFile requires a File or Blob object.")}async function Z(e,t,{format:r="jwk",wrapAlgo:a={name:o},output:n=A}={}){const i=await crypto.subtle.wrapKey(r,t,e,a);return n!==A?$(i,n):i}async function ee(e,r,{format:a="jwk",output:n=T}={}){const o=await Z(e,r,{format:a,wrapAlgo:e.algorithm,output:U}),i=t.encode(JSON.stringify({format:a,wrapAlgo:Z.algorithm,usages:r.usages,keyAlgo:r.algorithm})),s=new Uint8Array(o.length+i.length+1);switch(s.set([i.length],0,1),s.set(i,1,i.length+1),s.set(o,i.length+1),n){case U:return s;case A:return s.buffer;default:return $(s,n)}}async function te(e,t,{format:r="jwk",unwrapAlgo:n={name:"AES-KW"},unwrappedKeyAlgo:o={name:a},extractable:i=!0,usages:s=l,input:u=T}={}){if("string"==typeof t)return await te(e,$(t,u).buffer,{format:r,unwrapAlgo:n,unwrappedKeyAlgo:o,extractable:i,usages:s});if(t instanceof ArrayBuffer||ArrayBuffer.isView(t))return await crypto.subtle.unwrapKey(r,t,e,n,o,i,s);throw new TypeError("Invalid wrapped key data.")}async function re(t,r,{input:a=T,extractable:n=!0}={}){if("string"==typeof r)return await re(t,V(r,a),{extractable:n});if(r instanceof ArrayBuffer)return await re(t,new Uint8Array(r),{extractable:n});if(r instanceof Uint8Array){const a=r[0],{format:o,wrapAlgo:i,usages:s,keyAlgo:u}=JSON.parse(e.decode(r.slice(1,a+1))),c=r.slice(a+1);return await te(t,c,{format:o,unwrapAlgo:i,unwrappedKeyAlgo:u,usages:s,extractable:n})}throw new TypeError("Wrapped key data must be an encoded string, a `Uint8Array`, or an `ArrayBuffer`.")}export{n as AES_CBC,s as AES_CBC_LENGTH,r as AES_CTR,a as AES_GCM,i as AES_GCM_LENGTH,o as AES_KW,T as BASE64,E as BASE64_URL,A as BUFFER,b as DEFAULT_ALGO,u as DEFAULT_ALGO_NAME,c as DEFAULT_IV_LENGTH,y as DEFAULT_KEY_LENGTH,x as DEFAULT_OUTPUT,f as DERIVE_BITS,p as DERIVE_KEY,g as DERIVE_USAGES,D as DecryptionStream,l as ENCRYPT_USAGES,O as EncryptionStream,K as FILE_EXT,S as FILE_VERSION,k as HEADER_SIZE,B as HEX,I as IV_HEADER,C as MAGIC_STR_LEN,h as SHA256,d as SHA384,m as SHA512,v as TEXT,U as UI8_ARR,w as WRAP_USAGES,j as createSecretKeyFromPassword,q as createWrappingKeyFromPassword,P as decrypt,Q as decryptFile,L as decryptResponse,M as encrypt,z as encryptFile,W as encryptResponse,F as generateIV,H as generateSecretKey,N as generateWrappingKey,J as getSecretKey,_ as hash,G as sign,re as unwrapAndDecodeKey,te as unwrapKey,X as verify,Y as verifySignature,ee as wrapAndEncodeKey,Z as wrapKey};
//# sourceMappingURL=aes-gcm.min.js.map