diff --git a/public/libs/blake2b.js b/public/libs/blake2b.js new file mode 100644 index 0000000..19f49da --- /dev/null +++ b/public/libs/blake2b.js @@ -0,0 +1,11 @@ +/** + * Bundled by jsDelivr using Rollup v2.79.1 and Terser v5.19.2. + * Original file: /npm/blakejs@1.2.1/blake2b.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + * + * https://github.com/dcposch/blakejs + * https://esm.run/blakejs@1.2.1/blake2b.js + * https://cdn.jsdelivr.net/npm/blakejs@1.2.1/blake2b.js/+esm + */ +function e(e){return(4294967296+e).toString(16).substring(1)}const t={normalizeInput:function(e){let t;if(e instanceof Uint8Array)t=e;else{if("string"!=typeof e)throw new Error("Input must be an string, Buffer or Uint8Array");t=(new TextEncoder).encode(e)}return t},toHex:function(e){return Array.prototype.map.call(e,(function(e){return(e<16?"0":"")+e.toString(16)})).join("")},debugPrint:function(t,n,r){let o="\n"+t+" = ";for(let l=0;l=4294967296&&o++,e[t]=r,e[t+1]=o}function r(e,t,n,r){let o=e[t]+n;n<0&&(o+=4294967296);let l=e[t+1]+r;o>=4294967296&&l++,e[t]=o,e[t+1]=l}function o(e,t){return e[t]^e[t+1]<<8^e[t+2]<<16^e[t+3]<<24}function l(e,t,o,l,i,a){const u=s[i],f=s[i+1],b=s[a],g=s[a+1];n(c,e,t),r(c,e,u,f);let h=c[l]^c[e],p=c[l+1]^c[e+1];c[l]=p,c[l+1]=h,n(c,o,l),h=c[t]^c[o],p=c[t+1]^c[o+1],c[t]=h>>>24^p<<8,c[t+1]=p>>>24^h<<8,n(c,e,t),r(c,e,b,g),h=c[l]^c[e],p=c[l+1]^c[e+1],c[l]=h>>>16^p<<16,c[l+1]=p>>>16^h<<16,n(c,o,l),h=c[t]^c[o],p=c[t+1]^c[o+1],c[t]=p>>>31^h<<1,c[t+1]=h>>>31^p<<1}const i=new Uint32Array([4089235720,1779033703,2227873595,3144134277,4271175723,1013904242,1595750129,2773480762,2917565137,1359893119,725511199,2600822924,4215389547,528734635,327033209,1541459225]),a=new Uint8Array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3,11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4,7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8,9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13,2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9,12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11,13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10,6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5,10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3].map((function(e){return 2*e}))),c=new Uint32Array(32),s=new Uint32Array(32);function u(e,t){let n=0;for(n=0;n<16;n++)c[n]=e.h[n],c[n+16]=i[n];for(c[24]=c[24]^e.t,c[25]=c[25]^e.t/4294967296,t&&(c[28]=~c[28],c[29]=~c[29]),n=0;n<32;n++)s[n]=o(e.b,4*n);for(n=0;n<12;n++)l(0,8,16,24,a[16*n+0],a[16*n+1]),l(2,10,18,26,a[16*n+2],a[16*n+3]),l(4,12,20,28,a[16*n+4],a[16*n+5]),l(6,14,22,30,a[16*n+6],a[16*n+7]),l(0,10,20,30,a[16*n+8],a[16*n+9]),l(2,12,22,24,a[16*n+10],a[16*n+11]),l(4,14,16,26,a[16*n+12],a[16*n+13]),l(6,8,18,28,a[16*n+14],a[16*n+15]);for(n=0;n<16;n++)e.h[n]=e.h[n]^c[n]^c[n+16]}const f=new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);function b(e,t,n,r){if(0===e||e>64)throw new Error("Illegal output length, expected 0 < length <= 64");if(t&&t.length>64)throw new Error("Illegal key, expected Uint8Array with 0 < length <= 64");if(n&&16!==n.length)throw new Error("Illegal salt, expected Uint8Array with length is 16");if(r&&16!==r.length)throw new Error("Illegal personal, expected Uint8Array with length is 16");const l={b:new Uint8Array(128),h:new Uint32Array(16),t:0,c:0,outlen:e};f.fill(0),f[0]=e,t&&(f[1]=t.length),f[2]=1,f[3]=1,n&&f.set(n,32),r&&f.set(r,48);for(let e=0;e<16;e++)l.h[e]=i[e]^o(f,4*e);return t&&(g(l,t),l.c=128),l}function g(e,t){for(let n=0;n>2]>>8*(3&n);return t}function p(e,n,r,o,l){r=r||64,e=t.normalizeInput(e),o&&(o=t.normalizeInput(o)),l&&(l=t.normalizeInput(l));const i=b(r,n,o,l);return g(i,e),h(i)}var w={blake2b:p,blake2bHex:function(e,n,r,o,l){const i=p(e,n,r,o,l);return t.toHex(i)},blake2bInit:b,blake2bUpdate:g,blake2bFinal:h},U=w.blake2b,y=w.blake2bFinal,d=w.blake2bHex,k=w.blake2bInit,A=w.blake2bUpdate;export{U as blake2b,y as blake2bFinal,d as blake2bHex,k as blake2bInit,A as blake2bUpdate,w as default}; \ No newline at end of file diff --git a/public/libs/sha3.js b/public/libs/sha3.js new file mode 100644 index 0000000..302709c --- /dev/null +++ b/public/libs/sha3.js @@ -0,0 +1,12 @@ +/** + * Bundled by jsDelivr using Rollup v2.79.1 and Terser v5.19.2. + * Original file: /npm/@noble/hashes@1.3.3/sha3.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + * + * https://github.com/paulmillr/noble-hashes#sha3-fips-shake-keccak + * https://esm.run/@noble/hashes/sha3.js + * https://esm.run/@noble/hashes@1.3.3/esm/sha3.js + * https://cdn.jsdelivr.net/npm/@noble/hashes/sha3.js/+esm + */ +function t(t){if(!Number.isSafeInteger(t)||t<0)throw new Error(`Wrong positive integer: ${t}`)}function e(t,...e){if(!((n=t)instanceof Uint8Array||null!=n&&"object"==typeof n&&"Uint8Array"===n.constructor.name))throw new Error("Expected Uint8Array");var n;if(e.length>0&&!e.includes(t.length))throw new Error(`Expected Uint8Array of length ${e}, not of length=${t.length}`)}function n(t,e=!0){if(t.destroyed)throw new Error("Hash instance has been destroyed");if(e&&t.finished)throw new Error("Hash#digest() has already been called")}const r=BigInt(2**32-1),s=BigInt(32);function o(t,e=!1){return e?{h:Number(t&r),l:Number(t>>s&r)}:{h:0|Number(t>>s&r),l:0|Number(t&r)}}function i(t,e=!1){let n=new Uint32Array(t.length),r=new Uint32Array(t.length);for(let s=0;s>w)*g)%y,e&d&&(s^=p<<(p<n>32?((t,e,n)=>e<>>64-n)(t,e,n):((t,e,n)=>t<>>32-n)(t,e,n),I=(t,e,n)=>n>32?((t,e,n)=>t<>>64-n)(t,e,n):((t,e,n)=>e<>>32-n)(t,e,n);function A(t,e=24){const n=new Uint32Array(10);for(let r=24-e;r<24;r++){for(let e=0;e<10;e++)n[e]=t[e]^t[e+10]^t[e+20]^t[e+30]^t[e+40];for(let e=0;e<10;e+=2){const r=(e+8)%10,s=(e+2)%10,o=n[s],i=n[s+1],h=L(o,i,1)^n[r],u=I(o,i,1)^n[r+1];for(let n=0;n<50;n+=10)t[e+n]^=h,t[e+n+1]^=u}let e=t[2],s=t[3];for(let n=0;n<24;n++){const r=c[n],o=L(e,s,r),i=I(e,s,r),h=f[n];e=t[h],s=t[h+1],t[h]=o,t[h+1]=i}for(let e=0;e<50;e+=10){for(let r=0;r<10;r++)n[r]=t[e+r];for(let r=0;r<10;r++)t[e+r]^=~n[(r+2)%10]&n[(r+4)%10]}t[0]^=b[r],t[1]^=k[r]}n.fill(0)}class U extends u{constructor(e,n,r,s=!1,o=24){if(super(),this.blockLen=e,this.suffix=n,this.outputLen=r,this.enableXOF=s,this.rounds=o,this.pos=0,this.posOut=0,this.finished=!1,this.destroyed=!1,t(r),0>=this.blockLen||this.blockLen>=200)throw new Error("Sha3 supports only keccak-f1600 function");var i;this.state=new Uint8Array(200),this.state32=(i=this.state,new Uint32Array(i.buffer,i.byteOffset,Math.floor(i.byteLength/4)))}keccak(){A(this.state32,this.rounds),this.posOut=0,this.pos=0}update(t){n(this);const{blockLen:e,state:r}=this,s=(t=h(t)).length;for(let n=0;n=s&&this.keccak();const o=Math.min(s-this.posOut,n-e);t.set(r.subarray(this.posOut,this.posOut+o),e),this.posOut+=o,e+=o}return t}xofInto(t){if(!this.enableXOF)throw new Error("XOF is not possible for this instance");return this.writeInto(t)}xof(e){return t(e),this.xofInto(new Uint8Array(e))}digestInto(t){if(function(t,n){e(t);const r=n.outputLen;if(t.lengthfunction(t){const e=e=>t().update(h(e)).digest(),n=t();return e.outputLen=n.outputLen,e.blockLen=n.blockLen,e.create=()=>t(),e}((()=>new U(e,t,n))),E=x(6,144,28),O=x(6,136,32),m=x(6,104,48),B=x(6,72,64),N=x(1,144,28),v=x(1,136,32),F=x(1,104,48),X=x(1,72,64),$=(t,e,n)=>function(t){const e=(e,n)=>t(n).update(h(e)).digest(),n=t({});return e.outputLen=n.outputLen,e.blockLen=n.blockLen,e.create=e=>t(e),e}(((r={})=>new U(e,t,void 0===r.dkLen?n:r.dkLen,!0))),M=$(31,168,16),j=$(31,136,32);export{U as Keccak,A as keccakP,N as keccak_224,v as keccak_256,F as keccak_384,X as keccak_512,E as sha3_224,O as sha3_256,m as sha3_384,B as sha3_512,M as shake128,j as shake256};export default null; \ No newline at end of file diff --git a/src/helpers/wallet.js b/src/helpers/wallet.js index e45fbcd..b631ddf 100644 --- a/src/helpers/wallet.js +++ b/src/helpers/wallet.js @@ -14,6 +14,8 @@ import { // @ts-ignore import blake from 'blakejs' +// @ts-ignore +import { keccak_256 } from '@noble/hashes/sha3' // @ts-ignore let dashsight = DashSight.create({ @@ -235,19 +237,23 @@ export async function decryptPhraseFromKeystore( // console.log('decryptPhrase derivedBits', derivedBytes) - const calculatedMAC = blake256([ + const bMAC = blake256([ ...new Uint8Array(derivedBytes.slice(16, 32)), ...Cryptic.toBytes(ciphertext), ]) + const kMAC = Cryptic.toHex(keccak_256(new Uint8Array([ + ...new Uint8Array(derivedBytes.slice(16, 32)), + ...Cryptic.toBytes(ciphertext), + ]))); // console.log( - // 'decryptPhrase mac === calculatedMAC', + // 'decryptPhrase mac === bMAC', // // mac, - // // calculatedMAC, - // mac === calculatedMAC + // // bMAC, + // mac === bMAC // ) - if (mac !== calculatedMAC) { + if (mac && ![bMAC, kMAC].includes(mac)) { throw new Error('Invalid password') } @@ -313,19 +319,23 @@ export async function decryptPhraseFromKeystoreBytes( // console.log('decryptPhrase derivedBits', derivedBytes) - const calculatedMAC = blake256([ + const bMAC = blake256([ ...new Uint8Array(derivedBytes.slice(16, 32)), ...Cryptic.toBytes(ciphertext), ]) + const kMAC = Cryptic.toHex(keccak_256(new Uint8Array([ + ...new Uint8Array(derivedBytes.slice(16, 32)), + ...Cryptic.toBytes(ciphertext), + ]))); // console.log( - // 'decryptPhrase mac === calculatedMAC', + // 'decryptPhrase mac === bMAC', // // mac, - // // calculatedMAC, - // mac === calculatedMAC + // // bMAC, + // mac === bMAC // ) - if (mac !== calculatedMAC) { + if (mac && ![bMAC, kMAC].includes(mac)) { throw new Error('Invalid password') } @@ -355,6 +365,128 @@ export async function decryptPhraseFromKeystoreBytes( } } +export async function encryptKeystore( + encryptionPassword, + recoveryPhrase, +) { + let ks = { + crypto: { + cipher: "aes-128-ctr", + ciphertext: '', + cipherparams: { + iv: '', + }, + kdf: "pbkdf2", + kdfparams: { + c: 262144, + dklen: 32, + prf: "hmac-sha256", + salt: '', + }, + mac: '', + }, + id: crypto.randomUUID(), + meta: 'dash-incubator-keystore', + version: 3, + } + // const { + // ciphertext, cipherLength, cipherAlgorithm, + // derivationAlgorithm, hashingAlgorithm, // iv, + // mac, iterations, ivBuffer, salt, numBits, + // } = getKeystoreData(ks) + + const [ + cipherAlgorithm, + cipherLength, + ] = KS_CIPHER[ks.crypto.cipher] + + // Cryptic.setConfig('name', cipherAlgorithm) + // Cryptic.setConfig('length', cipherLength) + // Cryptic.setConfig('pbkdfName', 'PBKDF2') + // Cryptic.setConfig( + // 'iterations', + // // @ts-ignore + // ks.crypto.kdfparams.c, + // ) + + const salt = Cryptic.randomBytes(32) + const iv = Cryptic.randomBytes(16) + + ks.crypto.kdfparams.salt = Cryptic.bufferToHex(salt) + ks.crypto.cipherparams.iv = Cryptic.bufferToHex(iv) + + const keyMaterial = await crypto.subtle.importKey( + 'raw', + Cryptic.stringToBuffer(encryptionPassword), + ks.crypto.kdf.toUpperCase(), + false, + ['deriveBits', 'deriveKey'], + ) + + const keyLength = ks.crypto.kdfparams.dklen / 2 + // const numBits = (keyLength + Cryptic.bufferToHex(iv).length) * 8 + const numBits = (keyLength + iv.length) * 8 + + const derivedBytes = await crypto.subtle.deriveBits( + { + name: ks.crypto.kdf.toUpperCase(), + salt, + iterations: ks.crypto.kdfparams.c, + hash: KS_PRF[ks.crypto.kdfparams.prf], + }, + keyMaterial, + numBits, + ); + + const derivedKey = await crypto.subtle.deriveKey( + { + name: ks.crypto.kdf.toUpperCase(), + salt, + iterations: ks.crypto.kdfparams.c, + hash: KS_PRF[ks.crypto.kdfparams.prf], + }, + keyMaterial, + { + name: cipherAlgorithm, + length: cipherLength + }, + true, + ['encrypt', 'decrypt'], + ) + + let enc = await crypto.subtle.encrypt( + { + name: cipherAlgorithm, + counter: iv, + length: cipherLength, + }, + derivedKey, + Cryptic.stringToBuffer(recoveryPhrase), + ) + ks.crypto.ciphertext = Cryptic.bufferToHex(enc) + + const bMAC = blake256([ + ...new Uint8Array(derivedBytes.slice(16, 32)), + ...Cryptic.toBytes(ks.crypto.ciphertext), + ]) + const kMAC = Cryptic.toHex(keccak_256(new Uint8Array([ + ...new Uint8Array(derivedBytes.slice(16, 32)), + ...Cryptic.toBytes(ks.crypto.ciphertext), + ]))); + + ks.crypto.mac = bMAC + + // console.log( + // 'encrypted keystore', ks, + // [ + // bMAC, + // kMAC, + // ] + // ) + + return ks +} + export async function initWallet( encryptionPassword, wallet, diff --git a/src/index.html b/src/index.html index 8de0fde..4cd2caf 100644 --- a/src/index.html +++ b/src/index.html @@ -64,7 +64,8 @@