@secrez/crypto
Advanced tools
Comparing version 0.1.4 to 1.0.0
{ | ||
"name": "@secrez/crypto", | ||
"version": "0.1.4", | ||
"version": "1.0.0", | ||
"license": "MIT", | ||
@@ -13,14 +13,14 @@ "publishConfig": { | ||
"test": "cross-env NODE_ENV=test nyc --reporter=lcov --reporter=text ./node_modules/.bin/_mocha test/*.test.js test/**/*.test.js --exit", | ||
"posttest": "nyc check-coverage --statements 99 --branches 90 --functions 99 --lines 99" | ||
"posttest": "nyc check-coverage --statements 99 --branches 85 --functions 99 --lines 99" | ||
}, | ||
"dependencies": { | ||
"base-x": "^3.0.8", | ||
"bip39": "^3.0.2", | ||
"byte-base64": "^1.1.0", | ||
"microseconds": "^0.2.0", | ||
"sha3": "^2.1.2", | ||
"shamir": "^0.7.1", | ||
"tweetnacl": "^1.0.3", | ||
"tweetnacl-util": "^0.15.1" | ||
"tweetnacl": "^1.0.3" | ||
}, | ||
"devDependencies": { | ||
"@secrez/utils": "~0.1.6", | ||
"@secrez/utils": "~1.0.0", | ||
"chai": "^4.2.0", | ||
@@ -27,0 +27,0 @@ "cross-env": "^7.0.2", |
@@ -28,10 +28,16 @@ # @secrez/crypto | ||
``` | ||
32 passing (2s) | ||
33 passing (734ms) | ||
2 pending | ||
----------|---------|----------|---------|---------|------------------- | ||
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s | ||
----------|---------|----------|---------|---------|------------------- | ||
All files | 100 | 91.38 | 100 | 100 | | ||
index.js | 100 | 91.38 | 100 | 100 | 27-34,71,112,172 | ||
----------|---------|----------|---------|---------|------------------- | ||
----------|---------|----------|---------|---------|-------------------------------------- | ||
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s | ||
----------|---------|----------|---------|---------|-------------------------------------- | ||
All files | 100 | 86.9 | 100 | 100 | | ||
index.js | 100 | 86.9 | 100 | 100 | 42-53,82,108-134,184-185,204,354-358 | ||
----------|---------|----------|---------|---------|-------------------------------------- | ||
> @secrez/crypto@1.0.0 posttest /Users/sullof/Projects/Personal/secrez/packages/crypto | ||
> nyc check-coverage --statements 99 --branches 85 --functions 99 --lines 99 | ||
``` | ||
@@ -38,0 +44,0 @@ |
211
src/index.js
const crypto = require('crypto') | ||
const util = require('util') | ||
const {Keccak} = require('sha3') | ||
const basex = require('base-x') | ||
const shamir = require('shamir') | ||
const bip39 = require('bip39') | ||
const {bytesToBase64, base64ToBytes} = require('byte-base64') | ||
const {TextEncoder, TextDecoder} = require('util') | ||
const utf8Encoder = new TextEncoder() | ||
const utf8Decoder = new TextDecoder() | ||
const μs = require('microseconds') | ||
const SAFE_ENC = { | ||
'+': '-', | ||
'/': '_', | ||
'=': '' | ||
} | ||
const SAFE_DEC = { | ||
'-': '+', | ||
_: '/' | ||
} | ||
const { | ||
@@ -15,7 +29,4 @@ box, | ||
const { | ||
decodeUTF8, | ||
encodeUTF8 | ||
} = require('tweetnacl-util') | ||
class Crypto { | ||
@@ -27,2 +38,6 @@ | ||
static fromBase64(data) { | ||
return Buffer.from(data, 'base64').toString('utf-8') | ||
} | ||
static toBase58(data) { | ||
@@ -35,2 +50,6 @@ if (!Buffer.isBuffer(data)) { | ||
static fromBase58(data) { | ||
return Crypto.bs58.decode(data) | ||
} | ||
static toBase32(data) { | ||
@@ -43,10 +62,2 @@ if (!Buffer.isBuffer(data)) { | ||
static fromBase64(data) { | ||
return Buffer.from(data, 'base64').toString('utf-8') | ||
} | ||
static fromBase58(data) { | ||
return Crypto.bs58.decode(data) | ||
} | ||
static fromBase32(data) { | ||
@@ -86,10 +97,2 @@ return Crypto.bs32.decode(data) | ||
static getMnemonic() { | ||
return bip39.entropyToMnemonic(crypto.randomBytes(16).toString('hex')) | ||
} | ||
static async getSeed(recoveryCode) { | ||
return await bip39.mnemonicToSeed(recoveryCode) | ||
} | ||
static SHA3(data) { | ||
@@ -116,2 +119,6 @@ const hash = new Keccak(256) | ||
static b64Hash(data, size) { | ||
return Crypto.bs64.encode(Crypto.SHA3(data)).substring(0, size) | ||
} | ||
static b32Hash(data, size) { | ||
@@ -159,5 +166,9 @@ if (!Buffer.isBuffer(data)) { | ||
static generateKey(noEncode) { | ||
static generateKey(noEncode, codec = 'bs64') { | ||
let key = randomBytes(secretbox.keyLength) | ||
return noEncode ? key : Crypto.bs58.encode(Buffer.from(key)) | ||
/* istanbul ignore if */ | ||
if (codec === 'bs58') { | ||
key = Buffer.from(key) | ||
} | ||
return noEncode ? key : Crypto[codec].encode(key) | ||
} | ||
@@ -179,9 +190,14 @@ | ||
static encryptUint8Array(messageUint8, key, nonce = Crypto.randomBytes(secretbox.nonceLength), getNonce, noEncode) { | ||
const keyUint8Array = Crypto.bs58.decode(key) | ||
static encrypt(message, key, nonce = Crypto.randomBytes(secretbox.nonceLength), getNonce, returnUint8Array, codec = 'bs64') { | ||
let messageUint8 = Buffer.isBuffer(message) ? new Uint8Array(message) : typeof message === 'string' ? Crypto.utf8ToArray(message) : message | ||
const keyUint8Array = typeof key === 'string' ? Crypto[codec].decode(key) : key | ||
const box = secretbox(messageUint8, nonce, keyUint8Array) | ||
const fullMessage = new Uint8Array(nonce.length + box.length) | ||
let fullMessage = new Uint8Array(nonce.length + box.length) | ||
fullMessage.set(nonce) | ||
fullMessage.set(box, nonce.length) | ||
const encoded = noEncode ? fullMessage : Crypto.bs58.encode(Buffer.from(fullMessage)) | ||
/* istanbul ignore if */ | ||
if (codec === 'bs58') { | ||
fullMessage = Buffer.from(fullMessage) | ||
} | ||
const encoded = returnUint8Array ? fullMessage : Crypto[codec].encode(fullMessage) | ||
if (getNonce) { | ||
@@ -194,13 +210,9 @@ return [nonce, encoded] | ||
static encrypt(message, key, nonce = Crypto.randomBytes(secretbox.nonceLength), getNonce, returnUint8Array) { | ||
return Crypto.encryptUint8Array(decodeUTF8(message), key, nonce, getNonce, returnUint8Array) | ||
} | ||
static encryptBuffer(buf, key, nonce = Crypto.randomBytes(secretbox.nonceLength), getNonce, returnUint8Array) { | ||
return Crypto.encryptUint8Array(new Uint8Array(buf), key, nonce, getNonce, returnUint8Array) | ||
} | ||
static decryptUint8Array(messageWithNonceAsUint8Array, key, returnUint8Array) { | ||
const keyUint8Array = Crypto.bs58.decode(key) | ||
const nonce = messageWithNonceAsUint8Array.slice(0, secretbox.nonceLength) | ||
static decrypt(messageWithNonce, key, returnUint8Array, codec = 'bs64') { | ||
const messageWithNonceAsUint8Array = typeof messageWithNonce === 'string' ? Crypto[codec].decode(messageWithNonce) : messageWithNonce | ||
const keyUint8Array = typeof key === 'string' ? Crypto[codec].decode(key) : key | ||
const nonce = messageWithNonceAsUint8Array.slice( | ||
0, | ||
secretbox.nonceLength | ||
) | ||
const message = messageWithNonceAsUint8Array.slice( | ||
@@ -211,16 +223,12 @@ secretbox.nonceLength, | ||
const decrypted = secretbox.open(message, nonce, keyUint8Array) | ||
/* istanbul ignore if */ | ||
if (!decrypted) { | ||
throw new Error('Could not decrypt message') | ||
} | ||
return returnUint8Array ? decrypted : encodeUTF8(decrypted) | ||
return returnUint8Array ? decrypted : Crypto.arrayToUtf8(decrypted) | ||
} | ||
static decrypt(messageWithNonce, key, returnUint8Array) { | ||
return Crypto.decryptUint8Array(Crypto.bs58.decode(messageWithNonce), key, returnUint8Array) | ||
} | ||
static getNonceFromMessage(messageWithNonce) { | ||
const messageWithNonceAsUint8Array = Crypto.bs58.decode(messageWithNonce) | ||
let nonce = messageWithNonceAsUint8Array.slice(0, secretbox.nonceLength) | ||
return Crypto.hexToUint8Array(nonce.toString('hex')) | ||
static getNonceFromMessage(messageWithNonce, codec = 'bs64') { | ||
return Crypto[codec].decode(messageWithNonce).slice(0, secretbox.nonceLength) | ||
} | ||
@@ -271,4 +279,4 @@ | ||
static boxEncrypt(secretOrSharedKey, message, key, nonce = randomBytes(box.nonceLength), getNonce) { | ||
const messageUint8 = decodeUTF8(message) | ||
static boxEncrypt(secretOrSharedKey, message, key, nonce = randomBytes(box.nonceLength), getNonce, codec = 'bs64') { | ||
const messageUint8 = Crypto.utf8ToArray(message) | ||
const encrypted = key | ||
@@ -278,7 +286,10 @@ ? box(messageUint8, nonce, key, secretOrSharedKey) | ||
const fullMessage = new Uint8Array(nonce.length + encrypted.length) | ||
let fullMessage = new Uint8Array(nonce.length + encrypted.length) | ||
fullMessage.set(nonce) | ||
fullMessage.set(encrypted, nonce.length) | ||
const encoded = Crypto.bs58.encode(Buffer.from(fullMessage)) | ||
/* istanbul ignore if */ | ||
if (codec === 'bs58') { | ||
fullMessage = Buffer.from(fullMessage) | ||
} | ||
const encoded = Crypto[codec].encode(fullMessage) | ||
if (getNonce) { | ||
@@ -291,4 +302,4 @@ return [nonce, encoded] | ||
static boxDecrypt(secretOrSharedKey, messageWithNonce, key) { | ||
const messageWithNonceAsUint8Array = Crypto.bs58.decode(messageWithNonce) | ||
static boxDecrypt(secretOrSharedKey, messageWithNonce, key, codec = 'bs64') { | ||
const messageWithNonceAsUint8Array = Crypto[codec].decode(messageWithNonce) | ||
const nonce = messageWithNonceAsUint8Array.slice(0, box.nonceLength) | ||
@@ -302,23 +313,34 @@ const message = messageWithNonceAsUint8Array.slice( | ||
: box.open.after(message, nonce, secretOrSharedKey) | ||
/* istanbul ignore if */ | ||
if (!decrypted) { | ||
throw new Error('Could not decrypt message') | ||
} | ||
return encodeUTF8(decrypted) | ||
return Crypto.arrayToUtf8(decrypted) | ||
} | ||
static getSignature(message, secretKey) { | ||
let signature = sign.detached(decodeUTF8(message), secretKey) | ||
return Crypto.bs58.encode(Buffer.from(signature)) | ||
static getSignature(message, secretKey, codec = 'bs64') { | ||
let signature = sign.detached(Crypto.utf8ToArray(message), secretKey) | ||
/* istanbul ignore if */ | ||
if (codec === 'bs58') { | ||
signature = Buffer.from(signature) | ||
} | ||
return Crypto[codec].encode(signature) | ||
} | ||
static verifySignature(message, signature, publicKey) { | ||
let verified = sign.detached.verify(decodeUTF8(message), Crypto.bs58.decode(signature), publicKey) | ||
static verifySignature(message, signature, publicKey, codec = 'bs64') { | ||
let verified = sign.detached.verify(Crypto.utf8ToArray(message), Crypto[codec].decode(signature), publicKey) | ||
return verified | ||
} | ||
static utf8ToArray(bytes) { | ||
return utf8Encoder.encode(bytes) | ||
} | ||
static arrayToUtf8(bytes) { | ||
return utf8Decoder.decode(bytes) | ||
} | ||
static splitSecret(secretBytes, parts, quorum) { | ||
if (!Crypto.isUint8Array(secretBytes)) { | ||
const utf8Encoder = new util.TextEncoder() | ||
secretBytes = utf8Encoder.encode(secretBytes) | ||
secretBytes = Crypto.utf8ToArray(secretBytes) | ||
} | ||
@@ -329,7 +351,55 @@ return shamir.split(Crypto.randomBytes, parts, quorum, secretBytes) | ||
static joinSecret(parts, asUint8Array) { | ||
const utf8Decoder = new util.TextDecoder() | ||
const recovered = shamir.join(parts) | ||
return asUint8Array ? recovered : utf8Decoder.decode(recovered) | ||
return asUint8Array ? recovered : Buffer.from(recovered).toString('utf8') | ||
} | ||
static getSignPublicKeyFromSecretPublicKey(publicKey) { | ||
return Crypto.bs64.decode(publicKey.split('$')[1]) | ||
} | ||
static getBoxPublicKeyFromSecretPublicKey (publicKey) { | ||
return Crypto.bs64.decode(publicKey.split('$')[0]) | ||
} | ||
static isValidSecrezPublicKey (pk) { | ||
if (typeof pk === 'string') { | ||
try { | ||
const [boxPublicKey, signPublicKey] = pk.split('$').map(e => { | ||
e = Crypto.bs64.decode(e) | ||
if (Crypto.isValidPublicKey(e)) { | ||
return e | ||
} | ||
}) | ||
if (boxPublicKey && signPublicKey) { | ||
return true | ||
} | ||
} catch (e) { | ||
} | ||
} | ||
return false | ||
} | ||
static getTimestampWithMicroseconds () { | ||
let now = Date.now() | ||
let tmp = [Math.floor(now / 1000), μs.parse(μs.now()).microseconds.toString()] | ||
tmp[1] = parseInt(now.toString().substr(-3) + '0'.repeat(3 - tmp[1].length) + tmp[1]) | ||
return tmp | ||
} | ||
static fromTsToDate(ts) { | ||
let [seconds, microseconds] = ts.split('.') | ||
let milliseconds = microseconds.substring(0, 3) | ||
let timestamp = parseInt(seconds) * 1000 + parseInt(milliseconds) | ||
return [(new Date(timestamp)).toISOString(), parseInt(microseconds.substring(3))] | ||
} | ||
static fromBase64ToFsSafeBase64 (base64 ) { | ||
return base64.replace(/[+/=]/g, (m) => SAFE_ENC[m]) | ||
} | ||
static fromFsSafeBase64ToBase64 (safeBase64 ) { | ||
for (let i = 1; i < safeBase64.length % 4; i++) safeBase64 += '=' | ||
return safeBase64.replace(/[-_]/g, (m) => SAFE_DEC[m]) | ||
} | ||
} | ||
@@ -343,4 +413,15 @@ | ||
Crypto.bs64 = { | ||
encode: data => { | ||
return bytesToBase64(data) | ||
}, | ||
decode: data => { | ||
return base64ToBytes(data) | ||
} | ||
} | ||
Crypto.randomBytes = randomBytes | ||
module.exports = Crypto |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
94428
346
1
52
+ Addedbyte-base64@^1.1.0
+ Addedmicroseconds@^0.2.0
+ Addedbyte-base64@1.1.0(transitive)
+ Addedmicroseconds@0.2.0(transitive)
- Removedbip39@^3.0.2
- Removedtweetnacl-util@^0.15.1
- Removed@noble/hashes@1.5.0(transitive)
- Removedbip39@3.1.0(transitive)
- Removedtweetnacl-util@0.15.1(transitive)