From 7a8ea7060831ebd4881473d520a22d72080dd69a Mon Sep 17 00:00:00 2001 From: Luk Lu Date: Sun, 14 Aug 2022 14:50:23 +0800 Subject: [PATCH] u --- ticc.js | 52 +++++++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/ticc.js b/ticc.js index 2f71995..0d0f81f 100644 --- a/ticc.js +++ b/ticc.js @@ -208,7 +208,7 @@ class TicCrypto { * @return {String} * @memberof TicCrypto */ - static async encrypt_easy ({ data, tool = 'crypto', keytype = 'pwd', key, input, output, cipher } = {}) { + static async encrypt_easy ({ data, tool = 'crypto', keytype = 'pwd', key, input = my.INPUT, output = my.OUTPUT, cipher = my.CIPHER } = {}) { if (tool === 'eccrypto') { // data 应当是 utf8 的字符串。key 必须是 pubkey // eccrypto 能用 Uint8Array 和 Buffer @@ -219,17 +219,17 @@ class TicCrypto { } else if (keytype === 'pwd') { // 对称加密 if (typeof key === 'string') { - let inputEncoding = my.INPUT_LIST.includes(input) ? input : my.INPUT // 'utf8' by default, 'ascii', 'latin1' for string or ignored for Buffer/TypedArray/DataView - let outputEncoding = output === 'buf' ? undefined : my.OUTPUT_LIST.includes(output) ? output : my.OUTPUT // 'latin1', 'base64', 'hex' by default or 'buf' to Buffer explicitly + let inputEncoding = input // 'utf8' by default, 'ascii', 'latin1' for string or ignored for Buffer/TypedArray/DataView + let outputEncoding = output === 'buf' ? undefined : output // 'latin1', 'base64', 'hex' by default or 'buf' to Buffer explicitly const iv = crypto.randomBytes(16) - let encryptor = crypto.createCipheriv(my.CIPHER_LIST.includes(cipher) ? cipher : my.CIPHER, this.hex_to_buf(this.hash_easy(key)), iv) // cipher 和 key 的长度必须相同,例如 cipher 是 ***-192,那么 key 就必须是 192/8=24 字节 = 48 hex 的。 + let encryptor = crypto.createCipheriv(cipher, this.hex_to_buf(this.hash_easy(key)), iv) // cipher 和 key 的长度必须相同,例如 cipher 是 ***-192,那么 key 就必须是 192/8=24 字节 = 48 hex 的。 if (typeof data !== 'string' && !(data instanceof Buffer) && !(data instanceof DataView)) data = JSON.stringify(data) let ciphertext = encryptor.update(data, inputEncoding, outputEncoding) ciphertext += encryptor.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string return { iv: iv.toString('hex'), ciphertext } // 有 iv,显然每次结果不一样 } } else if (keytype === 'seckey') { - // 尚未走通,不能使用 ticc 生成的 Elliptic curve 椭圆曲线算法公私钥,只能用 crypto.generateKeyPair('rsa') 生成的 rsa 公私钥 + // 尚未走通,不能使用 ticc 生成的 Elliptic curve 椭圆曲线算法公私钥,只能用 crypto.generateKeyPairSync('rsa') 生成的 rsa 公私钥 let seckeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。 return crypto.privateEncrypt(seckeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。 } else if (keytype === 'pubkey') { @@ -248,7 +248,7 @@ class TicCrypto { * @return {String} * @memberof TicCrypto */ - static async decrypt_easy ({ data = {}, tool = 'crypto', keytype = 'pwd', key, input, output, cipher } = {}) { + static async decrypt_easy ({ data = {}, tool = 'crypto', keytype = 'pwd', key, input = my.OUTPUT, output = my.OUTPUT, cipher = my.CIPHER } = {}) { // data 应当是 encrypt 输出的数据类型 if (tool === 'eccrypto') { try { @@ -264,13 +264,9 @@ class TicCrypto { } else if (keytype === 'pwd') { // 对称解密 if ((typeof data.ciphertext === 'string' || data.ciphertext instanceof Buffer) && typeof key === 'string') { - let inputEncoding = my.OUTPUT_LIST.includes(input) ? input : my.OUTPUT // input (=output of encrypt) could be 'latin1', 'base64', 'hex' by default for string or ignored for Buffer - let outputEncoding = output === 'buf' ? undefined : my.INPUT_LIST.includes(output) ? output : my.INPUT // output (=input of encrypt) could be 'latin1', 'ascii', 'utf8' by default or 'buf' to Buffer explicitly - let decryptor = crypto.createDecipheriv( - my.CIPHER_LIST.includes(cipher) ? cipher : my.CIPHER, - this.hex_to_buf(this.hash_easy(key)), - Buffer.from(data.iv, 'hex') - ) + let inputEncoding = input // input (=output of encrypt) could be 'latin1', 'base64', 'hex' by default for string or ignored for Buffer + let outputEncoding = output === 'buf' ? undefined : output // output (=input of encrypt) could be 'latin1', 'ascii', 'utf8' by default or 'buf' to Buffer explicitly + let decryptor = crypto.createDecipheriv(cipher, this.hex_to_buf(this.hash_easy(key)), Buffer.from(data.iv, 'hex')) let decrypted = decryptor.update(data.ciphertext, inputEncoding, outputEncoding) decrypted += decryptor.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string // 如果用户输入错误密码,deciper也能解密,无法自动判断是否正确结果。可在返回后人工判断。 @@ -297,7 +293,7 @@ class TicCrypto { * @return {String} * @memberof TicCrypto */ - static async sign_easy ({ data, seckey, tool = 'crypto', hasher }) { + static async sign_easy ({ data, seckey, tool = 'crypto', hasher = my.HASHER }) { // data can be string or buffer or object, results are the same if (this.is_hashable({ data }) && this.is_seckey({ seckey })) { if (tool === 'nacl' && seckey.length === 128) { @@ -312,11 +308,11 @@ class TicCrypto { } else if (seckey.length === 64) { // 纯 crypto let seckeyPEM = await new keyman.Key('oct', this.hex_to_buf(seckey), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。 - let signer = crypto.createSign(my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER) // 注意,不知为何,hasher必须含有'sha'才能完成签名,例如 sha1, sha256, sha512, sha3, RSA-SHA1, id-rsassa-pkcs1-v1_5-with-sha3-224, 其他都会报错。 + let signer = crypto.createSign(hasher) // 注意,不知为何,hasher必须含有'sha'才能完成签名,例如 sha1, sha256, sha512, sha3, RSA-SHA1, id-rsassa-pkcs1-v1_5-with-sha3-224, 其他都会报错。 signer.update(this.hash_easy(data)).end() let signature = signer.sign(seckeyPEM, 'hex') // since nodejs 12, 有了 crypto.sign 方法,但在浏览器中无效: - // let signature = crypto.sign(my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER, Buffer.from(this.hash_easy(data)), seckeyPEM).toString('hex') + // let signature = crypto.sign(hasher, Buffer.from(this.hash_easy(data)), seckeyPEM).toString('hex') return signature // 发现同样的输入,nodejs里每次调用会生成不同的 signature, 且长度不定(140,142,144 hex) 但都可以通过 verify。但在浏览器里调用,signature却是固定的。 } } @@ -334,7 +330,7 @@ class TicCrypto { * @return {Boolean} * @memberof TicCrypto */ - static async verify_easy ({ data, signature, pubkey, tool = 'crypto', hasher }) { + static async verify_easy ({ data, signature, pubkey, tool = 'crypto', hasher = my.HASHER }) { // data could be anything, but converts to string or remains be Buffer/TypedArray/DataView if (this.is_hashable({ data }) && this.is_signature({ sig: signature }) && this.is_pubkey({ pubkey })) { if ('nacl' === tool && signature.length === 128) { @@ -355,11 +351,11 @@ class TicCrypto { } else if (signature.length >= 140) { // 纯 crypto // 发现大小写不影响 crypto 验签!都能通过 let pubkeyPEM = await new keyman.Key('oct', this.hex_to_buf(pubkey), { namedCurve: 'P-256K' }).export('pem') // 公钥导出的der格式为88字节。经测试,同一对压缩和非压缩公钥得出的结果一模一样。 - let verifier = crypto.createVerify(my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER) + let verifier = crypto.createVerify(hasher) verifier.update(this.hash_easy(data)).end() // end() 在 nodejs 12 里返回verifier自身,但在浏览器里返回 undefined,因此不能串联运行。 let verified = verifier.verify(pubkeyPEM, signature, 'hex') // 如果给signature添加1位hex,crypto 的 verify结果也是true! 估计因为一位hex不被转成字节。但减少1位会导致false // since nodejs 12, 有了 crypto.verify 方法,但在浏览器中无效: - // let verified = crypto.verify(my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER, Buffer.from(this.hash_easy(data)), pubkeyPEM, Buffer.from(signature, 'hex')) + // let verified = crypto.verify(hasher, Buffer.from(this.hash_easy(data)), pubkeyPEM, Buffer.from(signature, 'hex')) return verified } } @@ -375,10 +371,9 @@ class TicCrypto { * @return {Object} {pubkey, seckey, address,} * @memberof TicCrypto */ - static pass_to_keypair ({ pass, hasher } = {}) { + static pass_to_keypair ({ pass, hasher = my.HASHER } = {}) { // 如果使用其他机制,例如密码、随机数,不使用secword,也可生成keypair if (this.is_hashable({ data: pass })) { - hasher = my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER var hashBuf = crypto .createHash(hasher) .update(pass) @@ -433,7 +428,7 @@ class TicCrypto { * @return {Object} {pubkey, seckey,} * @memberof TicCrypto */ - static secword_to_keypair ({ secword, coin, pass, pathRoot, pathIndex, path, tool, hasher } = {}) { + static secword_to_keypair ({ secword, coin, pass, pathRoot, pathIndex, path, tool, hasher = my.HASHER } = {}) { // coin 币种; // passphase 密码,默认为空; // path 规范为 m/Purpose'/CoinType'/Account'/Change/Index (https://learnblockchain.cn/2018/09/28/hdwallet/), 其中 @@ -448,7 +443,6 @@ class TicCrypto { if (tool === 'nacl') { // 采用自己的算法:bip39算法从secword到种子,hash后用 nacl.sign.keyPair.fromSeed()方法。 - hasher = my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER let hashBuf = crypto .createHash(hasher) .update(this.secword_to_seed({ secword, pass })) @@ -674,13 +668,13 @@ class TicCrypto { .digest('hex') .slice(-40) } else { - let h256 = crypto + let h256buf = crypto .createHash('sha256') .update(Buffer.from(pubkey, 'hex')) .digest() let h160 = crypto .createHash('ripemd160') - .update(h256) + .update(h256buf) .digest('hex') return h160 } @@ -1024,14 +1018,14 @@ class TicCrypto { * @return {*} * @memberof TicCrypto */ - static get_merkle_hash ({ hashList, output, hasher } = {}) { + static get_merkle_hash ({ hashList, output = my.OUTPUT, hasher = my.HASHER } = {}) { // merkle算法略有难度,暂时用最简单的hash代替 if (Array.isArray(hashList)) { - myhasher = crypto.createHash(my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER) - for (var hash of hashList) { + const myhasher = crypto.createHash(hasher) + for (let hash of hashList) { myhasher.update(hash) } - return myhasher.digest(output === 'buf' ? undefined : output || my.OUTPUT) + return myhasher.digest(output === 'buf' ? undefined : output) } return null }