diff --git a/README.xlsx b/README.xlsx index 9cacbee..86752c8 100644 Binary files a/README.xlsx and b/README.xlsx differ diff --git a/index.js b/index.js index 48307cf..f70e12c 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,7 @@ const nacl = require('tweetnacl') const bs58check = require('bs58check') const uuid = require('uuid') const keccak = require('keccak') -const eccrypto = require('eccrypto') // 用于加解密。不知道怎么用 crypto 本身的加解密。 +const eccrypto = require('eccrypto-js') // 用于加解密。eccrypto 在 windows 上和 openssl 的版本兼容性有点麻烦,所以换用 eccrypto-js const keyman = require('js-crypto-key-utils') // 转换原始密钥和 PER/DER 格式。 // const BitcoreMnemonic = require('bitcore-mnemonic') // https://bitcore.io/api/mnemonic/ https://github.com/bitpay/bitcore-mnemonic // 打包成 app 里常有问题,试图访问 window 变量,无法生成 secword const bip39 = require('bip39') // https://github.com/bitcoinjs/bip39 // 有更多语言,但不方便选择语言,也不能使用 pass @@ -176,27 +176,32 @@ class TICrypto { * @return {String} * @memberof TICrypto */ - static async encrypt(data, { tool, keytype, key, input, output, cipher } = {}) { - if (keytype === 'pwd') { + static async encrypt(data, { keytype = 'pwd', key, input, output, cipher } = {}) { + if (tool === 'eccrypto') { + // data 应当是 utf8 的字符串。key 必须是 pubkey + // eccrypto 能用 Uint8Array 和 Buffer + // eccrypto-js 只能用 Buffer + // 在浏览器里 https://github.com/bitchan/eccrypto 库报错,即使用了 Uint8Array: Failed to execute 'encrypt' on 'SubtleCrypto': The provided value is not of type '(ArrayBuffer or ArrayBufferView)' + let cipherobject = await eccrypto.encrypt(Buffer.from(this.hex2buf(key)), data) // 对 eccrypto 库,使用 + return cipherobject // 返回一个复杂的结构。对同样的key和data,每次返回的结果不一样 + } else if (keytype === 'pwd') { if (typeof key === 'string') { let inputEncoding = my.INPUT_LIST.indexOf(input) >= 0 ? input : my.INPUT // 'utf8' by default, 'ascii', 'latin1' for string or ignored for Buffer/TypedArray/DataView let outputEncoding = output === 'buf' ? undefined : my.OUTPUT_LIST.indexOf(output) >= 0 ? output : my.OUTPUT // 'latin1', 'base64', 'hex' by default or 'buf' to Buffer explicitly - let ciph = crypto.createCipher(my.CIPHER_LIST.indexOf(cipher) >= 0 ? cipher : my.CIPHER, this.hash(key)) + const iv = crypto.randomBytes(16) + let ciph = crypto.createCipheriv(my.CIPHER_LIST.indexOf(cipher) >= 0 ? cipher : my.CIPHER, this.hex2buf(this.hash(key)), iv) if (typeof data !== 'string' && !(data instanceof Buffer) && !(data instanceof DataView)) data = JSON.stringify(data) - let encrypted = ciph.update(data, inputEncoding, outputEncoding) - encrypted += ciph.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string - return encrypted + let ciphertext = ciph.update(data, inputEncoding, outputEncoding) + ciphertext += ciph.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string + return { iv: iv.toString('hex'), ciphertext } } - } else if (tool === 'eccrypto') { - // data 应当是 utf8 的字符串。// 但在浏览器里不能使用 Failed to execute 'encrypt' on 'SubtleCrypto': The provided value is not of type '(ArrayBuffer or ArrayBufferView)' - let cipherobject = await eccrypto.encrypt(this.hex2buf(key), data) - return cipherobject } else if (keytype === 'seckey') { + // 尚未走通,不能使用 ticCrypto 生成的 Elliptic curve 椭圆曲线算法公私钥,只能用 crypto.generateKeypairs() 生成的 rsa 公私钥 let seckeyPEM = await new keyman.Key('oct', this.hex2buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。 - return crypto.privateEncrypt(seckeyPEM, Buffer.from(data)) + return crypto.privateEncrypt(seckeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。 } else if (keytype === 'pubkey') { - let pubkeyPEM = await new keyman.Key('oct', this.hex2buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。 - return crypto.publicEncrypt(pubkeyPEM, Buffer.from(data)) + let pubkeyPEM = await new keyman.Key('oct', this.hex2buf(key), { namedCurve: 'P-256K' }).export('pem') + return crypto.publicEncrypt(pubkeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果不一样。 } return null } @@ -210,34 +215,39 @@ class TICrypto { * @return {String} * @memberof TICrypto */ - static async decrypt(data, { keytype, key, input, output, cipher, format } = {}) { + static async decrypt(data = {}, { keytype = 'pwd', key, input, output, cipher } = {}) { // data 应当是 encrypt 输出的数据类型 - if (keytype === 'pwd') { - if (data && (typeof data === 'string' || data instanceof Buffer) && typeof key === 'string') { - let inputEncoding = my.OUTPUT_LIST.indexOf(input) >= 0 ? 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.indexOf(output) >= 0 ? output : my.INPUT // output (=input of encrypt) could be 'latin1', 'ascii', 'utf8' by default or 'buf' to Buffer explicitly - let decipher = crypto.createDecipher(my.CIPHER_LIST.indexOf(cipher) >= 0 ? cipher : my.CIPHER, this.hash(key)) - let decrypted = decipher.update(data, inputEncoding, outputEncoding) - decrypted += decipher.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string - if (format === 'json') { - // 如果用户输入错误密码,deciper也能返回结果。为了判断是否正确结果,对应当是 json 格式的原文做解析来验证。 - try { - JSON.parse(decrypted) - } catch (exception) { - return null - } - } - return decrypted - } - } else if (keytype === 'seckey') { - // cipherobject 需要是 eccrypto 自身encrypt方法返回的对象 + if (tool === 'eccrypto') { try { - let plaindata = await eccrypto.decrypt(Buffer.from(key, 'hex'), data) // eccrypto 需要调用 Buffer.compare 方法,不能在这里直接用 hex2buf + // eccrypto 只能接受 Buffer, 不接受 Uint8Array, 因为 eccrypto 需要调用 Buffer.compare 方法,不能在这里直接用 hex2buf + // eccrypto 也只能接受 Buffer, 不接受 Uint8Array + let plaindata = await eccrypto.decrypt(Buffer.from(key, 'hex'), data) // data 需要是 eccrypto 自身encrypt方法返回的 cipherobject return plaindata.toString('utf8') } catch (exception) { // eccrypto 对无法解密的,会抛出异常 return null } + } else if (keytype === 'pwd') { + if ((typeof data.ciphertext === 'string' || data.ciphertext instanceof Buffer) && typeof key === 'string') { + let inputEncoding = my.OUTPUT_LIST.indexOf(input) >= 0 ? 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.indexOf(output) >= 0 ? output : my.INPUT // output (=input of encrypt) could be 'latin1', 'ascii', 'utf8' by default or 'buf' to Buffer explicitly + let decipher = crypto.createDecipheriv( + my.CIPHER_LIST.indexOf(cipher) >= 0 ? cipher : my.CIPHER, + this.hex2buf(this.hash(key)), + Buffer.from(data.iv, 'hex') + ) + let decrypted = decipher.update(data.ciphertext, inputEncoding, outputEncoding) + decrypted += decipher.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string + // 如果用户输入错误密码,deciper也能解密,无法自动判断是否正确结果。可在返回后人工判断。 + return decrypted + } + } else if (keytype === 'seckey') { + // 尚未走通,不能使用 ticCrypto 生成的 Elliptic curve 椭圆曲线算法公私钥 + let seckeyPEM = await new keyman.Key('oct', this.hex2buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。 + return crypto.privateDecrypt(seckeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。 + } else if (keytype === 'pubkey') { + let pubkeyPEM = await new keyman.Key('oct', this.hex2buf(key), { namedCurve: 'P-256K' }).export('pem') + return crypto.publicDecrypt(pubkeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果不一样。 } return null } @@ -957,12 +967,14 @@ class TICrypto { } /** - * + * 生成 uuid * * @static * @memberof TICrypto */ - static randomUuid = uuid.v4 + static randomUuid() { + return uuid.v4() + } /** * 获取梅克哈希 diff --git a/package.json b/package.json index 0366b00..aa38aed 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "big-integer": "^1.6.48", "bip39": "^3.0.2", "bs58check": "^2.1.2", - "eccrypto": "^1.1.3", + "eccrypto-js": "^5.4.0", "hdkey": "^1.1.1", "js-crypto-key-utils": "^0.7.3", "keccak": "^2.1.0",