ncrypt-js 2.1.2 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # NcryptJs
2
2
 
3
- ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/ajimae/ncrypt-js/release.yml) [![Coverage Status](https://coveralls.io/repos/github/ajimae/ncrypt-js/badge.svg)](https://coveralls.io/github/ajimae/ncrypt-js) ![NPM Downloads](https://img.shields.io/npm/dw/ncrypt-js)
3
+ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/ajimae/ncrypt-js/.github%2Fworkflows%2Fci.yml)
4
+ [![Coverage Status](https://coveralls.io/repos/github/ajimae/ncrypt-js/badge.svg)](https://coveralls.io/github/ajimae/ncrypt-js) ![NPM Downloads](https://img.shields.io/npm/dw/ncrypt-js)
4
5
 
5
6
  [![GitHub release (latest by date)](https://img.shields.io/github/v/release/ajimae/ncrypt-js)](https://github.com/ajimae/ncrypt-js/releases) [![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/ajimae/ncrypt-js)](https://github/languages/code-size/ajimae/ncrypt-js) [![GitHub issues](https://img.shields.io/github/issues/ajimae/ncrypt-js)](https://github.com/ajimae/ncrypt-js/issues) [![NPM](https://img.shields.io/npm/l/ncrypt-js)](https://www.npmjs.com/package/ncrypt-js/v/2.0.0#license)
6
7
 
@@ -16,8 +17,9 @@
16
17
  * [NcryptJs Methods](#ncryptjs-methods)
17
18
  * [Using the `randomString()` methods](#using-randomstring-method)
18
19
  * [Using `encrypt()` and `decrypt()` methods](#using-encrypt-and-decrypt-methods)
19
- * [Stirng Encryption](#string-encryption)
20
+ * [String Encryption](#string-encryption)
20
21
  * [Object Encryption](#object-encryption)
22
+ * [Using password hashing methods](#using-password-hashing-methods)
21
23
  * [Built With](#built-with)
22
24
  * [Contribution](#contribution)
23
25
  * [Version Management](#version-management)
@@ -79,6 +81,9 @@ var { ncrypt } = require("ncrypt-js");
79
81
  | Methods | Description | Parameters | Return |
80
82
  | ------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
81
83
  | [_static_] **randomString()** | Random String. |**size**: _number_ - An optional size of the generated `randomBytes`. <br/>**enc:** _base64/hex_ - Encoding used for encoding the `randomBytes` defaults to _`base64`_ |**encoded**: _string_ - encoded string. |
84
+ | [_static_] **generate()** | Generates a hashed password. |**password**: _string_ - The password to hash. <br/>**options**: _object_ - Optional configuration object (see below). |**hashedPassword**: _string_ - The hashed password string. |
85
+ | [_static_] **verify()** | Verifies a password against a hashed password. | **password**: _string_ - The password to verify. <br/>**hashedPassword**: _string_ - The hashed password to verify against. <br/>**options**: _object_ - Optional configuration object (see below). | **boolean** - Returns `true` if the password matches the hash, `false` otherwise.
86
+ | [_static_] **isHashed()** | Checks if a string is a hashed password. | **password**: _string_ - The string to check. <br/>**options**: _object_ - Optional configuration object (see below). | **boolean** - Returns `true` if the string appears to be a hashed password, `false` otherwise.
82
87
  | **encrypt()** | Encrypts data. |**data**: _object/string/number/boolean_ - The data to be encrypted. <br/>|**ciphered**: _string_ - encrypted data. |
83
88
  | **decrypt()** | Decrypts the encrypted or ciphered data | **encodedData**: string - The encrypted data: _string_ to be decrypted. | **data**: _string/object/number/boolean_ - The decrypted or original data (it might be string or object, depends on the initial input data type).
84
89
 
@@ -204,6 +209,110 @@ _**NOTE:** The secret is required to decrypt the encrypted data, if the secret u
204
209
 
205
210
  _Same goes for encoding, if data was encrypted using `hex` encoding format, decrypting with a `base64` encoding or other encoding format and vise versa will not work_
206
211
 
212
+ ### Using password hashing methods
213
+
214
+ The `generate()`, `verify()`, and `isHashed()` static methods provide secure password hashing and verification functionality. These methods use HMAC (Hash-based Message Authentication Code) for password hashing.
215
+
216
+ #### Generating a hashed password
217
+
218
+ The `generate()` method creates a secure hash of a password with a randomly generated salt.
219
+
220
+ ```ts
221
+ var { ncrypt } = require('ncrypt-js'); // or import ncrypt from 'ncrypt-js'
222
+
223
+ var password = "mySecurePassword123";
224
+ var hashedPassword = ncrypt.generate(password);
225
+ console.log(hashedPassword); // sha1$abc12345$1$hashedvalue...
226
+
227
+ // signature
228
+ ncrypt.generate(password: string, options?: {
229
+ algorithm?: string; // Hash algorithm (default: 'sha1')
230
+ saltLength?: number; // Salt length in characters (default: 8)
231
+ iterations?: number; // Number of hash iterations (default: 1)
232
+ encoding?: 'hex' | 'base64'; // Encoding format (default: 'hex')
233
+ separator?: string; // Separator character (default: '$')
234
+ });
235
+ ```
236
+
237
+ #### Verifying a password
238
+
239
+ The `verify()` method checks if a plain text password matches a previously hashed password.
240
+
241
+ ```ts
242
+ var { ncrypt } = require('ncrypt-js');
243
+
244
+ var password = "mySecurePassword123";
245
+ var hashedPassword = ncrypt.generate(password);
246
+
247
+ // Later, verify the password
248
+ var isValid = ncrypt.verify(password, hashedPassword);
249
+ console.log(isValid); // true
250
+
251
+ // signature
252
+ ncrypt.verify(password: string, hashedPassword: string, options?: {
253
+ encoding?: 'hex' | 'base64'; // Encoding format (default: 'hex')
254
+ separator?: string; // Separator character (default: '$')
255
+ });
256
+ ```
257
+
258
+ #### Checking if a string is hashed
259
+
260
+ The `isHashed()` method checks if a string appears to be a hashed password by verifying its format.
261
+
262
+ ```ts
263
+ var { ncrypt } = require('ncrypt-js');
264
+
265
+ var hashedPassword = ncrypt.generate("password123");
266
+ var isHashed = ncrypt.isHashed(hashedPassword);
267
+ console.log(isHashed); // true
268
+
269
+ var plainPassword = "password123";
270
+ var isHashed = ncrypt.isHashed(plainPassword);
271
+ console.log(isHashed); // false
272
+
273
+ // signature
274
+ ncrypt.isHashed(password: string, options?: {
275
+ separator?: string; // Separator character (default: '$')
276
+ });
277
+ ```
278
+
279
+ #### Advanced usage with custom options
280
+
281
+ You can customize the hashing algorithm, salt length, iterations, encoding, and separator:
282
+
283
+ ```ts
284
+ var { ncrypt } = require('ncrypt-js');
285
+
286
+ // Generate with custom options
287
+ var hashedPassword = ncrypt.generate("password123", {
288
+ algorithm: "sha256", // Use SHA-256 instead of SHA-1
289
+ saltLength: 16, // Use 16 character salt
290
+ iterations: 1000, // Apply hashing 1000 times
291
+ encoding: "base64", // Use base64 encoding
292
+ separator: "." // Use '.' as separator instead of '$'
293
+ });
294
+
295
+ // Verify with matching options
296
+ var isValid = ncrypt.verify("password123", hashedPassword, {
297
+ encoding: "base64",
298
+ separator: "."
299
+ });
300
+ console.log(isValid); // true
301
+ ```
302
+
303
+ **Available hash algorithms:** Any algorithm supported by Node.js `crypto.createHmac()`, such as `'sha1'`, `'sha256'`, `'sha512'`, `'md5'`, etc.
304
+
305
+ **Note:** The `encoding` and `separator` options must match between `generate()` and `verify()` calls for verification to succeed. To be safe, ensure you create a single options object and use the same object everywhere.
306
+
307
+ ```ts
308
+ const same_options_obj = {
309
+ ...
310
+ }
311
+
312
+ ncrypt.generate("pass", same_options_obj)
313
+ ncrypt.verify("pass", hasedPass, same_options_obj)
314
+ ```
315
+
207
316
  ## Built With
208
317
 
209
318
  Written in [TypeScript](https://typscriptlang.org/), built into ECMAScript 5 using the TypeScript compiler.
@@ -1,3 +1,10 @@
1
+ declare type THASH_ENC = {
2
+ algorithm?: string;
3
+ saltLength?: number;
4
+ iterations?: number;
5
+ encoding?: "base64" | "hex";
6
+ separator?: string;
7
+ };
1
8
  /**
2
9
  * @class Ncrypt
3
10
  * @type {Ncrypt.<object>}
@@ -20,6 +27,9 @@ export default class Ncrypt {
20
27
  * crypto random initial vector generated from core node {crypto} module
21
28
  */
22
29
  private readonly initialVector;
30
+ /**
31
+ * hashing salt
32
+ */
23
33
  /**
24
34
  * crypto random key generated from core node {crypto} module
25
35
  * {note}: please read the value for KEY from your app's environment
@@ -61,6 +71,47 @@ export default class Ncrypt {
61
71
  * @returns {string.<string>} decrypted data
62
72
  */
63
73
  private decode;
74
+ /**
75
+ *
76
+ * generate salt method
77
+ * @param length
78
+ * @param enc
79
+ * @returns
80
+ */
81
+ private static generateSalt;
82
+ /**
83
+ *
84
+ * generate hash method
85
+ * @param algorithm
86
+ * @param salt
87
+ * @param password
88
+ * @param iterations
89
+ * @param enc
90
+ * @param separator
91
+ * @returns
92
+ */
93
+ private static generateHash;
94
+ /**
95
+ *
96
+ * generate hashed password method
97
+ * @param password
98
+ * @param options
99
+ * @returns
100
+ */
101
+ static generate(password: string, options?: THASH_ENC): string;
102
+ /**
103
+ *
104
+ * verify password method
105
+ */
106
+ static verify(password: string, hashedPassword: string, options?: THASH_ENC): boolean;
107
+ /**
108
+ *
109
+ * isHashed method
110
+ * @param password
111
+ * @param options
112
+ * @returns
113
+ */
114
+ static isHashed(password: string, options?: THASH_ENC): boolean;
64
115
  /**
65
116
  * generate random strings
66
117
  * @example
@@ -74,7 +125,7 @@ export default class Ncrypt {
74
125
  * @param {enc.<string>} enc
75
126
  * @returns {*.<string>} string
76
127
  */
77
- static randomString(size?: number, enc?: 'hex' | 'base64'): string;
128
+ static randomString(size?: number, enc?: "hex" | "base64"): string;
78
129
  /**
79
130
  * data to be encrypted
80
131
  * @param {data.<stirng>} data
@@ -88,3 +139,4 @@ export default class Ncrypt {
88
139
  */
89
140
  decrypt(text: string): string | number | boolean | object;
90
141
  }
142
+ export {};
@@ -21,27 +21,32 @@ class Ncrypt {
21
21
  /**
22
22
  * algorithm used for encoding message
23
23
  */
24
- this.algorithm = 'aes-256-cbc';
24
+ this.algorithm = "aes-256-cbc";
25
25
  /**
26
26
  * ecoding for encrypted stirng
27
27
  */
28
- this.enc = (process.env.NCRYPT_ENC) || 'hex';
28
+ this.enc = process.env.NCRYPT_ENC || "hex";
29
29
  /**
30
30
  * crypto random initial vector generated from core node {crypto} module
31
31
  */
32
32
  this.initialVector = crypto.randomBytes(16);
33
+ /**
34
+ * hashing salt
35
+ */
36
+ // private readonly saltChars =
37
+ // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
33
38
  /**
34
39
  * crypto random key generated from core node {crypto} module
35
40
  * {note}: please read the value for KEY from your app's environment
36
41
  */
37
- this.key = crypto.scryptSync(process.env.KEY || 'please provide a KEY in your .env file or config', 'salt', 32);
42
+ this.key = crypto.scryptSync(process.env.KEY || "please provide a KEY in your .env file or config", "salt", 32);
38
43
  /**
39
44
  * convert all entered text to decimal equivalent character codes
40
45
  * @param {text.<string>} text to be converted
41
46
  * @return {Array.<number>} array of character codes
42
47
  */
43
48
  this.convertTextToDecimal = (text) => {
44
- return text.split('').map((value) => value.charCodeAt(0));
49
+ return text.split("").map((value) => value.charCodeAt(0));
45
50
  };
46
51
  /**
47
52
  * encode provided secret on decimal character codes
@@ -49,8 +54,7 @@ class Ncrypt {
49
54
  * @returns {*.<number>} decimal string
50
55
  */
51
56
  this.applySecretToCharacters = (charCodes) => {
52
- return this.convertTextToDecimal(this.secret)
53
- .reduce((firstValue, secondValue) => (firstValue ^ secondValue), charCodes);
57
+ return this.convertTextToDecimal(this.secret).reduce((firstValue, secondValue) => firstValue ^ secondValue, charCodes);
54
58
  };
55
59
  /**
56
60
  * convert character bytes to hexadecimal equivalent
@@ -58,7 +62,7 @@ class Ncrypt {
58
62
  * @returns {*.<string>} hexadecimal string
59
63
  */
60
64
  this.convertByteToHexadecimal = (number) => {
61
- return ('0' + Number(number).toString(16)).substr(-2);
65
+ return ("0" + Number(number).toString(16)).substr(-2);
62
66
  };
63
67
  /**
64
68
  * intermediate data encoder function
@@ -78,11 +82,11 @@ class Ncrypt {
78
82
  * @returns {string.<string>} decrypted data
79
83
  */
80
84
  this.decode = (text) => {
81
- if (typeof text !== 'string') {
82
- throw new TypeError('argument must be a string, or a string-like object');
85
+ if (typeof text !== "string") {
86
+ throw new TypeError("argument must be a string, or a string-like object");
83
87
  }
84
- const iv = text.split('.')[0];
85
- const encryptedData = text.split('.')[1];
88
+ const iv = text.split(".")[0];
89
+ const encryptedData = text.split(".")[1];
86
90
  let _iv = Buffer.from(iv, this.enc);
87
91
  let encryptedText = Buffer.from(encryptedData, this.enc);
88
92
  let decipher = crypto.createDecipheriv(this.algorithm, Buffer.from(this.key), _iv);
@@ -95,6 +99,95 @@ class Ncrypt {
95
99
  this.encrypt = this.encrypt.bind(this);
96
100
  this.decrypt = this.decrypt.bind(this);
97
101
  }
102
+ /**
103
+ *
104
+ * generate salt method
105
+ * @param length
106
+ * @param enc
107
+ * @returns
108
+ */
109
+ static generateSalt(length, enc = "hex") {
110
+ if (typeof length != "number" ||
111
+ length <= 0 ||
112
+ length !== parseInt(length, 10)) {
113
+ throw new Error("Invalid salt length");
114
+ }
115
+ // ensure your JS environment supports the `crypto.randomBytes()` function
116
+ return crypto
117
+ .randomBytes(Math.ceil(length / 2))
118
+ .toString(enc)
119
+ .substring(0, length);
120
+ }
121
+ /**
122
+ *
123
+ * generate hash method
124
+ * @param algorithm
125
+ * @param salt
126
+ * @param password
127
+ * @param iterations
128
+ * @param enc
129
+ * @param separator
130
+ * @returns
131
+ */
132
+ static generateHash(algorithm, salt, password, iterations = 1, enc = "hex", separator = "$") {
133
+ try {
134
+ let hash = password;
135
+ for (let i = 0; i < iterations; ++i) {
136
+ hash = crypto.createHmac(algorithm, salt).update(hash).digest(enc);
137
+ }
138
+ return (algorithm + separator + salt + separator + iterations + separator + hash);
139
+ }
140
+ catch (e) {
141
+ throw new Error("Invalid message digest algorithm");
142
+ }
143
+ }
144
+ /**
145
+ *
146
+ * generate hashed password method
147
+ * @param password
148
+ * @param options
149
+ * @returns
150
+ */
151
+ static generate(password, options = {}) {
152
+ options.algorithm = options.algorithm || "sha1";
153
+ options.saltLength = options.saltLength || 8;
154
+ options.iterations = options.iterations || 1;
155
+ options.encoding = options.encoding || "hex";
156
+ options.separator = options.separator || "$";
157
+ let salt = this.generateSalt(options.saltLength, options.encoding);
158
+ return this.generateHash(options.algorithm, salt, password, options.iterations, options.encoding, options.separator);
159
+ }
160
+ /**
161
+ *
162
+ * verify password method
163
+ */
164
+ static verify(password, hashedPassword, options = {}) {
165
+ if (!password || !hashedPassword)
166
+ return false;
167
+ options.encoding = options.encoding || "hex";
168
+ options.separator = options.separator || "$";
169
+ let parts = hashedPassword.split(options.separator);
170
+ if (parts.length != 4)
171
+ return false;
172
+ try {
173
+ return (this.generateHash(parts[0], parts[1], password, parts[2], options.encoding, options.separator) == hashedPassword);
174
+ }
175
+ catch (e) { }
176
+ return false;
177
+ }
178
+ /**
179
+ *
180
+ * isHashed method
181
+ * @param password
182
+ * @param options
183
+ * @returns
184
+ */
185
+ static isHashed(password, options = {}) {
186
+ if (!password)
187
+ return false;
188
+ options.separator = options.separator || "$";
189
+ return password.split(options.separator).length == 4;
190
+ }
98
191
  /**
99
192
  * generate random strings
100
193
  * @example
@@ -108,7 +201,7 @@ class Ncrypt {
108
201
  * @param {enc.<string>} enc
109
202
  * @returns {*.<string>} string
110
203
  */
111
- static randomString(size, enc = 'base64') {
204
+ static randomString(size, enc = "base64") {
112
205
  return crypto.randomBytes(size || 64).toString(enc);
113
206
  }
114
207
  /**
@@ -123,15 +216,17 @@ class Ncrypt {
123
216
  * hexadecimal mapping
124
217
  */
125
218
  try {
126
- const encodedMessage = JSON.stringify(data).split('')
219
+ const encodedMessage = JSON.stringify(data)
220
+ .split("")
127
221
  .map(this.convertTextToDecimal)
128
222
  .map(this.applySecretToCharacters)
129
223
  .map(this.convertByteToHexadecimal)
130
- .join('');
224
+ .join("");
131
225
  return this.encode(encodedMessage);
132
226
  }
133
227
  catch (e) {
134
- throw new Error('invalid data was entered, enter data of type object, number, string or boolean to be encrypted.' + e);
228
+ throw new Error("invalid data was entered, enter data of type object, number, string or boolean to be encrypted." +
229
+ e);
135
230
  }
136
231
  }
137
232
  /**
@@ -141,11 +236,12 @@ class Ncrypt {
141
236
  */
142
237
  decrypt(text) {
143
238
  const encodeData = this.decode(text);
144
- const data = (encodeData).match(/.{1,2}/g)
239
+ const data = encodeData
240
+ .match(/.{1,2}/g)
145
241
  .map((hex) => parseInt(hex, 16))
146
242
  .map(this.applySecretToCharacters)
147
243
  .map((charCode) => String.fromCharCode(charCode))
148
- .join('');
244
+ .join("");
149
245
  return JSON.parse(data);
150
246
  }
151
247
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ncrypt-js",
3
- "version": "2.1.2",
3
+ "version": "2.2.0",
4
4
  "description": "a light weight javascript data encryption and decryption library",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {