From 97d209b0db1cbfecf801410188eb4adc6617cd9c Mon Sep 17 00:00:00 2001 From: CMEONE Date: Sun, 14 Nov 2021 15:59:52 -0800 Subject: [PATCH] Add documentation, fix bugs --- README.md | 365 +++++++++++++++++++++++++++++++++++++++++++++++-- node/tenvoy.js | 139 +++++-------------- tenvoy.js | 177 ++++++++---------------- 3 files changed, 439 insertions(+), 242 deletions(-) diff --git a/README.md b/README.md index 3e32a118..29fb8be9 100644 --- a/README.md +++ b/README.md @@ -115,21 +115,21 @@ For browsers only, a static `window` property contains an instance of tEnvoy by const envoy = window.TogaTech.tEnvoy; // tEnvoy {...} ``` **Parameters:** -- openpgp (optional, default: `openpgp`): Object (`openpgp`) - a valid instance of OpenPGP.js (https://github.com/openpgpjs/openpgpjs), `openpgp` is added by default in `tenvoy.js`, but this parameter can be used to provide a modified version of `openpgp` or a polyfill -- nacl (optional, default: `nacl`): Object (`nacl`) - a valid instance of TweetNaCl.js (https://github.com/dchest/tweetnacl-js), `nacl` is added by default in `tenvoy.js`, but this parameter can be used to provide a modified version of `nacl` or a polyfill -- sha256 (optional, default: `sha256`): Object (`sha256`) - a valid instance of fasth-sha256-js (https://github.com/dchest/fast-sha256-js), `sha256` is added by default in `tenvoy.js`, but this parameter can be used to provide a modified version of `sha256` or a polyfill +- openpgp (optional, default: `openpgp`): Object (`openpgp`) - a valid instance of [OpenPGP.js](https://github.com/openpgpjs/openpgpjs), `openpgp` is added by default in `tenvoy.js`, but this parameter can be used to provide a modified version of `openpgp` or a polyfill +- nacl (optional, default: `nacl`): Object (`nacl`) - a valid instance of [TweetNaCl.js](https://github.com/dchest/tweetnacl-js), `nacl` is added by default in `tenvoy.js`, but this parameter can be used to provide a modified version of `nacl` or a polyfill +- sha256 (optional, default: `sha256`): Object (`sha256`) - a valid instance of [fast-sha256-js](https://github.com/dchest/fast-sha256-js), `sha256` is added by default in `tenvoy.js`, but this parameter can be used to provide a modified version of `sha256` or a polyfill **Returns:** tEnvoy (`tEnvoy {...}`) - the instance of tEnvoy ### wordsList Gets or sets the [BIP39 English wordlist](https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt) as an array of 2048 words, used to generate random words or back up/restore NaCl-based keys ```javascript -let dictionary = envoy.dictionary; // (2048) ['abandon', 'ability', 'able', 'about', ...] -envoy.dictionary = ['abandon', 'ability', 'able', 'about', ...]; +let wordsList = envoy.wordsList; // (2048) ['abandon', 'ability', 'able', 'about', ...] +envoy.wordsList = ['abandon', 'ability', 'able', 'about', ...]; ``` **Type:** Array (`(2048) ['abandon', 'ability', 'able', 'about', ...]`) -**Warning: It is not recommended to modify envoy.dictionary.** +**Warning: It is not recommended to modify envoy.wordsList.** ### version Gets the version (read-only) of tEnvoy @@ -166,7 +166,7 @@ let sha256 = envoy.core.sha256; // {...} ### util.utf8encode Encodes a string into a UTF-8 bytes array ```javascript -let bytes = envoy.util.utf8encode("test") // Uint8Array(4) [116, 101, 115, 116] +let bytes = envoy.util.utf8encode("test"); // Uint8Array(4) [116, 101, 115, 116] ``` **Parameters:** - string (required): string (`"test"`) - the string to encode @@ -176,102 +176,439 @@ let bytes = envoy.util.utf8encode("test") // Uint8Array(4) [116, 101, 115, 116] ### util.utf8decode Decodes a UTF-8 bytes array into a string ```javascript -let string = envoy.util.utf8decode(new Uint8Array([116, 101, 115, 116])) // "test" +let string = envoy.util.utf8decode(new Uint8Array([116, 101, 115, 116])); // "test" ``` **Parameters:** -- bytes (required): Uint8Array (`Uint8Array(4) [116, 101, 115, 116]`) - the bytes to decode +- bytes (required): Uint8Array or Array (`Uint8Array(4) [116, 101, 115, 116]`) - the bytes to decode **Returns:** string (`"test"`) - the UTF-8 decoded string ### util.stringToBytes Encodes a string into a bytes array ```javascript -let bytes = envoy.util.stringToBytes("test") // Uint8Array(4) [116, 101, 115, 116] +let bytes = envoy.util.stringToBytes("test"); // Uint8Array(4) [116, 101, 115, 116] ``` **Parameters:** - string (required): string (`"test"`) - the string to encode **Returns:** Uint8Array (`Uint8Array(4) [116, 101, 115, 116]`) - the encoded bytes -**Warning: While this method is similar to [util.utf8encode](#util-utf8encode), it does not handle UTF-8 encoding for characters outside of the 8 byte range, causing unexpected outputs for UTF-8 characters.** +**Warning: While this method is similar to [util.utf8encode](#util-utf8encode), it does not handle UTF-8 encoding for characters outside of the 8 bit range, causing unexpected outputs for UTF-8 characters.** ### util.bytesToString Decodes a bytes array into a string ```javascript -let string = envoy.util.utf8decode(new Uint8Array([116, 101, 115, 116])) // "test" +let string = envoy.util.utf8decode(new Uint8Array([116, 101, 115, 116])); // "test" ``` **Parameters:** -- bytes (required): Uint8Array (`Uint8Array(4) [116, 101, 115, 116]`) - the bytes to decode +- bytes (required): Uint8Array or Array (`Uint8Array(4) [116, 101, 115, 116]`) - the bytes to decode **Returns:** string (`"test"`) - the decoded string -**Warning: While this method is similar to [util.utf8decode](#util-utf8decode), it does not handle UTF-8 decoding for characters outside of the 8 byte range, causing unexpected outputs for UTF-8 characters.** +**Warning: While this method is similar to [util.utf8decode](#util-utf8decode), it does not handle UTF-8 decoding for characters outside of the 8 bit range, causing unexpected outputs for UTF-8 characters.** ### util.stringToHex +Encodes a string into hexadecimal +```javascript +let hex = envoy.util.stringToHex("testing"); // "74657374696e67" +``` +**Parameters:** +- string (required): string (`"testing"`) - the string to encode + +**Returns:** string (`"74657374696e67"`) - the encoded hexadecimal ### util.hexToString +Decodes hexadecimal into a string +```javascript +let hex = envoy.util.hexToString("74657374696e67"); // "testing" +``` +**Parameters:** +- hex (required): string (`"74657374696e67"`) - the hexadecimal to decode + +**Returns:** string (`"testing"`) - the decoded string ### util.bytesToHex +Encodes a bytes array into hexadecimal +```javascript +let hex = envoy.util.bytesToHex(new Uint8Array([116, 101, 115, 116, 105, 110, 103])); // "74657374696e67" +``` +**Parameters:** +- bytes (required): Uint8Array or Array (`new Uint8Array([116, 101, 115, 116, 105, 110, 103])`) - the bytes to encode + +**Returns:** string (`"74657374696e67"`) - the encoded hexadecimal ### util.hexToBytes +Decodes hexadecimal into a bytes array +```javascript +let hex = envoy.util.hexToBytes("74657374696e67"); // Uint8Array(7) [116, 101, 115, 116, 105, 110, 103] +``` +**Parameters:** +- hex (required): string (`"74657374696e67"`) - the hexadecimal to decode + +**Returns:** Uint8Array (`Uint8Array(7) [116, 101, 115, 116, 105, 110, 103]`) - the decoded bytes ### util.arrayDeepCopy +Copies an array and all subarrays to a new array +```javascript +let copy = envoy.util.arrayDeepCopy([1, [2, 3], new Uint8Array([4, 5]), 6]); // [1, [2, 3], Uint8Array(2) [4, 5], 6] +``` +**Parameters:** +- hex (required): string (`"74657374696e67"`) - the hexadecimal to decode + +**Returns:** Uint8Array (`Uint8Array(7) [116, 101, 115, 116, 105, 110, 103]`) - the decoded bytes ### util.compareConstant +Compares two arguments for index-based equality in almost constant time +```javascript +let equals1 = envoy.util.compareConstant([1, 2], [1, 2]); // true +let equals2 = envoy.util.compareConstant([1, 2], [3, 2]); // false +let equals3 = envoy.util.compareConstant(new Uint8Array([1, 2]), [1, 2]); // true +let equals4 = envoy.util.compareConstant(new Uint16Array([1, 2]), new Uint8Array([1, 2])); // true +let equals5 = envoy.util.compareConstant("test", "test"); // true +let equals6 = envoy.util.compareConstant("test", ["t", "e", "s", "t"]); // true +let equals7 = envoy.util.compareConstant("test", "testing"); // false +``` +**Parameters:** +- inputted (required): string or Array or Uint8Array or any index-based object (`[1, 2]`) - the user-inputted argument for comparison +- original (required): string or Array or Uint8Array or any index-based object (`[1, 2]`) - the stored argument to check the user-inputted argument against + +**Returns:** boolean (`true`) - whether the index-based objects are equal (`==`) at every index and have the same length ### util.mixedToUint8Array +Converts any type to a Uint8Array +```javascript +let uint8array1 = envoy.util.mixedToUint8Array(null); // null +let uint8array3 = envoy.util.mixedToUint8Array(new Uint8Array([1, 2])); // Uint8Array(2) [1, 2] +let uint8array2 = envoy.util.mixedToUint8Array({0: 1, 1: 2}); // Uint8Array(2) [1, 2] +let uint8array4 = envoy.util.mixedToUint8Array([1, 2]); // Uint8Array(2) [1, 2] +let uint8array5 = envoy.util.mixedToUint8Array(1); // Uint8Array(1) [1] +let uint8array6 = envoy.util.mixedToUint8Array(256); // Uint8Array(2) [1, 0] +let uint8array7 = envoy.util.mixedToUint8Array(0); // Uint8Array(1) [0] +let uint8array8 = envoy.util.mixedToUint8Array(-1); // Uint8Array(1) [1] +let uint8array9 = envoy.util.mixedToUint8Array(-256); // Uint8Array(2) [1, 0] +let uint8array10 = envoy.util.mixedToUint8Array(NaN); // Uint8Array(1) [0] +let uint8array11 = envoy.util.mixedToUint8Array(1.1); // Uint8Array(3) [49, 46, 49] +let uint8array12 = envoy.util.mixedToUint8Array(Infinity); // Uint8Array(1) [255] +let uint8array13 = envoy.util.mixedToUint8Array([256, 257]); // Uint8Array(9) [91, 50, 53, 54, 44, 50, 53, 55, 93] +let uint8array14 = envoy.util.mixedToUint8Array(["t", "e", "s", "t"]); // Uint8Array(17) [91, 34, 116, 34, 44, 34, 101, 34, 44, 34, 115, 34, 44, 34, 116, 34, 93] +let uint8array15 = envoy.util.mixedToUint8Array({"t": "e", "s": "t"}); // Uint8Array(17) [123, 34, 116, 34, 58, 34, 101, 34, 44, 34, 115, 34, 58, 34, 116, 34, 125] +let uint8array16 = envoy.util.mixedToUint8Array(true); // Uint8Array(1) [1] +let uint8array17 = envoy.util.mixedToUint8Array(false); // Uint8Array(1) [0] +let uint8array18 = envoy.util.mixedToUint8Array(function test() {return "test"}); // Uint8Array(31) [102, 117, 110, 99, 116, 105, 111, 110, 32, 116, 101, 115, 116, 40, 41, 32, 123, 114, 101, 116, 117, 114, 110, 32, 34, 116, 101, 115, 116, 34, 125] +let uint8array19 = envoy.util.mixedToUint8Array("test"); // Uint8Array(4) [116, 101, 115, 116] +let uint8array20 = envoy.util.mixedToUint8Array("test", true); // Uint8Array(5) [254, 116, 101, 115, 116] +let uint8array21 = envoy.util.mixedToUint8Array("test", true, 10); // Uint8Array(10) [255, 255, 255, 255, 255, 254, 116, 101, 115, 116] +``` +**Parameters:** +- mixed (required): any (`[1, 2]`) - the mixed object to convert to a Uint8Array +- includeType (optional, default: `false`): boolean (`false`) - whether to include the type of the original mixed object in the Uint8Array +- length (optional, default: length of return array): number (`2`) - the length of the return array, used to add padding (includeType must be true to use the length argument) + +**Mixed Types:** +- null (`null`) => null (`null`) +- undefined (`undefined`) => undefined (`undefined`) +- Uint8Array (`new Uint8Array([1, 2])`) => Uint8Array (`Uint8Array(2) [1, 2]`) +- Uint8Array-like object (`{0: 1, 1: 2}`) => mapped keys to indices (`Uint8Array(2) [1, 2]`) +- Uint8Array-like Array (`[1, 2]`) => mapped one-to-one Uint8Array (`Uint8Array(2) [1, 2]`) +- Integer number (`256`) => base-256 representation of absolute value of number (`Uint8Array(2) [1, 0]`) +- NaN (`NaN`) => 0 `Uint8Array(1) [0]` +- Decimal number (`1.1`) => UTF-8 encoded string representation of number (`Uint8Array(3) [49, 46, 49]`) +- Infinity (`Infinity`) => 255 (`Uint8Array(1) [255]`) +- Array (`[256, 257]`) => UTF-8 encoded JSON stringified Array (`Uint8Array(9) [91, 50, 53, 54, 44, 50, 53, 55, 93]`) +- JSON object or object with toJSON method (`{"t": "e", "s": "t"}`) => UTF-8 encoded JSON stringified Object (`Uint8Array(17) [123, 34, 116, 34, 58, 34, 101, 34, 44, 34, 115, 34, 58, 34, 116, 34, 125]`) +- true (`true`) => 1 (`Uint8Array(1) [1]`) +- false (`false`) => 0 (`Uint8Array(1) [0]`) +- function (`function test() {return "test"}`) => UTF-8 encoded string representation of function (`Uint8Array(31) [102, 117, 110, 99, 116, 105, 111, 110, 32, 116, 101, 115, 116, 40, 41, 32, 123, 114, 101, 116, 117, 114, 110, 32, 34, 116, 101, 115, 116, 34, 125]`) +- string or other (`"test"`) => UTF-8 encoded string or return value of `toString()` (`Uint8Array(4) [116, 101, 115, 116]`) + +**Included Types:** +- Uint8Array: first non-padding byte is `0` +- Uint8Array-like object: first non-padding byte is `0` (a Uint8Array-like object is considered to be an artifact of an encoding or decoding bug and is treated like a Uint8Array, please add a dummy non-numerical key to bypass this behavior) +- Uint8Array-like Array: first non-padding byte is `1` +- Integer positive number: first non-padding byte is `2` +- Integer negative number: first non-padding byte is `3` +- 0: first non-padding byte is `4` +- NaN: first non-padding byte is `7` +- Decimal number: first non-padding byte is `8` +- Infinity: first non-padding byte is `9` +- Array: first non-padding byte is `5` +- JSON object or object with toJSON method: first non-padding byte is `5` +- true: first non-padding byte is `6` +- false: first non-padding byte is `6` +- function: first non-padding byte is `10` +- string or other: first non-padding byte is `254` +- padding: padding bytes of `255` are added to the beginning of the returned Uint8Array until the specified length is reached, and the returned array will be truncated if the length of the returned array is larger than the specified length. + +**Returns:** Uint8Array (`Uint8Array(2) [1, 2]`) - the converted result as a Uint8Array ### util.uint8ArrayToMixed +Converts a Uint8Array back to an Array or any type (reverse of `util.mixedToUint8Array`) +```javascript +let mixed1 = envoy.util.uint8ArrayToMixed(new Uint8Array([1, 2])); // [1, 2] +let mixed2 = envoy.util.uint8ArrayToMixed(new Uint8Array([255, 255, 255, 255, 255, 254, 116, 101, 115, 116]), true); // "test" +``` +**Parameters:** +- uint8Array (required): Uint8Array or Uint8Array-like array or Uint8Array-like object (`new Uint8Array([1, 2])`) - the Uint8Array to convert to a mixed object +- includeType (optional, default: `false`): boolean (`false`) - whether to use the type of the original mixed object in the converted mixed object + +**Returns:** any (`[1, 2]`) - the converted result as an Array or any type ### util.pack +Alias of `util.mixedToUint8Array(mixed, true, length)` + +**Parameters:** +- mixed (required): any (`[1, 2]`) - the mixed object to convert to a Uint8Array +- length (optional, default: length of return array): number (`2`) - the length of the return array, used to add padding (includeType must be true to use the length argument) + +**Returns:** Uint8Array (`Uint8Array(2) [1, 2]`) - the converted result as a Uint8Array ### util.unpack +Alias of `util.uint8ArrayToMixed(mixed, true)` + +**Parameters:** +- uint8Array (required): Uint8Array or Uint8Array-like array or Uint8Array-like object (`[1, 2]`) - the Uint8Array to convert to a mixed object + +**Returns:** any (`[1, 2]`) - the converted result as an Array or any type ### util.objectEquals +Check whether two JSON objects are equal in almost constant time +```javascript +let equals1 = envoy.util.objectEquals({"t": "e", "s": "t", "i": {"n": "g"}}, {"i": {"n": "g"}, "s": "t", "t": "e"}); // true +let equals2 = envoy.util.objectEquals({"t": "e", "s": "t", "i": {"n": "g"}}, {"i": {"n": "g"}, "t": "e"}); // false +``` +**Parameters:** +- inputted (optional, default: `null`): object (`{"t": "e", "s": "t", "i": {"n": "g"}}`) - the user-inputted argument for comparison +- original (optional, default: `null`): object (`{"i": {"n": "g"}, "s": "t", "t": "e"}`) - the stored argument to check the user-inputted argument against + +**Returns:** boolean (`true`) - whether the objects are equal (`==`) at every key and have the same keys ### util.fixArmor +Internal method used to fix the armored text on a `tEnvoyPGPKey` ## Random ### random.bytes +Generates cryptographically secure random bytes using any available cryptographically secure random number generator +```javascript +(async() => { + let random = await envoy.random.bytes(16); // Uint8Array(16) [104, 37, 240, 56, 174, 137, 249, 10, 46, 185, 52, 135, 172, 39, 150, 21] +})(); +``` +**Parameters:** +- length (optional, default: `1`): number (`16`) - the number of bytes to generate + +**Returns:** Promise fulfilling to Uint8Array (`Uint8Array(16) [104, 37, 240, 56, 174, 137, 249, 10, 46, 185, 52, 135, 172, 39, 150, 21]`) - the cryptographically secure random bytes + +**Note:** If tEnvoy cannot find any available cryptographically secure random number generator on the platform, you can replace this function **at your own risk** by assigning `envoy.random.bytes` to your own custom function. **`random.bytes` is used for all random bytes generation throughout tEnvoy. Do not replace this function unless you are a cryptography expert. If your custom function replacement is insecure, the entire security of tEnvoy will be compromised. We are not in any way responsible or liable for your modifications to tEnvoy.** ### random.number +Generates a cryptographically secure random number using `random.bytes` +```javascript +(async() => { + let number = await envoy.random.number(0, 10); // 8.862745098039216 +})(); +``` +**Parameters:** +- min (optional, default: `0`): number (`0`) - the minimum bound for the number +- max (optional, default: `1`): number (`10`) - the maximum bound for the number + +**Returns:** Promise fulfilling to Decimal number (`8.862745098039216`) - a cryptographically secure random number between the specified minimum and maximum ### random.string +Generates a cryptographically secure random string using `random.number` +```javascript +(async() => { + let string = await envoy.random.string(16); // HLONsJaTcCvI3vRD +})(); +``` +**Parameters:** +- length (optional, default: `10`): number (`16`) - the number of characters to generate + +**Returns:** Promise fulfilling to string (`HLONsJaTcCvI3vRD`) - a cryptographically secure random string of the specified length ### random.words +Generates a cryptographically secure series of random words using `random.number` and the [BIP39 English wordlist](https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt) +```javascript +(async() => { + let words = await envoy.random.words(4); // bright shield latin web +})(); +``` +**Parameters:** +- length (optional, default: `12`): number (`4`) - the number of words to generate + +**Returns:** Promise fulfilling to string (`bright shield latin web`) - a cryptographically secure series of the specified number of random words ## Hashing ### hash +Get the deterministic hash using any hash function in tEnvoy (SHA-256, SHA-1, SHA-224, SHA-384, SHA-512, MD5, RIPEMD-160) +```javascript +(async() => { + let hash = await envoy.hash("test", "sha256"); // 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 +})(); +``` +**Parameters:** +- mixed (required): string or any - the value to hash (encoded into bytes for hashing through `util.mixedToUint8Array(mixed, false)`) +- algorithm (optional, default: `"sha256"`): string - the algorithm to use + +**Algorithms:** +- SHA-256 => `"sha256"` +- SHA-1 => `"sha1"` +- SHA-224 => `"sha224"` +- SHA-384 => `"sha384"` +- SHA-512 => `"sha512"` +- MD5 => `"md5"` +- RIPEMD-160 => `"ripemd160"` + +**Returns:** Promise fulfilling to string (`"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"`) - the hexadecimal representation of the deterministic hash of the specified input using the specified algorithm ### hash.sha256 +Get the deterministic hash using the SHA-256 hash function +```javascript +(async() => { + let hash = await envoy.hash.sha256("test"); // 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 +})(); +``` +**Parameters:** +- mixed (required): string or any - the value to hash (encoded into bytes for hashing through `util.mixedToUint8Array(mixed, false)`) + +**Returns:** Promise fulfilling to string (`"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"`) - the hexadecimal representation of the deterministic hash of the specified input using the SHA-256 algorithm ### hash.sha1 +Get the deterministic hash using the SHA-1 hash function +```javascript +(async() => { + let hash = await envoy.hash.sha1("test"); // a94a8fe5ccb19ba61c4c0873d391e987982fbbd3 +})(); +``` +**Parameters:** +- mixed (required): string or any - the value to hash (encoded into bytes for hashing through `util.mixedToUint8Array(mixed, false)`) + +**Returns:** Promise fulfilling to string (`"a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"`) - the hexadecimal representation of the deterministic hash of the specified input using the SHA-1 algorithm + +**Warning: It is not recommended to use this method, as the SHA-1 algorithm has been broken.** ### hash.sha224 +Get the deterministic hash using the SHA-224 hash function +```javascript +(async() => { + let hash = await envoy.hash.sha224("test"); // 90a3ed9e32b2aaf4c61c410eb925426119e1a9dc53d4286ade99a809 +})(); +``` +**Parameters:** +- mixed (required): string or any - the value to hash (encoded into bytes for hashing through `util.mixedToUint8Array(mixed, false)`) + +**Returns:** Promise fulfilling to string (`"90a3ed9e32b2aaf4c61c410eb925426119e1a9dc53d4286ade99a809"`) - the hexadecimal representation of the deterministic hash of the specified input using the SHA-224 algorithm ### hash.sha384 +Get the deterministic hash using the SHA-384 hash function +```javascript +(async() => { + let hash = await envoy.hash.sha384("test"); // 768412320f7b0aa5812fce428dc4706b3cae50e02a64caa16a782249bfe8efc4b7ef1ccb126255d196047dfedf17a0a9 +})(); +``` +**Parameters:** +- mixed (required): string or any - the value to hash (encoded into bytes for hashing through `util.mixedToUint8Array(mixed, false)`) + +**Returns:** Promise fulfilling to string (`"768412320f7b0aa5812fce428dc4706b3cae50e02a64caa16a782249bfe8efc4b7ef1ccb126255d196047dfedf17a0a9"`) - the hexadecimal representation of the deterministic hash of the specified input using the SHA-384 algorithm ### hash.sha512 +Get the deterministic hash using the SHA-512 hash function +```javascript +(async() => { + let hash = await envoy.hash.sha512("test"); // ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff +})(); +``` +**Parameters:** +- mixed (required): string or any - the value to hash (encoded into bytes for hashing through `util.mixedToUint8Array(mixed, false)`) + +**Returns:** Promise fulfilling to string (`"ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff"`) - the hexadecimal representation of the deterministic hash of the specified input using the SHA-512 algorithm ### hash.md5 +Get the deterministic hash using the MD5 hash function +```javascript +(async() => { + let hash = await envoy.hash.md5("test"); // 098f6bcd4621d373cade4e832627b4f6 +})(); +``` +**Parameters:** +- mixed (required): string or any - the value to hash (encoded into bytes for hashing through `util.mixedToUint8Array(mixed, false)`) + +**Returns:** Promise fulfilling to string (`"098f6bcd4621d373cade4e832627b4f6"`) - the hexadecimal representation of the deterministic hash of the specified input using the MD5 algorithm + +**Warning: It is not recommended to use this method, as the MD5 algorithm has been broken.** ### hash.ripemd160 +Get the deterministic hash using the RIPEMD-160 hash function +```javascript +(async() => { + let hash = await envoy.hash.ripemd160("test"); // 5e52fee47e6b070565f74372468cdc699de89107 +})(); +``` +**Parameters:** +- mixed (required): string or any - the value to hash (encoded into bytes for hashing through `util.mixedToUint8Array(mixed, false)`) + +**Returns:** Promise fulfilling to string (`"5e52fee47e6b070565f74372468cdc699de89107"`) - the hexadecimal representation of the deterministic hash of the specified input using the RIPEMD-160 algorithm ## Key Factory ### keyFactory.pbkdf2 +Generates a key of a certain size from a password and salt through a certain number of rounds through PBKDF2-HMAC-SHA256 (Password-Based Key Derivation Function 2 with SHA-256 Hash-based Message Authentication Code) +```javascript +(async() => { + let bytes = await envoy.keyFactory.pbkdf2("password", "salt", 150000, 32); // Uint8Array(32) [149, 196, 67, 208, 74, 43, 94, 32, 74, 46, 127, 61, 91, 212, 249, 168, 6, 120, 30, 15, 29, 198, 125, 130, 53, 250, 186, 249, 187, 224, 180, 201] +})(); +``` +**Parameters:** +- password (required): string or any - the password to use to generate the key (encoded into bytes for key generation through `util.mixedToUint8Array(password, false)`) +- salt (required): string or any - the salt to use to generate the key (encoded into bytes for key generation through `util.mixedToUint8Array(salt, false)`) +- rounds (optional, default: `150000`): number - the number of rounds to use to generate the key +- size (optional, default: `32`): number - the size of the key in bytes + +**Returns:** the key generated from the specified parameters using PBKDF2-HMAC-SHA256 ### keyFactory.genSeedFromCredentials +Alias of `keyFactory.pbkdf2(password, username, rounds, size)` + +**Parameters:** +- username (required): string or any - the salt to use to generate the key (encoded into bytes for key generation through `util.mixedToUint8Array(username, false)`) +- password (required): string or any - the password to use to generate the key (encoded into bytes for key generation through `util.mixedToUint8Array(password, false)`) +- rounds (optional, default: `150000`): number - the number of rounds to use to generate the key +- size (optional, default: `32`): number - the size of the key in bytes + +**Returns:** the key generated from the specified parameters using PBKDF2-HMAC-SHA256 ### keyFactory.genPGPKeys +Generates an asymmetrical PGP key +```javascript +(async() => { + let keys = await envoy.keyFactory.genPGPKeys(); // {privateKey: tEnvoyPGPKey, publicKey: tEnvoyPGPKey} +})(); +``` ### keyFactory.genPGPSymmetricKey +Generates a symmetrical PGP key +```javascript +(async() => { + let key = await envoy.keyFactory.genPGPSymmetricKey({key: "test"}) // tEnvoyPGPKey {...} +})(); +``` ### keyFactory.genNaClKeys +Generates an asymmetrical NaCl key +```javascript +(async() => { + let keys = await envoy.keyFactory.genNaClKeys(); // {privateKey: tEnvoyNaClKey, publicKey: tEnvoyNaClKey, privateSigningKey: tEnvoyNaClSigningKey, publicSigningKey: tEnvoyNaClSigningKey} +})(); +``` ### keyFactory.genNaClSymmetricKey +Generates a symmetrical NaCl key +```javascript +(async() => { + let key = await envoy.keyFactory.genNaClSymmetricKey({key: "test"}); // tEnvoyNaClKey {...} +})(); +``` ## PGP Keys diff --git a/node/tenvoy.js b/node/tenvoy.js index 24a40c2d..bccc1fe4 100644 --- a/node/tenvoy.js +++ b/node/tenvoy.js @@ -142,10 +142,10 @@ function tEnvoy(openpgpRef = openpgp, naclRef = nacl, sha256Ref = sha256) { } else if(array instanceof Array) { copy = new Array(array.length); } else { - throw "tEnvoy Fatal Error: argument array of method util.arrayDeepCopy is invalid, array must be of type Uint8Array or Array."; + return array; } for(let i = 0; i < array.length; i++) { - copy[i] = array[i]; + copy[i] = this.util.arrayDeepCopy(array[i]); } return copy; } @@ -202,9 +202,6 @@ function tEnvoy(openpgpRef = openpgp, naclRef = nacl, sha256Ref = sha256) { return returnArray; } } - if(mixed == null) { - throw "tEnvoy Fatal Error: argument mixed of method util.mixedToUint8Array is required and does not have a default value."; - } let isObjectArray = true; if(typeof mixed == "object" && mixed.constructor == Object) { let keys = Object.keys(mixed); @@ -217,7 +214,17 @@ function tEnvoy(openpgpRef = openpgp, naclRef = nacl, sha256Ref = sha256) { } } if(isObjectArray) { - return returnUint8Array; + if(includeType) { + let oldReturnUint8Array = returnUint8Array; + returnUint8Array = new Uint8Array(oldReturnUint8Array.length + 1); + returnUint8Array[0] = 0; + for(let i = 0; i < oldReturnUint8Array.length; i++) { + returnUint8Array[i + 1] = oldReturnUint8Array[i]; + } + return pad(returnUint8Array, length); + } else { + return returnUint8Array; + } } } if(mixed instanceof Uint8Array) { @@ -365,7 +372,11 @@ function tEnvoy(openpgpRef = openpgp, naclRef = nacl, sha256Ref = sha256) { let mixedAsUint8Array = this.util.utf8encode(mixed.toString()); if(includeType) { let returnUint8Array = new Uint8Array(mixedAsUint8Array.length + 1); - returnUint8Array[0] = 254; + if(typeof mixed == "function") { + returnUint8Array[0] = 10; + } else { + returnUint8Array[0] = 254; + } for(let i = 0; i < mixedAsUint8Array.length; i++) { returnUint8Array[i + 1] = mixedAsUint8Array[i]; } @@ -454,6 +465,9 @@ function tEnvoy(openpgpRef = openpgp, naclRef = nacl, sha256Ref = sha256) { return parseFloat(this.util.utf8decode(returnUint8Array)); } else if(uint8Array[0] == 9) { return Infinity; + } else if(uint8Array[0] == 10) { + let fakeDecoded = this.util.utf8decode(fakeUint8Array); + return eval("(" + this.util.utf8decode(returnUint8Array) + ")"); } else if(uint8Array[0] == 254) { let fakeDecoded = this.util.utf8decode(fakeUint8Array); return this.util.utf8decode(returnUint8Array); @@ -477,108 +491,23 @@ function tEnvoy(openpgpRef = openpgp, naclRef = nacl, sha256Ref = sha256) { return this.util.uint8ArrayToMixed(packed, true); } - this.util.objectEquals = (object1, object2) => { - let deepCompare = () => { - var i, l, leftChain, rightChain; - let compare2Objects = (x, y) => { - var p; - // remember that NaN === NaN returns false - // and isNaN(undefined) returns true - if(isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') { - return true; - } - - // Compare primitives and functions. - // Check if both arguments link to the same object. - // Especially useful on the step where we compare prototypes - if(x === y) { - return true; - } - - // Works in case when functions are created in constructor. - // Comparing dates is a common scenario. Another built-ins? - // We can even handle functions passed across iframes - if((typeof x === 'function' && typeof y === 'function') || - (x instanceof Date && y instanceof Date) || - (x instanceof RegExp && y instanceof RegExp) || - (x instanceof String && y instanceof String) || - (x instanceof Number && y instanceof Number)) { - return x.toString() === y.toString(); - } - - // At last checking prototypes as good as we can - if(!(x instanceof Object && y instanceof Object)) { - return false; - } - - if(x.isPrototypeOf(y) || y.isPrototypeOf(x)) { - return false; + this.util.objectEquals = (inputted, original) => { + if(typeof inputted == "object" && typeof original == "object") { + let result = true; + let keys_inputted = Object.keys(inputted); + let keys_original = Object.keys(original); + for(let i = 0; i < keys_inputted.length; i++) { + if(!this.util.objectEquals(inputted[keys_inputted[i]], original[keys_inputted[i]])) { + result = false; } - - if(x.constructor !== y.constructor) { - return false; - } - - if(x.prototype !== y.prototype) { - return false; - } - - // Check for infinitive linking loops - if(leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) { - return false; - } - - // Quick checking of one object being a subset of another. - // todo: cache the structure of arguments[0] for performance - for(p in y) { - if(y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { - return false; - } else if(typeof y[p] !== typeof x[p]) { - return false; - } - } - - for(p in x) { - if(y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { - return false; - } else if(typeof y[p] !== typeof x[p]) { - return false; - } - - switch(typeof (x[p])) { - case 'object': - case 'function': - leftChain.push(x); - rightChain.push(y); - if(!compare2Objects (x[p], y[p])) { - return false; - } - leftChain.pop(); - rightChain.pop(); - break; - default: - if(x[p] !== y[p]) { - return false; - } - break; - } - } - return true; - } - if(arguments.length < 1) { - throw "need two or more arguments to compare"; } - for(i = 1, l = arguments.length; i < l; i++) { - leftChain = []; //Todo: this can be cached - rightChain = []; - if(!compare2Objects(arguments[0], arguments[i])) { - return false; - } + if(keys_inputted.length != keys_original.length) { + result = false; } - return true; + return result; + } else { + return inputted == original; } - - return deepCompare(object1, object2); } this.util.fixArmor = (armored) => { diff --git a/tenvoy.js b/tenvoy.js index 31b29a18..b98a98ff 100644 --- a/tenvoy.js +++ b/tenvoy.js @@ -46159,10 +46159,10 @@ function tEnvoy(openpgpRef = openpgp, naclRef = nacl, sha256Ref = sha256) { } else if(array instanceof Array) { copy = new Array(array.length); } else { - throw "tEnvoy Fatal Error: argument array of method util.arrayDeepCopy is invalid, array must be of type Uint8Array or Array."; + return array; } for(let i = 0; i < array.length; i++) { - copy[i] = array[i]; + copy[i] = this.util.arrayDeepCopy(array[i]); } return copy; } @@ -46219,9 +46219,6 @@ function tEnvoy(openpgpRef = openpgp, naclRef = nacl, sha256Ref = sha256) { return returnArray; } } - if(mixed == null) { - throw "tEnvoy Fatal Error: argument mixed of method util.mixedToUint8Array is required and does not have a default value."; - } let isObjectArray = true; if(typeof mixed == "object" && mixed.constructor == Object) { let keys = Object.keys(mixed); @@ -46234,7 +46231,17 @@ function tEnvoy(openpgpRef = openpgp, naclRef = nacl, sha256Ref = sha256) { } } if(isObjectArray) { - return returnUint8Array; + if(includeType) { + let oldReturnUint8Array = returnUint8Array; + returnUint8Array = new Uint8Array(oldReturnUint8Array.length + 1); + returnUint8Array[0] = 0; + for(let i = 0; i < oldReturnUint8Array.length; i++) { + returnUint8Array[i + 1] = oldReturnUint8Array[i]; + } + return pad(returnUint8Array, length); + } else { + return returnUint8Array; + } } } if(mixed instanceof Uint8Array) { @@ -46382,7 +46389,11 @@ function tEnvoy(openpgpRef = openpgp, naclRef = nacl, sha256Ref = sha256) { let mixedAsUint8Array = this.util.utf8encode(mixed.toString()); if(includeType) { let returnUint8Array = new Uint8Array(mixedAsUint8Array.length + 1); - returnUint8Array[0] = 254; + if(typeof mixed == "function") { + returnUint8Array[0] = 10; + } else { + returnUint8Array[0] = 254; + } for(let i = 0; i < mixedAsUint8Array.length; i++) { returnUint8Array[i + 1] = mixedAsUint8Array[i]; } @@ -46471,6 +46482,9 @@ function tEnvoy(openpgpRef = openpgp, naclRef = nacl, sha256Ref = sha256) { return parseFloat(this.util.utf8decode(returnUint8Array)); } else if(uint8Array[0] == 9) { return Infinity; + } else if(uint8Array[0] == 10) { + let fakeDecoded = this.util.utf8decode(fakeUint8Array); + return eval("(" + this.util.utf8decode(returnUint8Array) + ")"); } else if(uint8Array[0] == 254) { let fakeDecoded = this.util.utf8decode(fakeUint8Array); return this.util.utf8decode(returnUint8Array); @@ -46494,108 +46508,23 @@ function tEnvoy(openpgpRef = openpgp, naclRef = nacl, sha256Ref = sha256) { return this.util.uint8ArrayToMixed(packed, true); } - this.util.objectEquals = (object1, object2) => { - let deepCompare = () => { - var i, l, leftChain, rightChain; - let compare2Objects = (x, y) => { - var p; - // remember that NaN === NaN returns false - // and isNaN(undefined) returns true - if(isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') { - return true; + this.util.objectEquals = (inputted, original) => { + if(typeof inputted == "object" && typeof original == "object") { + let result = true; + let keys_inputted = Object.keys(inputted); + let keys_original = Object.keys(original); + for(let i = 0; i < keys_inputted.length; i++) { + if(!this.util.objectEquals(inputted[keys_inputted[i]], original[keys_inputted[i]])) { + result = false; } - - // Compare primitives and functions. - // Check if both arguments link to the same object. - // Especially useful on the step where we compare prototypes - if(x === y) { - return true; - } - - // Works in case when functions are created in constructor. - // Comparing dates is a common scenario. Another built-ins? - // We can even handle functions passed across iframes - if((typeof x === 'function' && typeof y === 'function') || - (x instanceof Date && y instanceof Date) || - (x instanceof RegExp && y instanceof RegExp) || - (x instanceof String && y instanceof String) || - (x instanceof Number && y instanceof Number)) { - return x.toString() === y.toString(); - } - - // At last checking prototypes as good as we can - if(!(x instanceof Object && y instanceof Object)) { - return false; - } - - if(x.isPrototypeOf(y) || y.isPrototypeOf(x)) { - return false; - } - - if(x.constructor !== y.constructor) { - return false; - } - - if(x.prototype !== y.prototype) { - return false; - } - - // Check for infinitive linking loops - if(leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) { - return false; - } - - // Quick checking of one object being a subset of another. - // todo: cache the structure of arguments[0] for performance - for(p in y) { - if(y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { - return false; - } else if(typeof y[p] !== typeof x[p]) { - return false; - } - } - - for(p in x) { - if(y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { - return false; - } else if(typeof y[p] !== typeof x[p]) { - return false; - } - - switch(typeof (x[p])) { - case 'object': - case 'function': - leftChain.push(x); - rightChain.push(y); - if(!compare2Objects (x[p], y[p])) { - return false; - } - leftChain.pop(); - rightChain.pop(); - break; - default: - if(x[p] !== y[p]) { - return false; - } - break; - } - } - return true; - } - if(arguments.length < 1) { - throw "need two or more arguments to compare"; } - for(i = 1, l = arguments.length; i < l; i++) { - leftChain = []; //Todo: this can be cached - rightChain = []; - if(!compare2Objects(arguments[0], arguments[i])) { - return false; - } + if(keys_inputted.length != keys_original.length) { + result = false; } - return true; + return result; + } else { + return inputted == original; } - - return deepCompare(object1, object2); } this.util.fixArmor = (armored) => { @@ -48526,23 +48455,25 @@ function tEnvoyNaClSigningKey(key, type = "secret", password = null, passwordPro TogaTech.tEnvoy = new tEnvoy(openpgp, nacl, sha256); -let message = () => { - console.log("%cPowered by TogaTech (TogaTech.org)\n%cSTOP!%c\nTHE CONSOLE IS INTENDED FOR DEVELOPERS ONLY. USE AT YOUR OWN RISK.\n\nIF SOMEONE TOLD YOU TO TYPE ANYTHING HERE, YOU ARE BEING SCAMMED.%c\nIf you were told to enter any text here, maybe to enable a hidden feature, DO NOT TYPE IT HERE. Doing so could send your password and sensitive data to hackers.\n\nTo learn more, visit togatech.org/selfxss.\n\n%ctEnvoy " + TogaTech.tEnvoy.version, "font-size: 15px;", "color: red; font-size: 50px;", "font-size: 27px;", "font-size: 17px;", "font-size: 12px;"); -} -message(); -setTimeout(() => { - message(); -}, 1000); -setTimeout(() => { - message(); -}, 2000); -setTimeout(() => { - message(); -}, 3000); -setTimeout(() => { - message(); -}, 4000); -setTimeout(() => { +(() => { + let message = () => { + console.log("%cPowered by TogaTech (TogaTech.org)\n%cSTOP!%c\nTHE CONSOLE IS INTENDED FOR DEVELOPERS ONLY. USE AT YOUR OWN RISK.\n\nIF SOMEONE TOLD YOU TO TYPE ANYTHING HERE, YOU ARE BEING SCAMMED.%c\nIf you were told to enter any text here, maybe to enable a hidden feature, DO NOT TYPE IT HERE. Doing so could send your password and sensitive data to hackers.\n\nTo learn more, visit togatech.org/selfxss.\n\n%ctEnvoy " + TogaTech.tEnvoy.version, "font-size: 15px;", "color: red; font-size: 50px;", "font-size: 27px;", "font-size: 17px;", "font-size: 12px;"); + } message(); -}, 5000); + setTimeout(() => { + message(); + }, 1000); + setTimeout(() => { + message(); + }, 2000); + setTimeout(() => { + message(); + }, 3000); + setTimeout(() => { + message(); + }, 4000); + setTimeout(() => { + message(); + }, 5000); +})(); // End tEnvoy.js \ No newline at end of file