iron-webcrypto
Advanced tools
Comparing version 0.2.5 to 0.2.6
@@ -53,7 +53,7 @@ import { Buffer } from 'buffer/index.js'; | ||
*/ | ||
declare type Password = Buffer | string; | ||
type Password = Buffer | string; | ||
/** | ||
* generateKey() method options. | ||
*/ | ||
declare type GenerateKeyOptions = Pick<SealOptionsSub, 'algorithm' | 'iterations' | 'minPasswordlength'> & { | ||
type GenerateKeyOptions = Pick<SealOptionsSub, 'algorithm' | 'iterations' | 'minPasswordlength'> & { | ||
saltBits?: number | undefined; | ||
@@ -100,3 +100,3 @@ salt?: string | undefined; | ||
} | ||
declare type RawPassword = Password | password.Secret | password.Specific; | ||
type RawPassword = Password | password.Secret | password.Specific; | ||
@@ -103,0 +103,0 @@ declare const base64urlEncode: (value: Buffer | string) => string; |
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
var index_js = require('buffer/index.js'); | ||
var x=t=>(index_js.Buffer.isBuffer(t)?t:index_js.Buffer.from(t)).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,""),j={encryption:{saltBits:256,algorithm:"aes-256-cbc",iterations:1,minPasswordlength:32},integrity:{saltBits:256,algorithm:"sha256",iterations:1,minPasswordlength:32},ttl:0,timestampSkewSec:60,localtimeOffsetMsec:0},v=t=>({...t,encryption:{...t.encryption},integrity:{...t.integrity}}),h={"aes-128-ctr":{keyBits:128,ivBits:128,name:"AES-CTR"},"aes-256-cbc":{keyBits:256,ivBits:128,name:"AES-CBC"},sha256:{keyBits:256,name:"SHA-256"}},A="2",K=`Fe26.${A}`,M=(t,n)=>{let e=index_js.Buffer.allocUnsafe(n);return t.getRandomValues(e),e},b=(t,n)=>{if(n<1)throw Error("Invalid random bits count");let e=Math.ceil(n/8);return M(t,e)},H=async(t,n,e,s,r,c)=>{let o=new TextEncoder,a=o.encode(n),i=await t.subtle.importKey("raw",a,"PBKDF2",!1,["deriveBits"]),m=o.encode(e),f={name:"PBKDF2",hash:c,salt:m,iterations:s},y=await t.subtle.deriveBits(f,i,r*8);return index_js.Buffer.from(y)},E=async(t,n,e)=>{if(n==null||!n.length)throw new Error("Empty password");if(e==null||typeof e!="object")throw new Error("Bad options");if(!(e.algorithm in h))throw new Error(`Unknown algorithm: ${e.algorithm}`);let s=h[e.algorithm],r={},c=e.hmac??!1,o=c?{name:"HMAC",hash:s.name}:{name:s.name},a=c?["sign","verify"]:["encrypt","decrypt"];if(typeof n=="string"){if(n.length<e.minPasswordlength)throw new Error(`Password string too short (min ${e.minPasswordlength} characters required)`);let{salt:i=""}=e;if(!i){let{saltBits:y=0}=e;if(!y)throw new Error("Missing salt and saltBits options");i=b(t,y).toString("hex");}let m=await H(t,n,i,e.iterations,s.keyBits/8,"SHA-1"),f=await t.subtle.importKey("raw",m,o,!1,a);r.key=f,r.salt=i;}else {if(n.length<s.keyBits/8)throw new Error("Key buffer (password) too small");r.key=await t.subtle.importKey("raw",n,o,!1,a),r.salt="";}return e.iv?r.iv=e.iv:"ivBits"in s&&(r.iv=b(t,s.ivBits)),r},I=async(t,n,e,s)=>{let r=await E(t,n,e),o=new TextEncoder().encode(s),a=await t.subtle.encrypt({name:h[e.algorithm].name,iv:r.iv},r.key,o);return {encrypted:index_js.Buffer.from(a),key:r}},R=async(t,n,e,s)=>{let r=await E(t,n,e),c=await t.subtle.decrypt({name:h[e.algorithm].name,iv:r.iv},r.key,index_js.Buffer.isBuffer(s)?s:index_js.Buffer.from(s));return new TextDecoder().decode(c)},k=async(t,n,e,s)=>{let r=await E(t,n,{...e,hmac:!0}),o=new TextEncoder().encode(s),a=await t.subtle.sign({name:"HMAC"},r.key,o);return {digest:x(index_js.Buffer.from(a)),salt:r.salt}},$=t=>typeof t=="object"&&!index_js.Buffer.isBuffer(t)?"secret"in t?{id:t.id,encryption:t.secret,integrity:t.secret}:{id:t.id,encryption:t.encryption,integrity:t.integrity}:{encryption:t,integrity:t},F=async(t,n,e,s)=>{if(!e)throw Error("Empty password");let r=v(s),c=Date.now()+(r.localtimeOffsetMsec||0),o=JSON.stringify(n),a=$(e),{id:i=""}=a;if(i&&!/^\w+$/.test(i))throw new Error("Invalid password id");let{encrypted:m,key:f}=await I(t,a.encryption,r.encryption,o),y=x(m),d=x(f.iv),u=r.ttl?c+r.ttl:"",w=`${K}*${i}*${f.salt}*${d}*${y}*${u}`,g=await k(t,a.integrity,r.integrity,w);return `${w}*${g.salt}*${g.digest}`},D=(t,n)=>{let e=t.length===n.length?0:1;e&&(n=t);for(let s=0;s<t.length;s+=1)e|=t.charCodeAt(s)^n.charCodeAt(s);return e===0},U=async(t,n,e,s)=>{if(!e)throw Error("Empty password");let r=v(s),c=Date.now()+(r.localtimeOffsetMsec||0),o=n.split("*");if(o.length!==8)throw new Error("Incorrect number of sealed components");let a=o[0],i=o[1],m=o[2],f=o[3],y=o[4],d=o[5],u=o[6],w=o[7],g=`${a}*${i}*${m}*${f}*${y}*${d}`;if(K!==a)throw new Error("Wrong mac prefix");if(d){if(!/^\d+$/.exec(d))throw new Error("Invalid expiration");if(parseInt(d,10)<=c-r.timestampSkewSec*1e3)throw new Error("Expired seal")}if(typeof e>"u"||typeof e=="string"&&e.length===0)throw new Error("Empty password");let p;if(typeof e=="object"&&!index_js.Buffer.isBuffer(e)){if(!((i||"default")in e))throw new Error(`Cannot find password: ${i}`);p=e[i||"default"];}else p=e;p=$(p);let P=r.integrity;P.salt=u;let O=await k(t,p.integrity,P,g);if(!D(O.digest,w))throw new Error("Bad hmac value");let C=index_js.Buffer.from(y,"base64"),B=r.encryption;B.salt=m,B.iv=index_js.Buffer.from(f,"base64");let S=await R(t,p.encryption,B,C);return S?JSON.parse(S):null}; | ||
var x=t=>(index_js.Buffer.isBuffer(t)?t:index_js.Buffer.from(t)).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,""),j={encryption:{saltBits:256,algorithm:"aes-256-cbc",iterations:1,minPasswordlength:32},integrity:{saltBits:256,algorithm:"sha256",iterations:1,minPasswordlength:32},ttl:0,timestampSkewSec:60,localtimeOffsetMsec:0},v=t=>({...t,encryption:{...t.encryption},integrity:{...t.integrity}}),u={"aes-128-ctr":{keyBits:128,ivBits:128,name:"AES-CTR"},"aes-256-cbc":{keyBits:256,ivBits:128,name:"AES-CBC"},sha256:{keyBits:256,name:"SHA-256"}},A="2",K=`Fe26.${A}`,M=(t,n)=>{let e=index_js.Buffer.allocUnsafe(n);return t.getRandomValues(e),e},b=(t,n)=>{if(n<1)throw Error("Invalid random bits count");let e=Math.ceil(n/8);return M(t,e)},H=async(t,n,e,s,r,c)=>{let o=new TextEncoder,i=o.encode(n),a=await t.subtle.importKey("raw",i,"PBKDF2",!1,["deriveBits"]),f=o.encode(e),y={name:"PBKDF2",hash:c,salt:f,iterations:s},d=await t.subtle.deriveBits(y,a,r*8);return index_js.Buffer.from(d)},E=async(t,n,e)=>{var a;if(n==null||!n.length)throw new Error("Empty password");if(e==null||typeof e!="object")throw new Error("Bad options");if(!(e.algorithm in u))throw new Error(`Unknown algorithm: ${e.algorithm}`);let s=u[e.algorithm],r={},c=(a=e.hmac)!=null?a:!1,o=c?{name:"HMAC",hash:s.name}:{name:s.name},i=c?["sign","verify"]:["encrypt","decrypt"];if(typeof n=="string"){if(n.length<e.minPasswordlength)throw new Error(`Password string too short (min ${e.minPasswordlength} characters required)`);let{salt:f=""}=e;if(!f){let{saltBits:m=0}=e;if(!m)throw new Error("Missing salt and saltBits options");f=b(t,m).toString("hex");}let y=await H(t,n,f,e.iterations,s.keyBits/8,"SHA-1"),d=await t.subtle.importKey("raw",y,o,!1,i);r.key=d,r.salt=f;}else {if(n.length<s.keyBits/8)throw new Error("Key buffer (password) too small");r.key=await t.subtle.importKey("raw",n,o,!1,i),r.salt="";}return e.iv?r.iv=e.iv:"ivBits"in s&&(r.iv=b(t,s.ivBits)),r},I=async(t,n,e,s)=>{let r=await E(t,n,e),o=new TextEncoder().encode(s),i=await t.subtle.encrypt({name:u[e.algorithm].name,iv:r.iv},r.key,o);return {encrypted:index_js.Buffer.from(i),key:r}},R=async(t,n,e,s)=>{let r=await E(t,n,e),c=await t.subtle.decrypt({name:u[e.algorithm].name,iv:r.iv},r.key,index_js.Buffer.isBuffer(s)?s:index_js.Buffer.from(s));return new TextDecoder().decode(c)},k=async(t,n,e,s)=>{let r=await E(t,n,{...e,hmac:!0}),o=new TextEncoder().encode(s),i=await t.subtle.sign({name:"HMAC"},r.key,o);return {digest:x(index_js.Buffer.from(i)),salt:r.salt}},$=t=>typeof t=="object"&&!index_js.Buffer.isBuffer(t)?"secret"in t?{id:t.id,encryption:t.secret,integrity:t.secret}:{id:t.id,encryption:t.encryption,integrity:t.integrity}:{encryption:t,integrity:t},F=async(t,n,e,s)=>{if(!e)throw Error("Empty password");let r=v(s),c=Date.now()+(r.localtimeOffsetMsec||0),o=JSON.stringify(n),i=$(e),{id:a=""}=i;if(a&&!/^\w+$/.test(a))throw new Error("Invalid password id");let{encrypted:f,key:y}=await I(t,i.encryption,r.encryption,o),d=x(f),m=x(y.iv),w=r.ttl?c+r.ttl:"",g=`${K}*${a}*${y.salt}*${m}*${d}*${w}`,h=await k(t,i.integrity,r.integrity,g);return `${g}*${h.salt}*${h.digest}`},D=(t,n)=>{let e=t.length===n.length?0:1;e&&(n=t);for(let s=0;s<t.length;s+=1)e|=t.charCodeAt(s)^n.charCodeAt(s);return e===0},U=async(t,n,e,s)=>{if(!e)throw Error("Empty password");let r=v(s),c=Date.now()+(r.localtimeOffsetMsec||0),o=n.split("*");if(o.length!==8)throw new Error("Incorrect number of sealed components");let i=o[0],a=o[1],f=o[2],y=o[3],d=o[4],m=o[5],w=o[6],g=o[7],h=`${i}*${a}*${f}*${y}*${d}*${m}`;if(K!==i)throw new Error("Wrong mac prefix");if(m){if(!/^\d+$/.exec(m))throw new Error("Invalid expiration");if(parseInt(m,10)<=c-r.timestampSkewSec*1e3)throw new Error("Expired seal")}if(typeof e=="undefined"||typeof e=="string"&&e.length===0)throw new Error("Empty password");let p;if(typeof e=="object"&&!index_js.Buffer.isBuffer(e)){if(!((a||"default")in e))throw new Error(`Cannot find password: ${a}`);p=e[a||"default"];}else p=e;p=$(p);let P=r.integrity;P.salt=w;let O=await k(t,p.integrity,P,h);if(!D(O.digest,g))throw new Error("Bad hmac value");let C=index_js.Buffer.from(d,"base64"),B=r.encryption;B.salt=f,B.iv=index_js.Buffer.from(y,"base64");let S=await R(t,p.encryption,B,C);return S?JSON.parse(S):null}; | ||
@@ -13,3 +11,3 @@ Object.defineProperty(exports, 'Buffer', { | ||
}); | ||
exports.algorithms = h; | ||
exports.algorithms = u; | ||
exports.base64urlEncode = x; | ||
@@ -16,0 +14,0 @@ exports.clone = v; |
{ | ||
"$schema": "https://json.schemastore.org/package.json", | ||
"name": "iron-webcrypto", | ||
"version": "0.2.5", | ||
"version": "0.2.6", | ||
"description": "a cryptographic utility for sealing-unsealing a JSON object using symmetric key encryption with message integrity verification", | ||
@@ -74,3 +74,3 @@ "keywords": [ | ||
}, | ||
"packageManager": "pnpm@7.9.5", | ||
"packageManager": "pnpm@7.16.1", | ||
"publishConfig": { | ||
@@ -77,0 +77,0 @@ "registry": "https://registry.npmjs.org" |
@@ -1,2 +0,2 @@ | ||
# iron-webcrypto (beta) [![jsDocs.io](https://img.shields.io/badge/jsDocs.io-reference-blue?style=flat-square)](https://www.jsdocs.io/package/iron-webcrypto) | ||
# iron-webcrypto (beta) [![jsDocs.io](https://img.shields.io/badge/jsDocs.io-reference-blue?style=flat-square)](https://www.jsdocs.io/package/iron-webcrypto) [![npm](https://img.shields.io/npm/dm/iron-webcrypto?style=flat-square)](https://www.npmjs.com/package/iron-webcrypto) | ||
@@ -28,3 +28,3 @@ This module is a replacement for [`@hapi/iron`](https://hapi.dev/module/iron/), | ||
```js | ||
Iron.seal(obj, password, Iron.defaults); | ||
Iron.seal(obj, password, Iron.defaults) | ||
``` | ||
@@ -35,10 +35,11 @@ | ||
```js | ||
Iron.seal(_crypto, obj, password, Iron.defaults); | ||
Iron.seal(_crypto, obj, password, Iron.defaults) | ||
``` | ||
where `_crypto` is your Web Crypto implementation. Generally this will available | ||
in your context (for example, `globalThis.crypto` in browsers/edge runtimes, | ||
`globalThis.crypto.webcrypto` in newer Node.js versions). However, you may also | ||
need to polyfill this (for older Node.js versions). We recommend using | ||
where `_crypto` is your Web Crypto implementation. Generally, this will | ||
available in your context (for example, `globalThis.crypto` in browsers, edge | ||
runtimes, Deno, and Node.js v19+; `require('crypto').webcrypto` in Node.js | ||
v15+). However, you may also need to polyfill this for older Node.js versions. | ||
We recommend using | ||
[`@peculiar/webcrypto`](https://www.npmjs.com/package/@peculiar/webcrypto) for | ||
that. |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
20916
44
250