rename b64u to b64t; rename x2y 为 x_to_; add b32 的转换函数
This commit is contained in:
		
							parent
							
								
									b2abb16e81
								
							
						
					
					
						commit
						447a3eb442
					
				
							
								
								
									
										19
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								README.md
									
									
									
									
									
								
							@ -60,33 +60,37 @@ const keyPair = crypto.generateKeyPairSync('rsa', {
 | 
				
			|||||||
这样生成的 keyPair.privateKey 开头是 -----BEGIN ENCRYPTED PRIVATE KEY-----
 | 
					这样生成的 keyPair.privateKey 开头是 -----BEGIN ENCRYPTED PRIVATE KEY-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
如果直接
 | 
					如果直接
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
crypto.privateEncrypt(kp.privateKey, Buffer.from('sdafasfdsaf')) 
 | 
					crypto.privateEncrypt(kp.privateKey, Buffer.from('sdafasfdsaf')) 
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
会报错
 | 
					会报错
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
Uncaught TypeError: Passphrase required for encrypted key 
 | 
					Uncaught TypeError: Passphrase required for encrypted key 
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
所以要这样才行
 | 
					所以要这样才行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
crypto.privateEncrypt({key:kp.privateKey, passphrase:''}, Buffer.from('sdafasfdsaf')) 
 | 
					crypto.privateEncrypt({key:kp.privateKey, passphrase:''}, Buffer.from('sdafasfdsaf')) 
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
我从 https://www.cnblogs.com/chyingp/p/nodejs-asymmetric-enc-dec.html 抄到一个 privateKey 可以直接使用,不需要 passphrase
 | 
					我从 https://www.cnblogs.com/chyingp/p/nodejs-asymmetric-enc-dec.html 抄到一个 privateKey 可以直接使用,不需要 passphrase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
返回 Buffer。每次结果都一样
 | 
					返回 Buffer。每次结果都一样
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
这样生成的 keyPair.publicKey 开头是 -----BEGIN PUBLIC KEY-----
 | 
					这样生成的 keyPair.publicKey 开头是 -----BEGIN PUBLIC KEY-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
可以直接
 | 
					可以直接
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
crypto.publicEncrypt(kp.publicKey, Buffer.from('sdafasfdsaf')) 
 | 
					crypto.publicEncrypt(kp.publicKey, Buffer.from('sdafasfdsaf')) 
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
返回 Buffer。每次结果不一样
 | 
					返回 Buffer。每次结果不一样
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
似乎 crypto 一定要 rsa 公私钥才可以用加解密,ticCrypto.randomKeypair() 生成的 ecc 公私钥不行。
 | 
					似乎 crypto 一定要 rsa 公私钥才可以用加解密,ticCrypto.randomKeypair() 生成的 ecc 公私钥不行。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
而 eccrypto 和 eccrypto-js 可以用。eccrypto.generateKeyPair() 生成的和 ticCrypto.randomKeypair() 一样
 | 
					而 eccrypto 和 eccrypto-js 可以用。eccrypto.generateKeyPair() 生成的和 ticCrypto.randomKeypair() 一样
 | 
				
			||||||
@ -94,3 +98,12 @@ crypto.publicEncrypt(kp.publicKey, Buffer.from('sdafasfdsaf'))
 | 
				
			|||||||
eccrypto 在 windows 上的安装有麻烦,一来需要手工安装 OpenSSL 到 c:\openssl-win64\,二来 openssl 1.1.0 起把 libeay32.lib 改名为 libcrypto.dll,而 eccrypto 需要 c:\openssl-win64\lib\libeay32.lib,会报错
 | 
					eccrypto 在 windows 上的安装有麻烦,一来需要手工安装 OpenSSL 到 c:\openssl-win64\,二来 openssl 1.1.0 起把 libeay32.lib 改名为 libcrypto.dll,而 eccrypto 需要 c:\openssl-win64\lib\libeay32.lib,会报错
 | 
				
			||||||
 | 
					
 | 
				
			||||||
eccrypto-js 在 devDependencies 里继承了 eccrypto,因此 npm i --production 即可
 | 
					eccrypto-js 在 devDependencies 里继承了 eccrypto,因此 npm i --production 即可
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					base32 有多种字符集:[Base32 - Wikipedia](https://en.wikipedia.org/wiki/Base32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IPFS用的是 RFC4648字符集
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- 从数到数符串:Number(数).toString(进制数),0x数.toString(进制数), 0b数.toString(进制数)
 | 
				
			||||||
 | 
					- 从数符串到数字:parseInt(str, 进制数)
 | 
				
			||||||
 | 
					- Buffer到数符串: Buffer.toString(编码方案例如'hex','base64',默认'utf8')
 | 
				
			||||||
 | 
					- 字符串到Buffer: Buffer.from(data, 编码方案如'hex','base64',默认'utf8')
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										110
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								index.js
									
									
									
									
									
								
							@ -13,6 +13,8 @@ const bip39 = require('bip39') // https://github.com/bitcoinjs/bip39 // 有更
 | 
				
			|||||||
const hdkey = require('hdkey') // https://github.com/cryptocoinjs/hdkey // 或者用 bitcore-mnemonic 或者 ethers 里的相同功能
 | 
					const hdkey = require('hdkey') // https://github.com/cryptocoinjs/hdkey // 或者用 bitcore-mnemonic 或者 ethers 里的相同功能
 | 
				
			||||||
// const bitcorelib = require('bitcore-lib')
 | 
					// const bitcorelib = require('bitcore-lib')
 | 
				
			||||||
const secp256k1 = require('secp256k1')
 | 
					const secp256k1 = require('secp256k1')
 | 
				
			||||||
 | 
					const base32encode = require('base32-encode')
 | 
				
			||||||
 | 
					const base32decode = require('base32-decode')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 全部以hex为默认输入输出格式,方便人的阅读,以及方便函数之间统一接口
 | 
					// 全部以hex为默认输入输出格式,方便人的阅读,以及方便函数之间统一接口
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -182,7 +184,7 @@ class TICrypto {
 | 
				
			|||||||
      // eccrypto 能用 Uint8Array 和 Buffer
 | 
					      // eccrypto 能用 Uint8Array 和 Buffer
 | 
				
			||||||
      // eccrypto-js 只能用 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)'
 | 
					      // 在浏览器里 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)
 | 
					      let cipherobject = await eccrypto.encrypt(Buffer.from(this.hex_to_buf(key)), data)
 | 
				
			||||||
      return cipherobject // 返回一个复杂的结构 {iv:Buffer, ciphertext:Buffer, ...}。对同样的key和data,每次返回的结果不一样
 | 
					      return cipherobject // 返回一个复杂的结构 {iv:Buffer, ciphertext:Buffer, ...}。对同样的key和data,每次返回的结果不一样
 | 
				
			||||||
    } else if (keytype === 'pwd') {
 | 
					    } else if (keytype === 'pwd') {
 | 
				
			||||||
      // 对称加密
 | 
					      // 对称加密
 | 
				
			||||||
@ -190,7 +192,7 @@ class TICrypto {
 | 
				
			|||||||
        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 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 outputEncoding = output === 'buf' ? undefined : my.OUTPUT_LIST.indexOf(output) >= 0 ? output : my.OUTPUT // 'latin1', 'base64', 'hex' by default or 'buf' to Buffer explicitly
 | 
				
			||||||
        const iv = crypto.randomBytes(16)
 | 
					        const iv = crypto.randomBytes(16)
 | 
				
			||||||
        let encryptor = crypto.createCipheriv(my.CIPHER_LIST.indexOf(cipher) >= 0 ? cipher : my.CIPHER, this.hex2buf(this.hash(key)), iv) // cipher 和 key 的长度必须相同,例如 cipher 是 ***-192,那么 key 就必须是 192/8=24 字节 = 48 hex 的。
 | 
					        let encryptor = crypto.createCipheriv(my.CIPHER_LIST.indexOf(cipher) >= 0 ? cipher : my.CIPHER, this.hex_to_buf(this.hash(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)
 | 
					        if (typeof data !== 'string' && !(data instanceof Buffer) && !(data instanceof DataView)) data = JSON.stringify(data)
 | 
				
			||||||
        let ciphertext = encryptor.update(data, inputEncoding, outputEncoding)
 | 
					        let ciphertext = encryptor.update(data, inputEncoding, outputEncoding)
 | 
				
			||||||
        ciphertext += encryptor.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string
 | 
					        ciphertext += encryptor.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string
 | 
				
			||||||
@ -198,10 +200,10 @@ class TICrypto {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    } else if (keytype === 'seckey') {
 | 
					    } else if (keytype === 'seckey') {
 | 
				
			||||||
      // 尚未走通,不能使用 ticCrypto 生成的 Elliptic curve 椭圆曲线算法公私钥,只能用 crypto.generateKeypairs() 生成的 rsa 公私钥
 | 
					      // 尚未走通,不能使用 ticCrypto 生成的 Elliptic curve 椭圆曲线算法公私钥,只能用 crypto.generateKeypairs() 生成的 rsa 公私钥
 | 
				
			||||||
      let seckeyPEM = await new keyman.Key('oct', this.hex2buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
 | 
					      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。每次结果都一样。
 | 
					      return crypto.privateEncrypt(seckeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。
 | 
				
			||||||
    } else if (keytype === 'pubkey') {
 | 
					    } else if (keytype === 'pubkey') {
 | 
				
			||||||
      let pubkeyPEM = await new keyman.Key('oct', this.hex2buf(key), { namedCurve: 'P-256K' }).export('pem')
 | 
					      let pubkeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem')
 | 
				
			||||||
      return crypto.publicEncrypt(pubkeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果不一样。
 | 
					      return crypto.publicEncrypt(pubkeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果不一样。
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return null
 | 
					    return null
 | 
				
			||||||
@ -220,7 +222,7 @@ class TICrypto {
 | 
				
			|||||||
    // data 应当是 encrypt 输出的数据类型
 | 
					    // data 应当是 encrypt 输出的数据类型
 | 
				
			||||||
    if (tool === 'eccrypto') {
 | 
					    if (tool === 'eccrypto') {
 | 
				
			||||||
      try {
 | 
					      try {
 | 
				
			||||||
        // eccrypto 只能接受 Buffer, 不接受 Uint8Array, 因为 eccrypto 需要调用 Buffer.compare 方法,不能在这里直接用 hex2buf
 | 
					        // eccrypto 只能接受 Buffer, 不接受 Uint8Array, 因为 eccrypto 需要调用 Buffer.compare 方法,不能在这里直接用 hex_to_buf
 | 
				
			||||||
        // eccrypto 也只能接受 Buffer, 不接受 Uint8Array
 | 
					        // eccrypto 也只能接受 Buffer, 不接受 Uint8Array
 | 
				
			||||||
        // data 需要是 eccrypto 自身encrypt方法返回的 cipherobject. key 是 private key。
 | 
					        // data 需要是 eccrypto 自身encrypt方法返回的 cipherobject. key 是 private key。
 | 
				
			||||||
        let plainbuffer = await eccrypto.decrypt(Buffer.from(key, 'hex'), data) // 返回的是 Buffer
 | 
					        let plainbuffer = await eccrypto.decrypt(Buffer.from(key, 'hex'), data) // 返回的是 Buffer
 | 
				
			||||||
@ -236,7 +238,7 @@ class TICrypto {
 | 
				
			|||||||
        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 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 decryptor = crypto.createDecipheriv(
 | 
					        let decryptor = crypto.createDecipheriv(
 | 
				
			||||||
          my.CIPHER_LIST.indexOf(cipher) >= 0 ? cipher : my.CIPHER,
 | 
					          my.CIPHER_LIST.indexOf(cipher) >= 0 ? cipher : my.CIPHER,
 | 
				
			||||||
          this.hex2buf(this.hash(key)),
 | 
					          this.hex_to_buf(this.hash(key)),
 | 
				
			||||||
          Buffer.from(data.iv, 'hex')
 | 
					          Buffer.from(data.iv, 'hex')
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        let decrypted = decryptor.update(data.ciphertext, inputEncoding, outputEncoding)
 | 
					        let decrypted = decryptor.update(data.ciphertext, inputEncoding, outputEncoding)
 | 
				
			||||||
@ -246,10 +248,10 @@ class TICrypto {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    } else if (keytype === 'seckey') {
 | 
					    } else if (keytype === 'seckey') {
 | 
				
			||||||
      // 尚未走通,不能使用 ticCrypto 生成的 Elliptic curve 椭圆曲线算法公私钥
 | 
					      // 尚未走通,不能使用 ticCrypto 生成的 Elliptic curve 椭圆曲线算法公私钥
 | 
				
			||||||
      let seckeyPEM = await new keyman.Key('oct', this.hex2buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
 | 
					      let seckeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
 | 
				
			||||||
      return crypto.privateDecrypt(seckeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。
 | 
					      return crypto.privateDecrypt(seckeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。
 | 
				
			||||||
    } else if (keytype === 'pubkey') {
 | 
					    } else if (keytype === 'pubkey') {
 | 
				
			||||||
      let pubkeyPEM = await new keyman.Key('oct', this.hex2buf(key), { namedCurve: 'P-256K' }).export('pem')
 | 
					      let pubkeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem')
 | 
				
			||||||
      return crypto.publicDecrypt(pubkeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果不一样。
 | 
					      return crypto.publicDecrypt(pubkeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果不一样。
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return null
 | 
					    return null
 | 
				
			||||||
@ -279,7 +281,7 @@ class TICrypto {
 | 
				
			|||||||
        return signature.toString('hex')
 | 
					        return signature.toString('hex')
 | 
				
			||||||
      } else if (seckey.length === 64) {
 | 
					      } else if (seckey.length === 64) {
 | 
				
			||||||
        // 纯 crypto
 | 
					        // 纯 crypto
 | 
				
			||||||
        let seckeyPEM = await new keyman.Key('oct', this.hex2buf(seckey), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
 | 
					        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.indexOf(hasher) >= 0 ? hasher : my.HASHER) // 注意,不知为何,hasher必须含有'sha'才能完成签名,例如 sha1, sha256, sha512, sha3, RSA-SHA1, id-rsassa-pkcs1-v1_5-with-sha3-224, 其他都会报错。
 | 
					        let signer = crypto.createSign(my.HASHER_LIST.indexOf(hasher) >= 0 ? hasher : my.HASHER) // 注意,不知为何,hasher必须含有'sha'才能完成签名,例如 sha1, sha256, sha512, sha3, RSA-SHA1, id-rsassa-pkcs1-v1_5-with-sha3-224, 其他都会报错。
 | 
				
			||||||
        signer.update(this.hash(data)).end()
 | 
					        signer.update(this.hash(data)).end()
 | 
				
			||||||
        let signature = signer.sign(seckeyPEM, 'hex')
 | 
					        let signature = signer.sign(seckeyPEM, 'hex')
 | 
				
			||||||
@ -322,7 +324,7 @@ class TICrypto {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      } else if (signature.length >= 140) {
 | 
					      } else if (signature.length >= 140) {
 | 
				
			||||||
        // 纯 crypto  // 发现大小写不影响 crypto 验签!都能通过
 | 
					        // 纯 crypto  // 发现大小写不影响 crypto 验签!都能通过
 | 
				
			||||||
        let pubkeyPEM = await new keyman.Key('oct', this.hex2buf(pubkey), { namedCurve: 'P-256K' }).export('pem') // 公钥导出的der格式为88字节。经测试,同一对压缩和非压缩公钥得出的结果一模一样。
 | 
					        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.indexOf(hasher) >= 0 ? hasher : my.HASHER)
 | 
					        let verifier = crypto.createVerify(my.HASHER_LIST.indexOf(hasher) >= 0 ? hasher : my.HASHER)
 | 
				
			||||||
        verifier.update(this.hash(data)).end() // end() 在 nodejs 12 里返回verifier自身,但在浏览器里返回 undefined,因此不能串联运行。
 | 
					        verifier.update(this.hash(data)).end() // end() 在 nodejs 12 里返回verifier自身,但在浏览器里返回 undefined,因此不能串联运行。
 | 
				
			||||||
        let verified = verifier.verify(pubkeyPEM, signature, 'hex') // 如果给signature添加1位hex,crypto 的 verify结果也是true! 估计因为一位hex不被转成字节。但减少1位会导致false
 | 
					        let verified = verifier.verify(pubkeyPEM, signature, 'hex') // 如果给signature添加1位hex,crypto 的 verify结果也是true! 估计因为一位hex不被转成字节。但减少1位会导致false
 | 
				
			||||||
@ -554,13 +556,13 @@ class TICrypto {
 | 
				
			|||||||
      curve = my.CURVE_LIST.indexOf(curve) >= 0 ? curve : my.CURVE // 默认为 secp256k1
 | 
					      curve = my.CURVE_LIST.indexOf(curve) >= 0 ? curve : my.CURVE // 默认为 secp256k1
 | 
				
			||||||
      // return new crypto.createECDH(curve).setPrivateKey(seckey,'hex').getPublicKey('hex', compress===false?'uncompressed':'compressed') // ecdh.getPublicKey(不加参数) 默认为 'compressed'。用 HBuilderX 2.6.4 打包成ios或安卓 app 后 setPrivateKey() 报错:TypeError: null is not an object (evaluating 'this.rand.getBytes')
 | 
					      // return new crypto.createECDH(curve).setPrivateKey(seckey,'hex').getPublicKey('hex', compress===false?'uncompressed':'compressed') // ecdh.getPublicKey(不加参数) 默认为 'compressed'。用 HBuilderX 2.6.4 打包成ios或安卓 app 后 setPrivateKey() 报错:TypeError: null is not an object (evaluating 'this.rand.getBytes')
 | 
				
			||||||
      // 从 nodejs 10.0 开始,还有 crypto.ECDH.convertKey 方法,更直接。但可惜,浏览器里不存在 crypto.ECDH。
 | 
					      // 从 nodejs 10.0 开始,还有 crypto.ECDH.convertKey 方法,更直接。但可惜,浏览器里不存在 crypto.ECDH。
 | 
				
			||||||
      return this.buf2hex(secp256k1.publicKeyCreate(Buffer.from(seckey, 'hex'), compress !== false)) // 可用于浏览器。缺省输出压缩公钥,compress=false时输出非压缩公钥。
 | 
					      return this.buf_to_hex(secp256k1.publicKeyCreate(Buffer.from(seckey, 'hex'), compress !== false)) // 可用于浏览器。缺省输出压缩公钥,compress=false时输出非压缩公钥。
 | 
				
			||||||
      // 或者 bitcorelib.PublicKey.fromPrivateKey(new bitcorelib.PrivateKey(seckey)).toString('hex') // 可用于浏览器
 | 
					      // 或者 bitcorelib.PublicKey.fromPrivateKey(new bitcorelib.PrivateKey(seckey)).toString('hex') // 可用于浏览器
 | 
				
			||||||
      // 或者 const ecc = require('eccrypto')
 | 
					      // 或者 const ecc = require('eccrypto')
 | 
				
			||||||
      // if (compress===false){
 | 
					      // if (compress===false){
 | 
				
			||||||
      //   return ecc.getPublic(this.hex2buf(seckey)).toString('hex')
 | 
					      //   return ecc.getPublic(this.hex_to_buf(seckey)).toString('hex')
 | 
				
			||||||
      // }else{
 | 
					      // }else{
 | 
				
			||||||
      //   return ecc.getPublicCompressed(this.hex2buf(seckey)).toString('hex')
 | 
					      //   return ecc.getPublicCompressed(this.hex_to_buf(seckey)).toString('hex')
 | 
				
			||||||
      // }
 | 
					      // }
 | 
				
			||||||
      // 注意,Buffer.from(nacl.box.keyPair.fromSecretKey(Buffer.from(seckey,'hex')).publicKey).toString('hex') 得到的公钥与上面的不同
 | 
					      // 注意,Buffer.from(nacl.box.keyPair.fromSecretKey(Buffer.from(seckey,'hex')).publicKey).toString('hex') 得到的公钥与上面的不同
 | 
				
			||||||
    } else if (this.isSeckey(seckey) && seckey.length === 128) {
 | 
					    } else if (this.isSeckey(seckey) && seckey.length === 128) {
 | 
				
			||||||
@ -685,7 +687,7 @@ class TICrypto {
 | 
				
			|||||||
      address = bs58check.encode(Buffer.from(prefix + position, 'hex')) // wallet import format
 | 
					      address = bs58check.encode(Buffer.from(prefix + position, 'hex')) // wallet import format
 | 
				
			||||||
      return address
 | 
					      return address
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      // 默认为 TIC。把纯位置转换为大小写敏感能自我验证的 b64u(base64 for url) 地址。
 | 
					      // 默认为 TIC。把纯位置转换为大小写敏感能自我验证的 b64t 地址。
 | 
				
			||||||
      let prefix
 | 
					      let prefix
 | 
				
			||||||
      switch (world) {
 | 
					      switch (world) {
 | 
				
			||||||
        // Base64: https://baike.baidu.com/item/base64
 | 
					        // Base64: https://baike.baidu.com/item/base64
 | 
				
			||||||
@ -702,8 +704,8 @@ class TICrypto {
 | 
				
			|||||||
          prefix = '4c'
 | 
					          prefix = '4c'
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      let checksum = this.hash(this.hash(prefix + position)).slice(0, 6) // 添加 checksum 使得能够检测大小写错误。[todo] 校验码里要不要包含 prefix?
 | 
					      let checksum = this.hash(this.hash(prefix + position)).slice(0, 6) // 添加 checksum 使得能够检测大小写错误。[todo] 校验码里要不要包含 prefix?
 | 
				
			||||||
      //      address = this.hex2eip55(prefix + position + checksum) // 前缀1节,位置20节,校验3节,共24节=48字符(能够完全转化为8个色彩),再转eip55。
 | 
					      //      address = this.hex_to_eip55(prefix + position + checksum) // 前缀1节,位置20节,校验3节,共24节=48字符(能够完全转化为8个色彩),再转eip55。
 | 
				
			||||||
      address = this.hex2b64u(prefix + position + checksum) // 实际采用 b64u (named by luk.lu as base 64 for url), 共 32字符。
 | 
					      address = this.hex_to_b64t(prefix + position + checksum) // 实际采用 b64t, 共 32字符。
 | 
				
			||||||
      return address
 | 
					      return address
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return null
 | 
					    return null
 | 
				
			||||||
@ -722,13 +724,13 @@ class TICrypto {
 | 
				
			|||||||
      // todo: 如果是大小写敏感的,进行有效性验证
 | 
					      // todo: 如果是大小写敏感的,进行有效性验证
 | 
				
			||||||
      return address.toLowerCase()
 | 
					      return address.toLowerCase()
 | 
				
			||||||
    } else if (/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{26,34}$/.test(address)) { // BTC
 | 
					    } else if (/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{26,34}$/.test(address)) { // BTC
 | 
				
			||||||
      let hex = this.b58c2hex(address)
 | 
					      let hex = this.b58c_to_hex(address)
 | 
				
			||||||
      if (hex) {
 | 
					      if (hex) {
 | 
				
			||||||
        return hex.slice(2) // 去除网络前缀
 | 
					        return hex.slice(2) // 去除网络前缀
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } else if (/^[Tt][0-9a-zA-Z\._]{31}$/.test(address)) { // TIC
 | 
					    } else if (/^[Tt][0-9a-zA-Z\._]{31}$/.test(address)) { // TIC
 | 
				
			||||||
      // 格式合法
 | 
					      // 格式合法
 | 
				
			||||||
      let hex = this.b64u2hex(address)
 | 
					      let hex = this.b64t_to_hex(address)
 | 
				
			||||||
      let [all, prefix, position, checksum] = hex.match(/^([\da-fA-F]{2})([\da-fA-F]{40})([\da-fA-F]{6})$/)
 | 
					      let [all, prefix, position, checksum] = hex.match(/^([\da-fA-F]{2})([\da-fA-F]{40})([\da-fA-F]{6})$/)
 | 
				
			||||||
      if (this.hash(this.hash(position)).slice(0, 6) === checksum) {
 | 
					      if (this.hash(this.hash(position)).slice(0, 6) === checksum) {
 | 
				
			||||||
        return position
 | 
					        return position
 | 
				
			||||||
@ -750,13 +752,13 @@ class TICrypto {
 | 
				
			|||||||
      return 'ETH'
 | 
					      return 'ETH'
 | 
				
			||||||
    } else if (/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{26,34}$/.test(address) && address.length !== 32) {
 | 
					    } else if (/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{26,34}$/.test(address) && address.length !== 32) {
 | 
				
			||||||
      // 格式合法。常见的是 33或34字符长度
 | 
					      // 格式合法。常见的是 33或34字符长度
 | 
				
			||||||
      let prefixedPosition = this.b58c2hex(address)
 | 
					      let prefixedPosition = this.b58c_to_hex(address)
 | 
				
			||||||
      if (prefixedPosition && prefixedPosition.length === 42)
 | 
					      if (prefixedPosition && prefixedPosition.length === 42)
 | 
				
			||||||
        // 内容合法
 | 
					        // 内容合法
 | 
				
			||||||
        return 'BTC'
 | 
					        return 'BTC'
 | 
				
			||||||
    } else if (/^[Ttd][0-9a-zA-Z\._]{31}$/.test(address)) {
 | 
					    } else if (/^[Ttd][0-9a-zA-Z\._]{31}$/.test(address)) {
 | 
				
			||||||
      // 格式合法
 | 
					      // 格式合法
 | 
				
			||||||
      let hex = Buffer.from(this.b64u_to_b64(address), 'base64').toString('hex')
 | 
					      let hex = Buffer.from(this.b64t_to_b64(address), 'base64').toString('hex')
 | 
				
			||||||
      let [all, prefix, position, checksum] = hex.match(/^([\da-fA-F]{2})([\da-fA-F]{40})([\da-fA-F]{6})$/) // 内容合法
 | 
					      let [all, prefix, position, checksum] = hex.match(/^([\da-fA-F]{2})([\da-fA-F]{40})([\da-fA-F]{6})$/) // 内容合法
 | 
				
			||||||
      if (this.hash(this.hash(prefix + position)).slice(0, 6) === checksum)
 | 
					      if (this.hash(this.hash(prefix + position)).slice(0, 6) === checksum)
 | 
				
			||||||
        // [todo] 校验码里要不要包含 prefix?
 | 
					        // [todo] 校验码里要不要包含 prefix?
 | 
				
			||||||
@ -1181,7 +1183,7 @@ class TICrypto {
 | 
				
			|||||||
   * @return {*}
 | 
					   * @return {*}
 | 
				
			||||||
   * @memberof TICrypto
 | 
					   * @memberof TICrypto
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  static buf2hex(buffer) {
 | 
					  static buf_to_hex(buffer) {
 | 
				
			||||||
    // buffer is an ArrayBuffer
 | 
					    // buffer is an ArrayBuffer
 | 
				
			||||||
    return Array.prototype.map.call(new Uint8Array(buffer), (x) => ('00' + x.toString(16)).slice(-2)).join('')
 | 
					    return Array.prototype.map.call(new Uint8Array(buffer), (x) => ('00' + x.toString(16)).slice(-2)).join('')
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -1194,7 +1196,7 @@ class TICrypto {
 | 
				
			|||||||
   * @return {*}
 | 
					   * @return {*}
 | 
				
			||||||
   * @memberof TICrypto
 | 
					   * @memberof TICrypto
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  static hex2buf(hex) {
 | 
					  static hex_to_buf(hex) {
 | 
				
			||||||
    return new Uint8Array(
 | 
					    return new Uint8Array(
 | 
				
			||||||
      hex.match(/[\da-f]{2}/gi).map(function (h) {
 | 
					      hex.match(/[\da-f]{2}/gi).map(function (h) {
 | 
				
			||||||
        return parseInt(h, 16)
 | 
					        return parseInt(h, 16)
 | 
				
			||||||
@ -1213,7 +1215,7 @@ class TICrypto {
 | 
				
			|||||||
   * bs58check 和 bs58 可接受string, Buffer, ArrayBuffer, Array (包括空字符串'', 各种内容的数组例如包含 undefined,{...},等等);
 | 
					   * bs58check 和 bs58 可接受string, Buffer, ArrayBuffer, Array (包括空字符串'', 各种内容的数组例如包含 undefined,{...},等等);
 | 
				
			||||||
   * 不可接受 undefined, null, {...}, 等等,会返回 exception
 | 
					   * 不可接受 undefined, null, {...}, 等等,会返回 exception
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  static hex2b58c(hex) {
 | 
					  static hex_to_b58c(hex) {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      return bs58check.encode(Buffer.from(hex, 'hex'))
 | 
					      return bs58check.encode(Buffer.from(hex, 'hex'))
 | 
				
			||||||
    } catch (exception) {
 | 
					    } catch (exception) {
 | 
				
			||||||
@ -1221,7 +1223,7 @@ class TICrypto {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static hex2b58(hex) {
 | 
					  static hex_to_b58(hex) {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      return bs58.encode(Buffer.from(hex, 'hex'))
 | 
					      return bs58.encode(Buffer.from(hex, 'hex'))
 | 
				
			||||||
    } catch (exception) {
 | 
					    } catch (exception) {
 | 
				
			||||||
@ -1237,7 +1239,7 @@ class TICrypto {
 | 
				
			|||||||
   * @return {*}
 | 
					   * @return {*}
 | 
				
			||||||
   * @memberof TICrypto
 | 
					   * @memberof TICrypto
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  static b58c2hex(box) {
 | 
					  static b58c_to_hex(box) {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      return bs58check.decode(box).toString('hex')
 | 
					      return bs58check.decode(box).toString('hex')
 | 
				
			||||||
    } catch (exception) {
 | 
					    } catch (exception) {
 | 
				
			||||||
@ -1245,7 +1247,7 @@ class TICrypto {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static b582hex(box) {
 | 
					  static b58_to_hex(box) {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      return bs58.decode(box).toString('hex')
 | 
					      return bs58.decode(box).toString('hex')
 | 
				
			||||||
    } catch (exception) {
 | 
					    } catch (exception) {
 | 
				
			||||||
@ -1256,45 +1258,71 @@ class TICrypto {
 | 
				
			|||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * b64 字符串为 a-zA-Z0-9+/
 | 
					   * b64 字符串为 a-zA-Z0-9+/
 | 
				
			||||||
   * 其中,+ 和 / 会在 url query string 里被转成 %2B 和 %2F
 | 
					   * 其中,+ 和 / 会在 url query string 里被转成 %2B 和 %2F
 | 
				
			||||||
   * 因此定义 b64u (base64 for url),用 . 和 _ 替换。
 | 
					   * 因此定义 b64t (base64 for tic),用 . 和 _ 替换。
 | 
				
			||||||
   * (为何不用 -,因为 - 和空格一样导致 css white-space 自动换行。)
 | 
					   * (为何不用 base64url, 因为 base64url 把 + 变成 - 和空格一样导致 css white-space 自动换行。)
 | 
				
			||||||
   * @param {*} b64 
 | 
					   * @param {*} b64 
 | 
				
			||||||
   * @returns 
 | 
					   * @returns 
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  static b64_to_b64u(b64='') {
 | 
					  static b64_to_b64t(b64='') {
 | 
				
			||||||
    return b64.replace(/\+/g, '.').replace(/\//g, '_').replace(/=/g, '')
 | 
					    return b64.replace(/\+/g, '.').replace(/\//g, '_').replace(/=/g, '')
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static b64u_to_b64(b64u='') {
 | 
					  static b64t_to_b64(b64t='') {
 | 
				
			||||||
    return b64u.replace(/\./g, '+').replace(/_/g, '/')
 | 
					    return b64t.replace(/\./g, '+').replace(/_/g, '/')
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * 十六进制转b64u
 | 
					   * 十六进制转b64t
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
   * @static
 | 
					   * @static
 | 
				
			||||||
   * @param {*} hex
 | 
					   * @param {*} hex
 | 
				
			||||||
   * @return {*}
 | 
					   * @return {*}
 | 
				
			||||||
   * @memberof TICrypto
 | 
					   * @memberof TICrypto
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  static hex2b64u(hex) {
 | 
					  static hex_to_b64t(hex) {
 | 
				
			||||||
    if (/^[0-9a-fA-F]+$/.test(hex)) {
 | 
					    if (/^[0-9a-fA-F]+$/.test(hex)) {
 | 
				
			||||||
      return this.b64_to_b64u(Buffer.from(hex, 'hex').toString('base64'))
 | 
					      return this.b64_to_b64t(Buffer.from(hex, 'hex').toString('base64'))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return null
 | 
					    return null
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * b64u转16进制
 | 
					   * b64t转16进制
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
   * @static
 | 
					   * @static
 | 
				
			||||||
   * @param {*} b64u
 | 
					   * @param {*} b64t
 | 
				
			||||||
   * @return {*}
 | 
					   * @return {*}
 | 
				
			||||||
   * @memberof TICrypto
 | 
					   * @memberof TICrypto
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  static b64u2hex(b64u) {
 | 
					  static b64t_to_hex(b64t) {
 | 
				
			||||||
    if (/^[0-9a-zA-Z\._]+$/.test(b64u)) {
 | 
					    if (/^[0-9a-zA-Z\._]+$/.test(b64t)) {
 | 
				
			||||||
      return Buffer.from(this.b64u_to_b64(b64u), 'base64').toString('hex')
 | 
					      return Buffer.from(this.b64t_to_b64(b64t), 'base64').toString('hex')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return null
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // https://en.wikipedia.org/wiki/Base32
 | 
				
			||||||
 | 
					  static hex_to_b32(hex, {encoding='RFC4648'}={}) {
 | 
				
			||||||
 | 
					    if (/^[0-9a-fA-F]+$/.test(hex)) {
 | 
				
			||||||
 | 
					      return base32encode(Buffer.from(hex, 'hex'), encoding)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return null
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  static b32_to_hex(b32, {encoding='RFC4648'}={}) {
 | 
				
			||||||
 | 
					    if (/^[A-Za-z2-7=]+$/.test(b32)) {
 | 
				
			||||||
 | 
					      return Buffer.from(base32decode(b32.toUpperCase(), encoding)).toString('hex')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return null
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  static hex_to_b32h(hex, {encoding='RFC4648-HEX'}={}) {
 | 
				
			||||||
 | 
					    if (/^[0-9a-fA-F]+$/.test(hex)) {
 | 
				
			||||||
 | 
					      return base32encode(Buffer.from(hex, 'hex'), encoding)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return null
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  static b32h_to_hex(b32, {encoding='RFC4648-HEX'}={}) {
 | 
				
			||||||
 | 
					    if (/^[0-9A-Va-v=]+$/.test(b32)) {
 | 
				
			||||||
 | 
					      return Buffer.from(base32decode(b32.toUpperCase(), encoding)).toString('hex')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return null
 | 
					    return null
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -1307,8 +1335,8 @@ class TICrypto {
 | 
				
			|||||||
   * @return {*}
 | 
					   * @return {*}
 | 
				
			||||||
   * @memberof TICrypto
 | 
					   * @memberof TICrypto
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  static hex2eip55(hex) {
 | 
					  static hex_to_eip55(hex) {
 | 
				
			||||||
    if (/^(0x)?[\da-fA-F]*$/.test(hex)) {
 | 
					    if (/^(0x)?[\da-fA-F]+$/.test(hex)) {
 | 
				
			||||||
      hex = hex.toLowerCase().replace('0x', '')
 | 
					      hex = hex.toLowerCase().replace('0x', '')
 | 
				
			||||||
      let hash = keccak('keccak256').update(hex).digest('hex')
 | 
					      let hash = keccak('keccak256').update(hex).digest('hex')
 | 
				
			||||||
      let result = ''
 | 
					      let result = ''
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,8 @@
 | 
				
			|||||||
  "version": "0.1.0",
 | 
					  "version": "0.1.0",
 | 
				
			||||||
  "private": true,
 | 
					  "private": true,
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "base32-decode": "^1.0.0",
 | 
				
			||||||
 | 
					    "base32-encode": "^1.2.0",
 | 
				
			||||||
    "big-integer": "^1.6.48",
 | 
					    "big-integer": "^1.6.48",
 | 
				
			||||||
    "bip39": "^3.0.2",
 | 
					    "bip39": "^3.0.2",
 | 
				
			||||||
    "bs58check": "^2.1.2",
 | 
					    "bs58check": "^2.1.2",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								test.js
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								test.js
									
									
									
									
									
								
							@ -76,7 +76,7 @@ console.log('address = ', add)
 | 
				
			|||||||
/////////////////////// keyutil
 | 
					/////////////////////// keyutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let seckeyObject = new keyutil.Key('oct', Buffer.from(acc.seckey, 'hex'), {namedCurve:'P-256K'}) // {P-256 : secp256r1, P-384 : secp384r1, P-521 : secp521r1, P-256K : secp256k1}
 | 
					let seckeyObject = new keyutil.Key('oct', Buffer.from(acc.seckey, 'hex'), {namedCurve:'P-256K'}) // {P-256 : secp256r1, P-384 : secp384r1, P-521 : secp521r1, P-256K : secp256k1}
 | 
				
			||||||
let seckeyObject2 = new keyutil.Key('oct', tic.hex2buf(acc.seckey, 'hex'), {namedCurve:'P-256K'}) 
 | 
					let seckeyObject2 = new keyutil.Key('oct', tic.hex_to_buf(acc.seckey, 'hex'), {namedCurve:'P-256K'}) 
 | 
				
			||||||
let seckeyPEM
 | 
					let seckeyPEM
 | 
				
			||||||
seckeyObject.export('pem').then(data=>seckeyPEM=data)
 | 
					seckeyObject.export('pem').then(data=>seckeyPEM=data)
 | 
				
			||||||
let seckeyDER
 | 
					let seckeyDER
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user