From 60f1a2742d5257388b0abdbd82b21416766d35a1 Mon Sep 17 00:00:00 2001 From: sairajzero Date: Fri, 24 Sep 2021 03:31:03 +0530 Subject: [PATCH] Update floCrypto.js --- src/floCrypto.js | 549 ++++++++++++++++++++++++++--------------------- 1 file changed, 307 insertions(+), 242 deletions(-) diff --git a/src/floCrypto.js b/src/floCrypto.js index 81b589a..bad6ea2 100644 --- a/src/floCrypto.js +++ b/src/floCrypto.js @@ -1,274 +1,339 @@ 'use strict'; (function(GLOBAL) { - var floCrypto = GLOBAL.floCrypto = {}; - const p = BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16); - const ecparams = EllipticCurve.getSECCurveByName("secp256k1"); + const floCrypto = GLOBAL.floCrypto = { - function exponent1() { - return p.add(BigInteger.ONE).divide(BigInteger("4")); - }; + util: { + p: BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16), - function calculateY(x) { - let exp = exponent1(); - // x is x value of public key in BigInteger format without 02 or 03 or 04 prefix - return x.modPow(BigInteger("3"), p).add(BigInteger("7")).mod(p).modPow(exp, p); - }; + ecparams: EllipticCurve.getSECCurveByName("secp256k1"), - function getUncompressedPublicKey(compressedPublicKey) { - // Fetch x from compressedPublicKey - let pubKeyBytes = Crypto.util.hexToBytes(compressedPublicKey); - const prefix = pubKeyBytes.shift(); // remove prefix - let prefix_modulus = prefix % 2; - pubKeyBytes.unshift(0); // add prefix 0 - let x = new BigInteger(pubKeyBytes); - let xDecimalValue = x.toString(); - // Fetch y - let y = calculateY(x); - let yDecimalValue = y.toString(); - // verify y value - let resultBigInt = y.mod(BigInteger("2")); - let check = resultBigInt.toString() % 2; - if (prefix_modulus !== check) - yDecimalValue = y.negate().mod(p).toString(); - return { - x: xDecimalValue, - y: yDecimalValue - }; - }; + asciiAlternatives: `‘ '\n’ '\n“ "\n” "\n– --\n— ---\n≥ >=\n≤ <=\n≠ !=\n× *\n÷ /\n← <-\n→ ->\n↔ <->\n⇒ =>\n⇐ <=\n⇔ <=>`, - function getSenderPublicKeyString() { - privateKey = ellipticCurveEncryption.senderRandom(); - senderPublicKeyString = ellipticCurveEncryption.senderPublicString(privateKey); - return { - privateKey: privateKey, - senderPublicKeyString: senderPublicKeyString - }; - }; + exponent1: function() { + return this.p.add(BigInteger.ONE).divide(BigInteger("4")) + }, - function deriveSharedKeySender(receiverCompressedPublicKey, senderPrivateKey) { - try { - let receiverPublicKeyString = getUncompressedPublicKey(receiverCompressedPublicKey); - var senderDerivedKey = ellipticCurveEncryption.senderSharedKeyDerivation( - receiverPublicKeyString.x, receiverPublicKeyString.y, senderPrivateKey); - return senderDerivedKey; - } catch (error) { - return new Error(error); - }; - }; + calculateY: function(x) { + let p = this.p; + let exp = this.exponent1(); + // x is x value of public key in BigInteger format without 02 or 03 or 04 prefix + return x.modPow(BigInteger("3"), p).add(BigInteger("7")).mod(p).modPow(exp, p) + }, + getUncompressedPublicKey: function(compressedPublicKey) { + const p = this.p; + // Fetch x from compressedPublicKey + let pubKeyBytes = Crypto.util.hexToBytes(compressedPublicKey); + const prefix = pubKeyBytes.shift() // remove prefix + let prefix_modulus = prefix % 2; + pubKeyBytes.unshift(0) // add prefix 0 + let x = new BigInteger(pubKeyBytes) + let xDecimalValue = x.toString() + // Fetch y + let y = this.calculateY(x); + let yDecimalValue = y.toString(); + // verify y value + let resultBigInt = y.mod(BigInteger("2")); + let check = resultBigInt.toString() % 2; + if (prefix_modulus !== check) + yDecimalValue = y.negate().mod(p).toString(); + return { + x: xDecimalValue, + y: yDecimalValue + }; + }, - function deriveReceiverSharedKey(senderPublicKeyString, receiverPrivateKey) { - return ellipticCurveEncryption.receiverSharedKeyDerivation( - senderPublicKeyString.XValuePublicString, - senderPublicKeyString.YValuePublicString, receiverPrivateKey); - }; + getSenderPublicKeyString: function() { + privateKey = ellipticCurveEncryption.senderRandom(); + senderPublicKeyString = ellipticCurveEncryption.senderPublicString(privateKey); + return { + privateKey: privateKey, + senderPublicKeyString: senderPublicKeyString + } + }, - function getReceiverPublicKeyString(privateKey) { - return ellipticCurveEncryption.receiverPublicString(privateKey); - }; + deriveSharedKeySender: function(receiverCompressedPublicKey, senderPrivateKey) { + let receiverPublicKeyString = this.getUncompressedPublicKey(receiverCompressedPublicKey); + var senderDerivedKey = ellipticCurveEncryption.senderSharedKeyDerivation( + receiverPublicKeyString.x, receiverPublicKeyString.y, senderPrivateKey); + return senderDerivedKey; + }, - function wifToDecimal(pk_wif, isPubKeyCompressed = false) { - let pk = Bitcoin.Base58.decode(pk_wif); - pk.shift(); - pk.splice(-4, 4); - //If the private key corresponded to a compressed public key, also drop the last byte (it should be 0x01). - if (isPubKeyCompressed == true) pk.pop(); - pk.unshift(0); - privateKeyDecimal = BigInteger(pk).toString(); - privateKeyHex = Crypto.util.bytesToHex(pk); - return { - privateKeyDecimal: privateKeyDecimal, - privateKeyHex: privateKeyHex - }; - }; + deriveReceiverSharedKey: function(senderPublicKeyString, receiverPrivateKey) { + return ellipticCurveEncryption.receiverSharedKeyDerivation( + senderPublicKeyString.XValuePublicString, senderPublicKeyString.YValuePublicString, receiverPrivateKey); + }, + getReceiverPublicKeyString: function(privateKey) { + return ellipticCurveEncryption.receiverPublicString(privateKey); + }, - //generate a random Interger within range - floCrypto.randInt = function(min, max) { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min + 1)) + min; - }; + deriveSharedKeyReceiver: function(senderPublicKeyString, receiverPrivateKey) { + return ellipticCurveEncryption.receiverSharedKeyDerivation( + senderPublicKeyString.XValuePublicString, senderPublicKeyString.YValuePublicString, receiverPrivateKey); + }, - //generate a random String within length (options : alphaNumeric chars only) - floCrypto.randString = function(length, alphaNumeric = true) { - var result = ''; - if (alphaNumeric) - var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - else - var characters = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+-./*?@#&$<>=[]{}():'; - for (var i = 0; i < length; i++) - result += characters.charAt(Math.floor(Math.random() * characters.length)); - return result; - }; + wifToDecimal: function(pk_wif, isPubKeyCompressed = false) { + let pk = Bitcoin.Base58.decode(pk_wif) + pk.shift() + pk.splice(-4, 4) + //If the private key corresponded to a compressed public key, also drop the last byte (it should be 0x01). + if (isPubKeyCompressed == true) pk.pop() + pk.unshift(0) + privateKeyDecimal = BigInteger(pk).toString() + privateKeyHex = Crypto.util.bytesToHex(pk) + return { + privateKeyDecimal: privateKeyDecimal, + privateKeyHex: privateKeyHex + } + } + }, - //Encrypt Data using public-key - floCrypto.encryptData = function(data, publicKeyHex) { - var senderECKeyData = getSenderPublicKeyString(); - var senderDerivedKey = deriveSharedKeySender( - publicKeyHex, senderECKeyData.privateKey); - let senderKey = senderDerivedKey.XValue + senderDerivedKey.YValue; - let secret = Crypto.AES.encrypt(data, senderKey); - return { - secret: secret, - senderPublicKeyString: senderECKeyData.senderPublicKeyString - }; - }; + //generate a random Interger within range + randInt: function(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; + }, - //Decrypt Data using private-key - floCrypto.decryptData = function(data, privateKeyHex) { - var receiverECKeyData = {}; - if (typeof privateKeyHex !== "string") throw new Error("No private key found."); - let privateKey = wifToDecimal(privateKeyHex, true); - if (typeof privateKey.privateKeyDecimal !== "string") throw new Error( - "Failed to detremine your private key."); - receiverECKeyData.privateKey = privateKey.privateKeyDecimal; - var receiverDerivedKey = deriveReceiverSharedKey( - data.senderPublicKeyString, receiverECKeyData.privateKey); - let receiverKey = receiverDerivedKey.XValue + receiverDerivedKey.YValue; - let decryptMsg = Crypto.AES.decrypt(data.secret, receiverKey); - return decryptMsg; - }; + //generate a random String within length (options : alphaNumeric chars only) + randString: function(length, alphaNumeric = true) { + var result = ''; + if (alphaNumeric) + var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + else + var characters = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+-./*?@#&$<>=[]{}():'; + for (var i = 0; i < length; i++) + result += characters.charAt(Math.floor(Math.random() * characters.length)); + return result; + }, - //Sign data using private-key - floCrypto.signData = function(data, privateKeyHex) { - var key = new Bitcoin.ECKey(privateKeyHex); - if(key.priv === null) - return false; - key.setCompressed(true); - //var privateKeyArr = key.getBitcoinPrivateKeyByteArray(); - //var privateKey = BigInteger.fromByteArrayUnsigned(privateKeyArr); - var messageHash = Crypto.SHA256(data); - var messageHashBigInteger = new BigInteger(messageHash); - var messageSign = Bitcoin.ECDSA.sign(messageHashBigInteger, key.priv); - var sighex = Crypto.util.bytesToHex(messageSign); - return sighex; - }; - - //Verify signatue of the data using public-key - floCrypto.verifySign = function(data, signatureHex, publicKeyHex) { - var msgHash = Crypto.SHA256(data); - var messageHashBigInteger = new BigInteger(msgHash); - var sigBytes = Crypto.util.hexToBytes(signatureHex); - var signature = Bitcoin.ECDSA.parseSig(sigBytes); - var publicKeyPoint = ecparams.getCurve().decodePointHex(publicKeyHex); - var verify = Bitcoin.ECDSA.verifyRaw(messageHashBigInteger, - signature.r, signature.s, publicKeyPoint); - return verify; - }; - - //Generates a new flo ID and returns private-key, public-key and floID - floCrypto.generateNewID = function() { - try { - var key = new Bitcoin.ECKey(false); - key.setCompressed(true); + //Encrypt Data using public-key + encryptData: function(data, receiverCompressedPublicKey) { + var senderECKeyData = this.util.getSenderPublicKeyString(); + var senderDerivedKey = this.util.deriveSharedKeySender(receiverCompressedPublicKey, senderECKeyData + .privateKey); + let senderKey = senderDerivedKey.XValue + senderDerivedKey.YValue; + let secret = Crypto.AES.encrypt(data, senderKey); return { - floID: key.getBitcoinAddress(), - pubKey: key.getPubKeyHex(), - privKey: key.getBitcoinWalletImportFormat() + secret: secret, + senderPublicKeyString: senderECKeyData.senderPublicKeyString }; - } catch (e) { - console.error(e); - }; - }; + }, - //Returns public-key from private-key - floCrypto.getPubKeyHex = function(privateKeyHex) { - if (!privateKeyHex) - return null; - var key = new Bitcoin.ECKey(privateKeyHex); - if (key.priv == null) - return null; - key.setCompressed(true); - return key.getPubKeyHex(); - }; + //Decrypt Data using private-key + decryptData: function(data, myPrivateKey) { + var receiverECKeyData = {}; + if (typeof myPrivateKey !== "string") throw new Error("No private key found."); - //Returns flo-ID from public-key or private-key - floCrypto.getFloID = function(keyHex) { - if (!keyHex) - return null; - try { - var key = new Bitcoin.ECKey(keyHex); - if (key.priv == null) - key.setPub(keyHex); - return key.getBitcoinAddress(); - } catch (e) { - return null; - }; - }; + let privateKey = this.util.wifToDecimal(myPrivateKey, true); + if (typeof privateKey.privateKeyDecimal !== "string") throw new Error( + "Failed to detremine your private key."); + receiverECKeyData.privateKey = privateKey.privateKeyDecimal; - //Verify the private-key for the given public-key or flo-ID - floCrypto.verifyPrivKey = function(privateKeyHex, publicHex_ID) { - if (!privateKeyHex || !publicHex_ID) - return false; - try { + var receiverDerivedKey = this.util.deriveReceiverSharedKey(data.senderPublicKeyString, + receiverECKeyData + .privateKey); + + let receiverKey = receiverDerivedKey.XValue + receiverDerivedKey.YValue; + let decryptMsg = Crypto.AES.decrypt(data.secret, receiverKey); + return decryptMsg; + }, + + //Sign data using private-key + signData: function(data, privateKeyHex) { + var key = new Bitcoin.ECKey(privateKeyHex); + key.setCompressed(true); + + var privateKeyArr = key.getBitcoinPrivateKeyByteArray(); + privateKey = BigInteger.fromByteArrayUnsigned(privateKeyArr); + var messageHash = Crypto.SHA256(data); + + var messageHashBigInteger = new BigInteger(messageHash); + var messageSign = Bitcoin.ECDSA.sign(messageHashBigInteger, key.priv); + + var sighex = Crypto.util.bytesToHex(messageSign); + return sighex; + }, + + //Verify signatue of the data using public-key + verifySign: function(data, signatureHex, publicKeyHex) { + var msgHash = Crypto.SHA256(data); + var messageHashBigInteger = new BigInteger(msgHash); + + var sigBytes = Crypto.util.hexToBytes(signatureHex); + var signature = Bitcoin.ECDSA.parseSig(sigBytes); + + var publicKeyPoint = this.util.ecparams.getCurve().decodePointHex(publicKeyHex); + + var verify = Bitcoin.ECDSA.verifyRaw(messageHashBigInteger, signature.r, signature.s, + publicKeyPoint); + return verify; + }, + + //Generates a new flo ID and returns private-key, public-key and floID + generateNewID: function() { + try { + var key = new Bitcoin.ECKey(false); + key.setCompressed(true); + return { + floID: key.getBitcoinAddress(), + pubKey: key.getPubKeyHex(), + privKey: key.getBitcoinWalletImportFormat() + } + } catch (e) { + console.error(e); + } + }, + + //Returns public-key from private-key + getPubKeyHex: function(privateKeyHex) { + if (!privateKeyHex) + return null; var key = new Bitcoin.ECKey(privateKeyHex); if (key.priv == null) - return false; + return null; key.setCompressed(true); - if (publicHex_ID === key.getBitcoinAddress()) - return true; - else if (publicHex_ID === key.getPubKeyHex()) - return true; - else + return key.getPubKeyHex(); + }, + + //Returns flo-ID from public-key or private-key + getFloID: function(keyHex) { + if (!keyHex) + return null; + try { + var key = new Bitcoin.ECKey(keyHex); + if (key.priv == null) + key.setPub(keyHex); + return key.getBitcoinAddress(); + } catch (e) { + return null; + } + }, + + //Verify the private-key for the given public-key or flo-ID + verifyPrivKey: function(privateKeyHex, pubKey_floID, isfloID = true) { + if (!privateKeyHex || !pubKey_floID) return false; - } catch (e) { - console.error(e); - }; - }; + try { + var key = new Bitcoin.ECKey(privateKeyHex); + if (key.priv == null) + return false; + key.setCompressed(true); + if (isfloID && pubKey_floID == key.getBitcoinAddress()) + return true; + else if (!isfloID && pubKey_floID == key.getPubKeyHex()) + return true; + else + return false; + } catch (e) { + console.error(e); + } + }, - //Check if the given Address is valid or not - floCrypto.validateAddr = function(inpAddr) { - if (!inpAddr) - return false; - try { - var addr = new Bitcoin.Address(inpAddr); - return true; - } catch { - return false; - }; - }; + //Check if the given Address is valid or not + validateAddr: function(inpAddr) { + if (!inpAddr) + return false; + try { + var addr = new Bitcoin.Address(inpAddr); + return true; + } catch { + return false; + } + }, - //Split the str using shamir's Secret and Returns the shares - floCrypto.createShamirsSecretShares = function(str, total_shares, threshold_limit) { - try { - if (str.length > 0) { - var strHex = shamirSecretShare.str2hex(str); - return shamirSecretShare.share(strHex, total_shares, threshold_limit); - }; - return false; - } catch { - return false; - }; - }; + //Split the str using shamir's Secret and Returns the shares + createShamirsSecretShares: function(str, total_shares, threshold_limit) { + try { + if (str.length > 0) { + var strHex = shamirSecretShare.str2hex(str); + var shares = shamirSecretShare.share(strHex, total_shares, threshold_limit); + return shares; + } + return false; + } catch { + return false + } + }, - //Verifies the shares and str - floCrypto.verifyShamirsSecret = function(sharesArray, str) { - if(str == false) - return false; - try { - if (sharesArray.length > 0) { - var comb = shamirSecretShare.combine(sharesArray.slice(0, sharesArray.length)); - return (shamirSecretShare.hex2str(comb) === str ? true : false); - }; - return false; - } catch { - return false; - }; - }; + //Verifies the shares and str + verifyShamirsSecret: function(sharesArray, str) { + return (str && this.retrieveShamirSecret(sharesArray) === str) + }, - //Returns the retrived secret by combining the shamirs shares - floCrypto.retrieveShamirSecret = function(sharesArray) { - try { - if (sharesArray.length > 0) { - var comb = shamirSecretShare.combine(sharesArray.slice(0, sharesArray.length)); - return shamirSecretShare.hex2str(comb); - }; - return false; - } catch { - return false; - }; - }; + //Returns the retrived secret by combining the shamirs shares + retrieveShamirSecret: function(sharesArray) { + try { + if (sharesArray.length > 0) { + var comb = shamirSecretShare.combine(sharesArray.slice(0, sharesArray.length)); + comb = shamirSecretShare.hex2str(comb); + return comb; + } + return false; + } catch { + return false; + } + }, + + validateASCII: function(string, bool = true) { + if (typeof string !== "string") + return null; + if (bool) { + let x; + for (let i = 0; i < string.length; i++) { + x = string.charCodeAt(i); + if (x < 32 || x > 127) + return false; + } + return true; + } else { + let x, invalids = {}; + for (let i = 0; i < string.length; i++) { + x = string.charCodeAt(i); + if (x < 32 || x > 127) + if (x in invalids) + invalids[string[i]].push(i) + else + invalids[string[i]] = [i]; + } + if (Object.keys(invalids).length) + return invalids; + else + return true; + } + }, + + convertToASCII: function(string, mode = 'soft-remove') { + let chars = this.validateASCII(string, false); + if (chars === true) + return string; + else if (chars === null) + return null; + let convertor, result = string, + refAlt = {}; + this.util.asciiAlternatives.split('\n').forEach(a => refAlt[a[0]] = a.slice(2)); + mode = mode.toLowerCase(); + if (mode === "hard-unicode") + convertor = (c) => `\\u${('000'+c.charCodeAt().toString(16)).slice(-4)}`; + else if (mode === "soft-unicode") + convertor = (c) => refAlt[c] || `\\u${('000'+c.charCodeAt().toString(16)).slice(-4)}`; + else if (mode === "hard-remove") + convertor = c => ""; + else if (mode === "soft-remove") + convertor = c => refAlt[c] || ""; + else + return null; + for (let c in chars) + result = result.replaceAll(c, convertor(c)); + return result; + }, + + revertUnicode: function(string) { + return string.replace(/\\u[\dA-F]{4}/gi, + m => String.fromCharCode(parseInt(m.replace(/\\u/g, ''), 16))); + } + } })(typeof global !== "undefined" ? global : window); \ No newline at end of file