UNPKG

symmetricmorph

Version:

High-performance symmetric stream cipher with dynamic masking, cascading feedback, built-in MAC, and chunked encryption support. Lightweight and dependency-free.

2 lines (1 loc) 3.47 kB
(function(f,w){typeof exports=="object"&&typeof module<"u"?module.exports=w():typeof define=="function"&&define.amd?define(w):(f=typeof globalThis<"u"?globalThis:f||self,f.SymmetricMorph=w())})(this,function(){"use strict";class f{constructor(t,e){this.key=t,this.salt=e}getSalt(){return this.salt}static fromPassword(t,e=2e4,c=64){const n=this.generateSalt(24),s=this.deriveKey(this.strToBytes(t),n,e,c);return new f(s,n)}static fromPasswordWithSalt(t,e,c=2e4,n=64){const s=e instanceof Uint8Array?e:Uint8Array.from(e),o=this.deriveKey(this.strToBytes(t),s,c,n);return new f(o,s)}static fromKey(t){return new f(t)}static generateKey(t=64){const e=this.createPrng([Date.now()&255]);return Uint8Array.from({length:t},(c,n)=>e())}encrypt(t){const e=f.generateNonce(),c=f.createPrng([...this.key,...e]),n=new Uint8Array(t.length),s=this.initState();let o=165,a=108,i=58,l=145,u=157;for(let r=0;r<t.length;r++){const d=c(),h=(r+o+a+i)%s.length,y=(s[h]^o^a^i^l)&255,m=(t[r]^y^d)&255,p=(m<<r%5|m>>8-r%5)&255;n[r]=p,this.updateState(s,p,o,d,r,a,i,l),l=i,i=a,a=p,o=(o^p^d^r*13)&255,u=(u+p+o+r*31^d+a+i)&255}const g=f.generateMac(u,this.key);return Uint8Array.from([...e,...g,...n])}decrypt(t){const e=t.slice(0,8),c=t.slice(8,40),n=t.slice(40),s=f.createPrng([...this.key,...e]),o=this.initState();let a=165,i=108,l=58,u=145,g=157;const r=new Uint8Array(n.length);for(let h=0;h<n.length;h++){const y=s(),m=(h+a+i+l)%o.length,p=(o[m]^a^i^l^u)&255,A=n[h],k=((A>>h%5|A<<8-h%5)&255^p^y)&255;r[h]=k,this.updateState(o,A,a,y,h,i,l,u),u=l,l=i,i=A,a=(a^A^y^h*13)&255,g=(g+A+a+h*31^y+i+l)&255}const d=f.generateMac(g,this.key);if(!f.constantTimeCompare(c,d))throw new Error("MAC verification failed (integrity broken)");return r}encryptChunks(t){return t.map(e=>this.encrypt(e))}decryptChunks(t){return t.map(e=>this.decrypt(e))}updateState(t,e,c,n,s,o,a,i){const l=t.length,u=~e&255,g=(o^a^i^c^n)&255;for(let r=0;r<l;r++)t[r]^=e+g+r*31&255,t[r]=(t[r]<<r%5|t[r]>>8-r%5)&255;if(s%4===3){const r=[...t];for(let d=0;d<l;d++){const h=(d*13+s)%l;t[d]=(r[h]^u)&255}}for(let r=l-1;r>=0;r--)t[r]=t[r]+(u^r*17^c)&255,t[r]=(t[r]>>>r%7|t[r]<<8-r%7)&255}initState(){const t=new Array(64).fill(0);for(let e=0;e<t.length;e++)t[e]=(this.key[e%this.key.length]^e*67+19)&255;return t}static createPrng(t){const e=new Array(64).fill(0).map((n,s)=>t[s%t.length]^s*97&255);let c=0;return()=>{const n=c%64,s=(c*5+11)%64,o=(c*7+17)%64,a=e[n]+(e[s]^e[o]>>>3)+c&255;return e[n]=(e[n]^a<<c%7)&255,c++,a}}static deriveKey(t,e,c,n){let s=Array.from(t).concat(Array.from(e)),o=0;for(let i=0;i<c;i++){const l=s.map((u,g)=>(u^o+g*7+i)%256);o=(o+l.reduce((u,g)=>u^g,0))%256,s=l}const a=new Uint8Array(n);for(let i=0;i<n;i++)a[i]=s[i%s.length]^(i*37+o)%256;return a}static mac(t,e){const c=new Uint8Array(32);let n=137;for(let s=0;s<32;s++){const o=t[s%t.length],a=e[s%e.length];n=(n+o+a*(s+1))%256,c[s]=n^(s*11+o)%256}return c}static generateMac(t,e){const c=new Uint8Array(32);for(let n=0;n<32;n++)c[n]=(t^e[n%e.length]^n*19)&255;return c}static generateSalt(t){const e=performance.now()|0,c=[e&255,e>>8&255,e>>16&255],n=this.createPrng(c);return Uint8Array.from({length:t},(s,o)=>n())}static generateNonce(){const t=Date.now();return Uint8Array.from([t>>0&255,t>>8&255,t>>16&255,t>>24&255,t%251,t%241,t%239,t%233])}static strToBytes(t){return Array.from(t).map(e=>e.charCodeAt(0))}static constantTimeCompare(t,e){if(t.length!==e.length)return!1;let c=0;for(let n=0;n<t.length;n++)c|=t[n]^e[n];return c===0}}return f});