@gjsify/webcrypto 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/aes-kw.js +1 -0
- package/lib/esm/subtle.js +1 -1
- package/lib/types/aes-kw.d.ts +12 -0
- package/lib/types/crypto-key.d.ts +2 -0
- package/lib/types/subtle.d.ts +17 -2
- package/package.json +5 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";const e=Uint8Array.of(166,166,166,166,166,166,166,166);function xorCounter(e,t){for(let n=0;n<8&&t>0;n++)e[7-n]^=t&255,t=Math.floor(t/256)}function aesKeyWrap(t,n){if(t.length<16||t.length%8!=0)throw new DOMException(`AES-KW: key data must be a multiple of 8 bytes and at least 16 bytes`,`OperationError`);let r=t.length/8,i=e.slice(),a=[];for(let e=0;e<r;e++)a.push(t.slice(e*8,e*8+8));let o=new Uint8Array(16);for(let e=0;e<=5;e++)for(let t=1;t<=r;t++){o.set(i,0),o.set(a[t-1],8);let s=n(o);i.set(s.subarray(0,8)),xorCounter(i,r*e+t),a[t-1]=s.slice(8,16)}let s=new Uint8Array((r+1)*8);s.set(i,0);for(let e=0;e<r;e++)s.set(a[e],(e+1)*8);return s}function aesKeyUnwrap(t,n){if(t.length<24||t.length%8!=0)throw new DOMException(`AES-KW: wrapped key must be a multiple of 8 bytes and at least 24 bytes`,`OperationError`);let r=t.length/8-1,i=t.slice(0,8),a=[];for(let e=0;e<r;e++)a.push(t.slice((e+1)*8,(e+2)*8));let o=new Uint8Array(16);for(let e=5;e>=0;e--)for(let t=r;t>=1;t--){xorCounter(i,r*e+t),o.set(i,0),o.set(a[t-1],8);let s=n(o);i.set(s.subarray(0,8)),a[t-1]=s.slice(8,16)}let s=!0;for(let t=0;t<8;t++)i[t]!==e[t]&&(s=!1);if(!s)throw new DOMException(`AES-KW: integrity check failed`,`OperationError`);let c=new Uint8Array(r*8);for(let e=0;e<r;e++)c.set(a[e],e*8);return c}export{aesKeyUnwrap,aesKeyWrap};
|
package/lib/esm/subtle.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{CryptoKey as e}from"./crypto-key.js";import{base64urlDecode as t,base64urlEncode as n,checkUsage as r,hashSize as i,normalizeAlgorithm as a,toNodeCurveName as o,toNodeHashName as s,toUint8Array as c,validateUsages as l}from"./util.js";let u=!1,d,f,p,m,h,g,_,v,y,b,x,S,C,w,T,E;async function loadCrypto(){if(u)return;let e=await import(`node:crypto`);d=e.createHash,f=e.createHmac,p=e.createCipheriv,m=e.createDecipheriv,h=e.createSign,g=e.createVerify,_=e.pbkdf2Sync,v=e.hkdfSync,y=e.createECDH,b=e.randomBytes,e.publicEncrypt,e.privateDecrypt,e.createPublicKey,e.createPrivateKey,x=e.ecdsaSign,S=e.ecdsaVerify,C=e.rsaPssSign,w=e.rsaPssVerify,T=e.rsaOaepEncrypt,E=e.rsaOaepDecrypt,u=!0}const D=loadCrypto();var SubtleCrypto=class{async digest(e,t){await D;let n=s(a(e).name),r=c(t),i=d(n);i.update(r);let o=i.digest();return o.buffer.slice(o.byteOffset,o.byteOffset+o.byteLength)}async generateKey(t,n,r){await D;let s=a(t);switch(s.name.toUpperCase()){case`AES-CBC`:case`AES-CTR`:case`AES-GCM`:{let i=t.length;if(![128,192,256].includes(i))throw new DOMException(`Invalid AES key length: ${i}`,`OperationError`);l(r,[`encrypt`,`decrypt`,`wrapKey`,`unwrapKey`]);let a=b(i/8);return new e(`secret`,n,{name:s.name,length:i},r,new Uint8Array(a))}case`HMAC`:{let o=t,s=a(o.hash),c=o.length||i(s.name)*8;l(r,[`sign`,`verify`]);let u=b(Math.ceil(c/8));return new e(`secret`,n,{name:`HMAC`,hash:{name:s.name},length:c},r,new Uint8Array(u))}case`ECDH`:{let i=t.namedCurve,a=o(i);l(r,[`deriveKey`,`deriveBits`]);let s=y(a);s.generateKeys();let c=new Uint8Array(s.getPublicKey()),u=new Uint8Array(s.getPrivateKey());return{publicKey:new e(`public`,!0,{name:`ECDH`,namedCurve:i},[],c),privateKey:new e(`private`,n,{name:`ECDH`,namedCurve:i},r,{pub:c,priv:u})}}case`ECDSA`:{let i=t.namedCurve,a=o(i);l(r,[`sign`,`verify`]);let s=y(a);s.generateKeys();let c=new Uint8Array(s.getPublicKey()),u=new Uint8Array(s.getPrivateKey());return{publicKey:new e(`public`,!0,{name:`ECDSA`,namedCurve:i},[`verify`],c),privateKey:new e(`private`,n,{name:`ECDSA`,namedCurve:i},[`sign`],{pub:c,priv:u})}}default:throw new DOMException(`Unsupported algorithm: ${s.name}`,`NotSupportedError`)}}async importKey(n,r,i,o,s){await D;let u=a(i),d=u.name.toUpperCase();switch(d){case`AES-CBC`:case`AES-CTR`:case`AES-GCM`:if(n===`raw`){let t=c(r);if(![16,24,32].includes(t.length))throw new DOMException(`Invalid AES key length: ${t.length*8}`,`DataError`);return l(s,[`encrypt`,`decrypt`,`wrapKey`,`unwrapKey`]),new e(`secret`,o,{name:u.name,length:t.length*8},s,new Uint8Array(t))}if(n===`jwk`){let n=r;if(n.kty!==`oct`)throw new DOMException(`JWK kty must be "oct"`,`DataError`);let i=t(n.k);if(![16,24,32].includes(i.length))throw new DOMException(`Invalid AES key length: ${i.length*8}`,`DataError`);return l(s,[`encrypt`,`decrypt`,`wrapKey`,`unwrapKey`]),new e(`secret`,o,{name:u.name,length:i.length*8},s,i)}throw new DOMException(`Unsupported format: ${n}`,`NotSupportedError`);case`HMAC`:{let u=a(i.hash);if(n===`raw`){let t=c(r);return l(s,[`sign`,`verify`]),new e(`secret`,o,{name:`HMAC`,hash:{name:u.name},length:t.length*8},s,new Uint8Array(t))}if(n===`jwk`){let n=r;if(n.kty!==`oct`)throw new DOMException(`JWK kty must be "oct"`,`DataError`);let i=t(n.k);return l(s,[`sign`,`verify`]),new e(`secret`,o,{name:`HMAC`,hash:{name:u.name},length:i.length*8},s,i)}throw new DOMException(`Unsupported format: ${n}`,`NotSupportedError`)}case`PBKDF2`:if(n===`raw`){let t=c(r);return l(s,[`deriveKey`,`deriveBits`]),new e(`secret`,!1,{name:`PBKDF2`},s,new Uint8Array(t))}throw new DOMException(`Unsupported format: ${n}`,`NotSupportedError`);case`HKDF`:if(n===`raw`){let t=c(r);return l(s,[`deriveKey`,`deriveBits`]),new e(`secret`,!1,{name:`HKDF`},s,new Uint8Array(t))}throw new DOMException(`Unsupported format: ${n}`,`NotSupportedError`);case`ECDH`:case`ECDSA`:{let a=i.namedCurve;if(n===`raw`){let t=c(r);return d===`ECDH`?s.length>0&&l(s,[`deriveKey`,`deriveBits`]):l(s,[`verify`]),new e(`public`,o,{name:u.name,namedCurve:a},s,new Uint8Array(t))}if(n===`jwk`){let n=r;if(n.kty!==`EC`)throw new DOMException(`JWK kty must be "EC"`,`DataError`);if(n.d){let r=t(n.d),i=t(n.x),c=t(n.y),f=new Uint8Array(1+i.length+c.length);return f[0]=4,f.set(i,1),f.set(c,1+i.length),l(s,d===`ECDH`?[`deriveKey`,`deriveBits`]:[`sign`]),new e(`private`,o,{name:u.name,namedCurve:a},s,{pub:f,priv:r})}else{let r=t(n.x),i=t(n.y),c=new Uint8Array(1+r.length+i.length);return c[0]=4,c.set(r,1),c.set(i,1+r.length),d===`ECDH`?s.length>0&&l(s,[`deriveKey`,`deriveBits`]):l(s,[`verify`]),new e(`public`,o,{name:u.name,namedCurve:a},s,c)}}throw new DOMException(`Unsupported format: ${n}`,`NotSupportedError`)}default:throw new DOMException(`Unsupported algorithm: ${u.name}`,`NotSupportedError`)}}async exportKey(e,t){if(!t.extractable)throw new DOMException(`Key is not extractable`,`InvalidAccessError`);let r=t.algorithm.name.toUpperCase();if(e===`raw`){if(t.type===`secret`){let e=t._handle;return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}if(t.type===`public`&&(r===`ECDH`||r===`ECDSA`)){let e=t._handle;return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}throw new DOMException(`Cannot export in raw format`,`InvalidAccessError`)}if(e===`jwk`){if(t.type===`secret`){let e=t._handle,i={kty:`oct`,k:n(e),ext:t.extractable,key_ops:[...t.usages]};return r.startsWith(`AES-`)?i.alg=`A${t.algorithm.length}${r.replace(`AES-`,``)}`:r===`HMAC`&&(i.alg=`HS${t.algorithm.hash.name.replace(`SHA-`,``)}`),i}if((r===`ECDH`||r===`ECDSA`)&&(t.type===`public`||t.type===`private`)){let e=t.algorithm.namedCurve,r;r=t.type===`public`?t._handle:t._handle.pub;let i=(r.length-1)/2,a=r.slice(1,1+i),o=r.slice(1+i),s={kty:`EC`,crv:e,x:n(a),y:n(o),ext:t.extractable,key_ops:[...t.usages]};return t.type===`private`&&(s.d=n(t._handle.priv)),s}throw new DOMException(`JWK export not supported for ${r} ${t.type}`,`NotSupportedError`)}throw new DOMException(`Unsupported export format: ${e}`,`NotSupportedError`)}async encrypt(e,t,n){await D,r(t,`encrypt`);let i=a(e),o=i.name.toUpperCase(),l=c(n);switch(o){case`AES-CBC`:{let n=c(e.iv),r=t._handle,i=r.length*8,a=p(`aes-${i}-cbc`,r,n),o=a.update(l),s=a.final(),u=new Uint8Array(o.length+s.length);return u.set(new Uint8Array(o),0),u.set(new Uint8Array(s),o.length),u.buffer}case`AES-CTR`:{let n=c(e.counter),r=t._handle,i=r.length*8,a=p(`aes-${i}-ctr`,r,n),o=a.update(l),s=a.final(),u=new Uint8Array(o.length+s.length);return u.set(new Uint8Array(o),0),u.set(new Uint8Array(s),o.length),u.buffer}case`AES-GCM`:{let n=e,r=c(n.iv),i=n.additionalData?c(n.additionalData):void 0,a=t._handle,o=a.length*8,s=p(`aes-${o}-gcm`,a,r);i&&s.setAAD(i);let u=s.update(l),d=s.final(),f=s.getAuthTag(),m=new Uint8Array(u.length+d.length+f.length);return m.set(new Uint8Array(u),0),m.set(new Uint8Array(d),u.length),m.set(new Uint8Array(f),u.length+d.length),m.buffer}case`RSA-OAEP`:{let n=t.algorithm.hash.name,r=s(n),i=t._handle,a=e,o=a.label?c(a.label):void 0,u=T(r,i.pem,l,o);return u.buffer.slice(u.byteOffset,u.byteOffset+u.byteLength)}default:throw new DOMException(`Unsupported algorithm: ${i.name}`,`NotSupportedError`)}}async decrypt(e,t,n){await D,r(t,`decrypt`);let i=a(e),o=i.name.toUpperCase(),l=c(n);switch(o){case`AES-CBC`:{let n=c(e.iv),r=t._handle,i=r.length*8,a=m(`aes-${i}-cbc`,r,n),o=a.update(l),s=a.final(),u=new Uint8Array(o.length+s.length);return u.set(new Uint8Array(o),0),u.set(new Uint8Array(s),o.length),u.buffer}case`AES-CTR`:{let n=c(e.counter),r=t._handle,i=r.length*8,a=m(`aes-${i}-ctr`,r,n),o=a.update(l),s=a.final(),u=new Uint8Array(o.length+s.length);return u.set(new Uint8Array(o),0),u.set(new Uint8Array(s),o.length),u.buffer}case`AES-GCM`:{let n=e,r=c(n.iv),i=(n.tagLength||128)/8,a=n.additionalData?c(n.additionalData):void 0,o=t._handle,s=o.length*8,u=l.slice(0,l.length-i),d=l.slice(l.length-i),f=m(`aes-${s}-gcm`,o,r);f.setAuthTag(d),a&&f.setAAD(a);let p=f.update(u),h=f.final(),g=new Uint8Array(p.length+h.length);return g.set(new Uint8Array(p),0),g.set(new Uint8Array(h),p.length),g.buffer}case`RSA-OAEP`:{let n=t.algorithm.hash.name,r=s(n),i=t._handle,a=e,o=a.label?c(a.label):void 0,u=E(r,i.pem,l,o);return u.buffer.slice(u.byteOffset,u.byteOffset+u.byteLength)}default:throw new DOMException(`Unsupported algorithm: ${i.name}`,`NotSupportedError`)}}async sign(e,t,n){await D,r(t,`sign`);let o=a(e),l=o.name.toUpperCase(),u=c(n);switch(l){case`HMAC`:{let e=t.algorithm.hash.name,n=s(e),r=t._handle,i=f(n,r);i.update(u);let a=i.digest();return a.buffer.slice(a.byteOffset,a.byteOffset+a.byteLength)}case`RSASSA-PKCS1-V1_5`:{let e=t.algorithm.hash.name,n=s(e),r=t._handle,i=h(n);i.update(u);let a=i.sign(r.pem);return a.buffer.slice(a.byteOffset,a.byteOffset+a.byteLength)}case`ECDSA`:{let n=e,r=s(typeof n.hash==`string`?n.hash:n.hash.name),i=t.algorithm.namedCurve,a=t._handle,o=x(r,a.priv,u,i);return o.buffer.slice(o.byteOffset,o.byteOffset+o.byteLength)}case`RSA-PSS`:{let n=t.algorithm.hash.name,r=s(n),a=t._handle,o=e.saltLength??i(n),c=C(r,a.pem,u,o);return c.buffer.slice(c.byteOffset,c.byteOffset+c.byteLength)}default:throw new DOMException(`Unsupported algorithm: ${o.name}`,`NotSupportedError`)}}async verify(e,t,n,o){await D,r(t,`verify`);let l=a(e),u=l.name.toUpperCase(),d=c(o),p=c(n);switch(u){case`HMAC`:{let e=t.algorithm.hash.name,n=s(e),r=t._handle,i=f(n,r);i.update(d);let a=new Uint8Array(i.digest());if(a.length!==p.length)return!1;let o=0;for(let e=0;e<a.length;e++)o|=a[e]^p[e];return o===0}case`RSASSA-PKCS1-V1_5`:{let e=t.algorithm.hash.name,n=s(e),r=t._handle,i=g(n);return i.update(d),i.verify(r.pem,p)}case`ECDSA`:{let n=e,r=s(typeof n.hash==`string`?n.hash:n.hash.name),i=t.algorithm.namedCurve,a=t._handle;return S(r,a,p,d,i)}case`RSA-PSS`:{let n=t.algorithm.hash.name,r=s(n),a=t._handle,o=e.saltLength??i(n);return w(r,a.pem,p,d,o)}default:throw new DOMException(`Unsupported algorithm: ${l.name}`,`NotSupportedError`)}}async _deriveBitsInternal(e,t,n){await D;let r=a(e);switch(r.name.toUpperCase()){case`PBKDF2`:{let r=e,i=s(a(r.hash).name),o=c(r.salt),l=r.iterations,u=t._handle,d=_(u,o,l,n/8,i);return d.buffer.slice(d.byteOffset,d.byteOffset+d.byteLength)}case`HKDF`:{let r=e,i=s(a(r.hash).name),o=c(r.salt),l=c(r.info),u=t._handle;return v(i,u,o,l,n/8)}case`ECDH`:{let r=e.public,i=t.algorithm.namedCurve,a=o(i),s=y(a),c=t._handle;s.setPrivateKey(c.priv);let l=r._handle instanceof Uint8Array?r._handle:r._handle.pub,u=s.computeSecret(l),d=new Uint8Array(u);return n?d.buffer.slice(0,n/8):d.buffer.slice(d.byteOffset,d.byteOffset+d.byteLength)}default:throw new DOMException(`Unsupported algorithm: ${r.name}`,`NotSupportedError`)}}async deriveBits(e,t,n){return r(t,`deriveBits`),this._deriveBitsInternal(e,t,n)}async deriveKey(e,t,n,o,s){r(t,`deriveKey`);let c=a(n),l,u=c.name.toUpperCase();if(u===`AES-CBC`||u===`AES-CTR`||u===`AES-GCM`)l=n.length;else if(u===`HMAC`){let e=n,t=a(e.hash);l=e.length||i(t.name)*8}else throw new DOMException(`Unsupported derived key algorithm: ${c.name}`,`NotSupportedError`);let d=await this._deriveBitsInternal(e,t,l);return this.importKey(`raw`,d,n,o,s)}async wrapKey(e,t,n,r){throw new DOMException(`wrapKey not yet implemented`,`NotSupportedError`)}async unwrapKey(e,t,n,r,i,a,o){throw new DOMException(`unwrapKey not yet implemented`,`NotSupportedError`)}};export{SubtleCrypto};
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{aesKeyUnwrap as e,aesKeyWrap as t}from"./aes-kw.js";import{CryptoKey as n}from"./crypto-key.js";import{base64urlDecode as r,base64urlEncode as i,checkUsage as a,hashSize as o,normalizeAlgorithm as s,toNodeCurveName as c,toNodeHashName as l,toUint8Array as u,validateUsages as d}from"./util.js";let f=!1,p,m,h,g,_,v,y,b,x,S,C,w,T,E,D,O;async function loadCrypto(){if(f)return;let e=await import(`node:crypto`);p=e.createHash,m=e.createHmac,h=e.createCipheriv,g=e.createDecipheriv,_=e.createSign,v=e.createVerify,y=e.pbkdf2Sync,b=e.hkdfSync,x=e.createECDH,S=e.randomBytes,e.publicEncrypt,e.privateDecrypt,e.createPublicKey,e.createPrivateKey,C=e.ecdsaSign,w=e.ecdsaVerify,T=e.rsaPssSign,E=e.rsaPssVerify,D=e.rsaOaepEncrypt,O=e.rsaOaepDecrypt,f=!0}const k=loadCrypto();var SubtleCrypto=class{async digest(e,t){await k;let n=l(s(e).name),r=u(t),i=p(n);i.update(r);let a=i.digest();return a.buffer.slice(a.byteOffset,a.byteOffset+a.byteLength)}async generateKey(e,t,r){await k;let i=s(e);switch(i.name.toUpperCase()){case`AES-CBC`:case`AES-CTR`:case`AES-GCM`:{let a=e.length;if(![128,192,256].includes(a))throw new DOMException(`Invalid AES key length: ${a}`,`OperationError`);d(r,[`encrypt`,`decrypt`,`wrapKey`,`unwrapKey`]);let o=S(a/8);return new n(`secret`,t,{name:i.name,length:a},r,new Uint8Array(o))}case`AES-KW`:{let i=e.length;if(![128,192,256].includes(i))throw new DOMException(`Invalid AES key length: ${i}`,`OperationError`);d(r,[`wrapKey`,`unwrapKey`]);let a=S(i/8);return new n(`secret`,t,{name:`AES-KW`,length:i},r,new Uint8Array(a))}case`HMAC`:{let i=e,a=s(i.hash),c=i.length||o(a.name)*8;d(r,[`sign`,`verify`]);let l=S(Math.ceil(c/8));return new n(`secret`,t,{name:`HMAC`,hash:{name:a.name},length:c},r,new Uint8Array(l))}case`ECDH`:{let i=e.namedCurve,a=c(i);d(r,[`deriveKey`,`deriveBits`]);let o=x(a);o.generateKeys();let s=new Uint8Array(o.getPublicKey()),l=new Uint8Array(o.getPrivateKey());return{publicKey:new n(`public`,!0,{name:`ECDH`,namedCurve:i},[],s),privateKey:new n(`private`,t,{name:`ECDH`,namedCurve:i},r,{pub:s,priv:l})}}case`ECDSA`:{let i=e.namedCurve,a=c(i);d(r,[`sign`,`verify`]);let o=x(a);o.generateKeys();let s=new Uint8Array(o.getPublicKey()),l=new Uint8Array(o.getPrivateKey());return{publicKey:new n(`public`,!0,{name:`ECDSA`,namedCurve:i},[`verify`],s),privateKey:new n(`private`,t,{name:`ECDSA`,namedCurve:i},[`sign`],{pub:s,priv:l})}}default:throw new DOMException(`Unsupported algorithm: ${i.name}`,`NotSupportedError`)}}async importKey(e,t,i,a,o){await k;let c=s(i),l=c.name.toUpperCase();switch(l){case`AES-CBC`:case`AES-CTR`:case`AES-GCM`:if(e===`raw`){let e=u(t);if(![16,24,32].includes(e.length))throw new DOMException(`Invalid AES key length: ${e.length*8}`,`DataError`);return d(o,[`encrypt`,`decrypt`,`wrapKey`,`unwrapKey`]),new n(`secret`,a,{name:c.name,length:e.length*8},o,new Uint8Array(e))}if(e===`jwk`){let e=t;if(e.kty!==`oct`)throw new DOMException(`JWK kty must be "oct"`,`DataError`);let i=r(e.k);if(![16,24,32].includes(i.length))throw new DOMException(`Invalid AES key length: ${i.length*8}`,`DataError`);return d(o,[`encrypt`,`decrypt`,`wrapKey`,`unwrapKey`]),new n(`secret`,a,{name:c.name,length:i.length*8},o,i)}throw new DOMException(`Unsupported format: ${e}`,`NotSupportedError`);case`AES-KW`:{let i;if(e===`raw`)i=u(t);else if(e===`jwk`){let e=t;if(e.kty!==`oct`)throw new DOMException(`JWK kty must be "oct"`,`DataError`);i=r(e.k)}else throw new DOMException(`Unsupported format: ${e}`,`NotSupportedError`);if(![16,24,32].includes(i.length))throw new DOMException(`Invalid AES key length: ${i.length*8}`,`DataError`);return d(o,[`wrapKey`,`unwrapKey`]),new n(`secret`,a,{name:`AES-KW`,length:i.length*8},o,new Uint8Array(i))}case`HMAC`:{let c=s(i.hash);if(e===`raw`){let e=u(t);return d(o,[`sign`,`verify`]),new n(`secret`,a,{name:`HMAC`,hash:{name:c.name},length:e.length*8},o,new Uint8Array(e))}if(e===`jwk`){let e=t;if(e.kty!==`oct`)throw new DOMException(`JWK kty must be "oct"`,`DataError`);let i=r(e.k);return d(o,[`sign`,`verify`]),new n(`secret`,a,{name:`HMAC`,hash:{name:c.name},length:i.length*8},o,i)}throw new DOMException(`Unsupported format: ${e}`,`NotSupportedError`)}case`PBKDF2`:if(e===`raw`){let e=u(t);return d(o,[`deriveKey`,`deriveBits`]),new n(`secret`,!1,{name:`PBKDF2`},o,new Uint8Array(e))}throw new DOMException(`Unsupported format: ${e}`,`NotSupportedError`);case`HKDF`:if(e===`raw`){let e=u(t);return d(o,[`deriveKey`,`deriveBits`]),new n(`secret`,!1,{name:`HKDF`},o,new Uint8Array(e))}throw new DOMException(`Unsupported format: ${e}`,`NotSupportedError`);case`ECDH`:case`ECDSA`:{let s=i.namedCurve;if(e===`raw`){let e=u(t);return l===`ECDH`?o.length>0&&d(o,[`deriveKey`,`deriveBits`]):d(o,[`verify`]),new n(`public`,a,{name:c.name,namedCurve:s},o,new Uint8Array(e))}if(e===`jwk`){let e=t;if(e.kty!==`EC`)throw new DOMException(`JWK kty must be "EC"`,`DataError`);if(e.d){let t=r(e.d),i=r(e.x),u=r(e.y),f=new Uint8Array(1+i.length+u.length);return f[0]=4,f.set(i,1),f.set(u,1+i.length),d(o,l===`ECDH`?[`deriveKey`,`deriveBits`]:[`sign`]),new n(`private`,a,{name:c.name,namedCurve:s},o,{pub:f,priv:t})}else{let t=r(e.x),i=r(e.y),u=new Uint8Array(1+t.length+i.length);return u[0]=4,u.set(t,1),u.set(i,1+t.length),l===`ECDH`?o.length>0&&d(o,[`deriveKey`,`deriveBits`]):d(o,[`verify`]),new n(`public`,a,{name:c.name,namedCurve:s},o,u)}}throw new DOMException(`Unsupported format: ${e}`,`NotSupportedError`)}default:throw new DOMException(`Unsupported algorithm: ${c.name}`,`NotSupportedError`)}}async exportKey(e,t){if(!t.extractable)throw new DOMException(`Key is not extractable`,`InvalidAccessError`);let n=t.algorithm.name.toUpperCase();if(e===`raw`){if(t.type===`secret`){let e=t._handle;return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}if(t.type===`public`&&(n===`ECDH`||n===`ECDSA`)){let e=t._handle;return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}throw new DOMException(`Cannot export in raw format`,`InvalidAccessError`)}if(e===`jwk`){if(t.type===`secret`){let e=t._handle,r={kty:`oct`,k:i(e),ext:t.extractable,key_ops:[...t.usages]};return n.startsWith(`AES-`)?r.alg=`A${t.algorithm.length}${n.replace(`AES-`,``)}`:n===`HMAC`&&(r.alg=`HS${t.algorithm.hash.name.replace(`SHA-`,``)}`),r}if((n===`ECDH`||n===`ECDSA`)&&(t.type===`public`||t.type===`private`)){let e=t.algorithm.namedCurve,n;n=t.type===`public`?t._handle:t._handle.pub;let r=(n.length-1)/2,a=n.slice(1,1+r),o=n.slice(1+r),s={kty:`EC`,crv:e,x:i(a),y:i(o),ext:t.extractable,key_ops:[...t.usages]};return t.type===`private`&&(s.d=i(t._handle.priv)),s}throw new DOMException(`JWK export not supported for ${n} ${t.type}`,`NotSupportedError`)}throw new DOMException(`Unsupported export format: ${e}`,`NotSupportedError`)}async encrypt(e,t,n){return await k,a(t,`encrypt`),this._encryptImpl(e,t,n)}async _encryptImpl(e,n,r){let i=s(e),a=i.name.toUpperCase(),o=u(r);switch(a){case`AES-CBC`:{let t=u(e.iv),r=n._handle,i=r.length*8,a=h(`aes-${i}-cbc`,r,t),s=a.update(o),c=a.final(),l=new Uint8Array(s.length+c.length);return l.set(new Uint8Array(s),0),l.set(new Uint8Array(c),s.length),l.buffer}case`AES-CTR`:{let t=u(e.counter),r=n._handle,i=r.length*8,a=h(`aes-${i}-ctr`,r,t),s=a.update(o),c=a.final(),l=new Uint8Array(s.length+c.length);return l.set(new Uint8Array(s),0),l.set(new Uint8Array(c),s.length),l.buffer}case`AES-GCM`:{let t=e,r=u(t.iv),i=t.additionalData?u(t.additionalData):void 0,a=n._handle,s=a.length*8,c=h(`aes-${s}-gcm`,a,r);i&&c.setAAD(i);let l=c.update(o),d=c.final(),f=c.getAuthTag(),p=new Uint8Array(l.length+d.length+f.length);return p.set(new Uint8Array(l),0),p.set(new Uint8Array(d),l.length),p.set(new Uint8Array(f),l.length+d.length),p.buffer}case`RSA-OAEP`:{let t=n.algorithm.hash.name,r=l(t),i=n._handle,a=e,s=a.label?u(a.label):void 0,c=D(r,i.pem,o,s);return c.buffer.slice(c.byteOffset,c.byteOffset+c.byteLength)}case`AES-KW`:{let e=n._handle;return t(o,t=>this._aesEcbBlock(e,t,!0)).buffer}default:throw new DOMException(`Unsupported algorithm: ${i.name}`,`NotSupportedError`)}}async decrypt(e,t,n){return await k,a(t,`decrypt`),this._decryptImpl(e,t,n)}async _decryptImpl(t,n,r){let i=s(t),a=i.name.toUpperCase(),o=u(r);switch(a){case`AES-CBC`:{let e=u(t.iv),r=n._handle,i=r.length*8,a=g(`aes-${i}-cbc`,r,e),s=a.update(o),c=a.final(),l=new Uint8Array(s.length+c.length);return l.set(new Uint8Array(s),0),l.set(new Uint8Array(c),s.length),l.buffer}case`AES-CTR`:{let e=u(t.counter),r=n._handle,i=r.length*8,a=g(`aes-${i}-ctr`,r,e),s=a.update(o),c=a.final(),l=new Uint8Array(s.length+c.length);return l.set(new Uint8Array(s),0),l.set(new Uint8Array(c),s.length),l.buffer}case`AES-GCM`:{let e=t,r=u(e.iv),i=(e.tagLength||128)/8,a=e.additionalData?u(e.additionalData):void 0,s=n._handle,c=s.length*8,l=o.slice(0,o.length-i),d=o.slice(o.length-i),f=g(`aes-${c}-gcm`,s,r);f.setAuthTag(d),a&&f.setAAD(a);let p=f.update(l),m=f.final(),h=new Uint8Array(p.length+m.length);return h.set(new Uint8Array(p),0),h.set(new Uint8Array(m),p.length),h.buffer}case`RSA-OAEP`:{let e=n.algorithm.hash.name,r=l(e),i=n._handle,a=t,s=a.label?u(a.label):void 0,c=O(r,i.pem,o,s);return c.buffer.slice(c.byteOffset,c.byteOffset+c.byteLength)}case`AES-KW`:{let t=n._handle;return e(o,e=>this._aesEcbBlock(t,e,!1)).buffer}default:throw new DOMException(`Unsupported algorithm: ${i.name}`,`NotSupportedError`)}}_aesEcbBlock(e,t,n){let r=`aes-${e.length*8}-ecb`,i=new Uint8Array,a=n?h(r,e,i):g(r,e,i);a.setAutoPadding?.(!1);let o=a.update(t),s=a.final();if(s.length===0)return o;let c=new Uint8Array(o.length+s.length);return c.set(o,0),c.set(s,o.length),c}async sign(e,t,n){await k,a(t,`sign`);let r=s(e),i=r.name.toUpperCase(),c=u(n);switch(i){case`HMAC`:{let e=t.algorithm.hash.name,n=l(e),r=t._handle,i=m(n,r);i.update(c);let a=i.digest();return a.buffer.slice(a.byteOffset,a.byteOffset+a.byteLength)}case`RSASSA-PKCS1-V1_5`:{let e=t.algorithm.hash.name,n=l(e),r=t._handle,i=_(n);i.update(c);let a=i.sign(r.pem);return a.buffer.slice(a.byteOffset,a.byteOffset+a.byteLength)}case`ECDSA`:{let n=e,r=l(typeof n.hash==`string`?n.hash:n.hash.name),i=t.algorithm.namedCurve,a=t._handle,o=C(r,a.priv,c,i);return o.buffer.slice(o.byteOffset,o.byteOffset+o.byteLength)}case`RSA-PSS`:{let n=t.algorithm.hash.name,r=l(n),i=t._handle,a=e.saltLength??o(n),s=T(r,i.pem,c,a);return s.buffer.slice(s.byteOffset,s.byteOffset+s.byteLength)}default:throw new DOMException(`Unsupported algorithm: ${r.name}`,`NotSupportedError`)}}async verify(e,t,n,r){await k,a(t,`verify`);let i=s(e),c=i.name.toUpperCase(),d=u(r),f=u(n);switch(c){case`HMAC`:{let e=t.algorithm.hash.name,n=l(e),r=t._handle,i=m(n,r);i.update(d);let a=new Uint8Array(i.digest());if(a.length!==f.length)return!1;let o=0;for(let e=0;e<a.length;e++)o|=a[e]^f[e];return o===0}case`RSASSA-PKCS1-V1_5`:{let e=t.algorithm.hash.name,n=l(e),r=t._handle,i=v(n);return i.update(d),i.verify(r.pem,f)}case`ECDSA`:{let n=e,r=l(typeof n.hash==`string`?n.hash:n.hash.name),i=t.algorithm.namedCurve,a=t._handle;return w(r,a,f,d,i)}case`RSA-PSS`:{let n=t.algorithm.hash.name,r=l(n),i=t._handle,a=e.saltLength??o(n);return E(r,i.pem,f,d,a)}default:throw new DOMException(`Unsupported algorithm: ${i.name}`,`NotSupportedError`)}}async _deriveBitsInternal(e,t,n){await k;let r=s(e);switch(r.name.toUpperCase()){case`PBKDF2`:{let r=e,i=l(s(r.hash).name),a=u(r.salt),o=r.iterations,c=t._handle,d=y(c,a,o,n/8,i);return d.buffer.slice(d.byteOffset,d.byteOffset+d.byteLength)}case`HKDF`:{let r=e,i=l(s(r.hash).name),a=u(r.salt),o=u(r.info),c=t._handle;return b(i,c,a,o,n/8)}case`ECDH`:{let r=e.public,i=t.algorithm.namedCurve,a=c(i),o=x(a),s=t._handle;o.setPrivateKey(s.priv);let l=r._handle instanceof Uint8Array?r._handle:r._handle.pub,u=o.computeSecret(l),d=new Uint8Array(u);return n?d.buffer.slice(0,n/8):d.buffer.slice(d.byteOffset,d.byteOffset+d.byteLength)}default:throw new DOMException(`Unsupported algorithm: ${r.name}`,`NotSupportedError`)}}async deriveBits(e,t,n){return a(t,`deriveBits`),this._deriveBitsInternal(e,t,n)}async deriveKey(e,t,n,r,i){a(t,`deriveKey`);let c=s(n),l,u=c.name.toUpperCase();if(u===`AES-CBC`||u===`AES-CTR`||u===`AES-GCM`)l=n.length;else if(u===`HMAC`){let e=n,t=s(e.hash);l=e.length||o(t.name)*8}else throw new DOMException(`Unsupported derived key algorithm: ${c.name}`,`NotSupportedError`);let d=await this._deriveBitsInternal(e,t,l);return this.importKey(`raw`,d,n,r,i)}async wrapKey(e,t,n,r){await k,a(n,`wrapKey`);let i=await this.exportKey(e,t),o=e===`jwk`?new TextEncoder().encode(JSON.stringify(i)):i;return this._encryptImpl(r,n,o)}async unwrapKey(e,t,n,r,i,o,s){await k,a(n,`unwrapKey`);let c=await this._decryptImpl(r,n,t),l=e===`jwk`?JSON.parse(new TextDecoder().decode(new Uint8Array(c))):c;return this.importKey(e,l,i,o,s)}};export{SubtleCrypto};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** A single 16-byte AES-ECB block transform (encrypt or decrypt, no padding). */
|
|
2
|
+
export type AesBlockFn = (block: Uint8Array) => Uint8Array;
|
|
3
|
+
/**
|
|
4
|
+
* RFC 3394 AES Key Wrap. `plaintext` is the key material to wrap — a multiple of
|
|
5
|
+
* 8 bytes, at least 16 (two semiblocks). Returns `plaintext.length + 8` bytes.
|
|
6
|
+
*/
|
|
7
|
+
export declare function aesKeyWrap(plaintext: Uint8Array, encryptBlock: AesBlockFn): Uint8Array;
|
|
8
|
+
/**
|
|
9
|
+
* RFC 3394 AES Key Unwrap. `ciphertext` is `key.length + 8` bytes. Throws
|
|
10
|
+
* `OperationError` when the integrity check (recovered IV ≠ default) fails.
|
|
11
|
+
*/
|
|
12
|
+
export declare function aesKeyUnwrap(ciphertext: Uint8Array, decryptBlock: AesBlockFn): Uint8Array;
|
|
@@ -139,12 +139,14 @@ export interface CipherLike {
|
|
|
139
139
|
final(): Uint8Array;
|
|
140
140
|
setAAD?(aad: Uint8Array): void;
|
|
141
141
|
getAuthTag?(): Uint8Array;
|
|
142
|
+
setAutoPadding?(autoPadding: boolean): void;
|
|
142
143
|
}
|
|
143
144
|
export interface DecipherLike {
|
|
144
145
|
update(data: Uint8Array): Uint8Array;
|
|
145
146
|
final(): Uint8Array;
|
|
146
147
|
setAuthTag?(tag: Uint8Array): void;
|
|
147
148
|
setAAD?(aad: Uint8Array): void;
|
|
149
|
+
setAutoPadding?(autoPadding: boolean): void;
|
|
148
150
|
}
|
|
149
151
|
export interface SignerLike {
|
|
150
152
|
update(data: Uint8Array): void;
|
package/lib/types/subtle.d.ts
CHANGED
|
@@ -10,13 +10,28 @@ export declare class SubtleCrypto {
|
|
|
10
10
|
importKey(format: 'raw' | 'jwk' | 'pkcs8' | 'spki', keyData: BufferSource | JsonWebKey, algorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey>;
|
|
11
11
|
exportKey(format: 'raw' | 'jwk' | 'pkcs8' | 'spki', key: CryptoKey): Promise<ArrayBuffer | JsonWebKey>;
|
|
12
12
|
encrypt(algorithm: AlgorithmIdentifier, key: CryptoKey, data: BufferSource): Promise<ArrayBuffer>;
|
|
13
|
+
/**
|
|
14
|
+
* AES/RSA-OAEP encryption WITHOUT the 'encrypt' key-usage check. Shared by
|
|
15
|
+
* {@link encrypt} (checks 'encrypt') and {@link wrapKey} (checks 'wrapKey'):
|
|
16
|
+
* the wrap operation IS the encrypt operation, gated on a different usage
|
|
17
|
+
* per the WebCrypto spec.
|
|
18
|
+
*/
|
|
19
|
+
private _encryptImpl;
|
|
13
20
|
decrypt(algorithm: AlgorithmIdentifier, key: CryptoKey, data: BufferSource): Promise<ArrayBuffer>;
|
|
21
|
+
/**
|
|
22
|
+
* AES/RSA-OAEP decryption WITHOUT the 'decrypt' key-usage check. Shared by
|
|
23
|
+
* {@link decrypt} (checks 'decrypt') and {@link unwrapKey} (checks
|
|
24
|
+
* 'unwrapKey').
|
|
25
|
+
*/
|
|
26
|
+
private _decryptImpl;
|
|
27
|
+
/** One AES-ECB block (16→16 bytes, no padding) — the RFC 3394 primitive backing AES-KW wrap/unwrap. */
|
|
28
|
+
private _aesEcbBlock;
|
|
14
29
|
sign(algorithm: AlgorithmIdentifier, key: CryptoKey, data: BufferSource): Promise<ArrayBuffer>;
|
|
15
30
|
verify(algorithm: AlgorithmIdentifier, key: CryptoKey, signature: BufferSource, data: BufferSource): Promise<boolean>;
|
|
16
31
|
/** Internal deriveBits without usage check (used by deriveKey) */
|
|
17
32
|
private _deriveBitsInternal;
|
|
18
33
|
deriveBits(algorithm: AlgorithmIdentifier, baseKey: CryptoKey, length: number): Promise<ArrayBuffer>;
|
|
19
34
|
deriveKey(algorithm: AlgorithmIdentifier, baseKey: CryptoKey, derivedKeyAlgorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey>;
|
|
20
|
-
wrapKey(
|
|
21
|
-
unwrapKey(
|
|
35
|
+
wrapKey(format: 'raw' | 'jwk' | 'pkcs8' | 'spki', key: CryptoKey, wrappingKey: CryptoKey, wrapAlgorithm: AlgorithmIdentifier): Promise<ArrayBuffer>;
|
|
36
|
+
unwrapKey(format: 'raw' | 'jwk' | 'pkcs8' | 'spki', wrappedKey: BufferSource, unwrappingKey: CryptoKey, unwrapAlgorithm: AlgorithmIdentifier, unwrappedKeyAlgorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey>;
|
|
22
37
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/webcrypto",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "W3C WebCrypto API (SubtleCrypto) for GJS using @gjsify/crypto primitives",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"build:test:gjs": "gjsify build src/test.mts --app gjs --outfile test.gjs.mjs",
|
|
35
35
|
"build:test:node": "gjsify build src/test.mts --app node --outfile test.node.mjs",
|
|
36
36
|
"build:test:browser": "gjsify build src/test.browser.mts --app browser --outfile dist/test.browser.mjs",
|
|
37
|
-
"test": "gjsify run build:gjsify && gjsify run build:test && gjsify run test:node",
|
|
37
|
+
"test": "gjsify run build:gjsify && gjsify run build:test && gjsify run test:node && gjsify run test:gjs",
|
|
38
38
|
"test:gjs": "gjsify run test.gjs.mjs",
|
|
39
39
|
"test:node": "node test.node.mjs"
|
|
40
40
|
},
|
|
@@ -45,11 +45,11 @@
|
|
|
45
45
|
"crypto"
|
|
46
46
|
],
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@gjsify/dom-exception": "^0.
|
|
48
|
+
"@gjsify/dom-exception": "^0.18.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@gjsify/cli": "^0.
|
|
52
|
-
"@gjsify/unit": "^0.
|
|
51
|
+
"@gjsify/cli": "^0.18.0",
|
|
52
|
+
"@gjsify/unit": "^0.18.0",
|
|
53
53
|
"@types/node": "^25.9.2",
|
|
54
54
|
"typescript": "^6.0.3"
|
|
55
55
|
},
|