nestjs-cryptography 2.2.3 → 3.0.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.
Files changed (64) hide show
  1. package/README.md +6 -1
  2. package/dist/cryptography.service.d.ts +21 -23
  3. package/dist/cryptography.service.js +82 -82
  4. package/dist/interfaces/cryptography-options.interface.d.ts +1 -1
  5. package/dist/interfaces/generic-options.interface.d.ts +5 -0
  6. package/dist/interfaces/generic-options.interface.js +2 -0
  7. package/dist/interfaces/index.d.ts +1 -0
  8. package/dist/interfaces/index.js +1 -0
  9. package/package.json +16 -15
  10. package/wiki/README.md +41 -0
  11. package/wiki/babel.config.js +3 -0
  12. package/wiki/docs/Internals/_category_.json +7 -0
  13. package/wiki/docs/Internals/create-safe-random-data.mdx +41 -0
  14. package/wiki/docs/Internals/create-secure-hmac.mdx +31 -0
  15. package/wiki/docs/Internals/symmetric-data-encrypt.mdx +103 -0
  16. package/wiki/docs/Internals/symmetric-secure-data-encrypt.mdx +161 -0
  17. package/wiki/docs/api-reference/_category_.json +7 -0
  18. package/wiki/docs/api-reference/settings.mdx +199 -0
  19. package/wiki/docs/guides/_category_.json +7 -0
  20. package/wiki/docs/guides/generics.mdx +170 -0
  21. package/wiki/docs/guides/hashing.mdx +258 -0
  22. package/wiki/docs/guides/hmac.mdx +271 -0
  23. package/wiki/docs/guides/key-derivation.mdx +101 -0
  24. package/wiki/docs/guides/password-hashing.mdx +136 -0
  25. package/wiki/docs/guides/symmetric-encryption.mdx +272 -0
  26. package/wiki/docs/intro.mdx +148 -0
  27. package/wiki/docusaurus.config.ts +138 -0
  28. package/wiki/package.json +48 -0
  29. package/wiki/sidebars.ts +20 -0
  30. package/wiki/src/common/timing-attack.mdx +3 -0
  31. package/wiki/src/common/tips.mdx +18 -0
  32. package/wiki/src/components/GenerateHexButton/index.tsx +35 -0
  33. package/wiki/src/components/GenerateHexButton/styles.module.css +10 -0
  34. package/wiki/src/components/GenericLabel/index.tsx +19 -0
  35. package/wiki/src/components/HomepageFeatures/index.tsx +70 -0
  36. package/wiki/src/components/HomepageFeatures/styles.module.css +11 -0
  37. package/wiki/src/components/RecommendedLabel/index.tsx +19 -0
  38. package/wiki/src/components/RequiredLabel/index.tsx +12 -0
  39. package/wiki/src/css/custom.css +30 -0
  40. package/wiki/src/pages/index.module.css +23 -0
  41. package/wiki/src/pages/index.tsx +43 -0
  42. package/wiki/src/pages/markdown-page.md +7 -0
  43. package/wiki/static/.nojekyll +0 -0
  44. package/wiki/static/img/gear_api.png +0 -0
  45. package/wiki/static/img/logo.svg +1 -0
  46. package/wiki/static/img/nestjs_favicon.ico +0 -0
  47. package/wiki/static/img/node_crypto.png +0 -0
  48. package/wiki/static/img/phc_logo.png +0 -0
  49. package/wiki/static/img/profile.png +0 -0
  50. package/wiki/versioned_docs/version-2.x/Internals/_category_.json +8 -0
  51. package/wiki/versioned_docs/version-2.x/Internals/create-secure-hmac.mdx +30 -0
  52. package/wiki/versioned_docs/version-2.x/Internals/symmetric-secure-data-encrypt.mdx +160 -0
  53. package/wiki/versioned_docs/version-2.x/api-reference/_category_.json +8 -0
  54. package/wiki/versioned_docs/version-2.x/api-reference/settings.mdx +197 -0
  55. package/wiki/versioned_docs/version-2.x/guides/_category_.json +7 -0
  56. package/wiki/versioned_docs/version-2.x/guides/generics.mdx +133 -0
  57. package/wiki/versioned_docs/version-2.x/guides/hashing.mdx +229 -0
  58. package/wiki/versioned_docs/version-2.x/guides/hmac.mdx +198 -0
  59. package/wiki/versioned_docs/version-2.x/guides/key-derivation.mdx +98 -0
  60. package/wiki/versioned_docs/version-2.x/guides/password-hashing.mdx +132 -0
  61. package/wiki/versioned_docs/version-2.x/guides/symmetric-encryption.mdx +107 -0
  62. package/wiki/versioned_docs/version-2.x/intro.mdx +148 -0
  63. package/wiki/versioned_sidebars/version-2.x-sidebars.json +8 -0
  64. package/wiki/versions.json +3 -0
package/README.md CHANGED
@@ -1,9 +1,14 @@
1
1
  [![codecov](https://codecov.io/github/mjorgegulab/nestjs-cryptography/branch/main/graph/badge.svg?token=I0ZFVZTREB)](https://codecov.io/github/mjorgegulab/nestjs-cryptography)
2
2
  [![Codacy Badge](https://app.codacy.com/project/badge/Grade/d4c33e2a77d64f89ba7f6ba54c6d8cb5)](https://app.codacy.com/gh/mjorgegulab/nestjs-cryptography/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
3
3
  [![CodeQL](https://github.com/mjorgegulab/nestjs-cryptography/actions/workflows/github-code-scanning/codeql/badge.svg?branch=main)](https://github.com/mjorgegulab/nestjs-cryptography/actions/workflows/github-code-scanning/codeql)
4
+ [![Publish Wiki](https://github.com/mjorgegulab/nestjs-cryptography/actions/workflows/deploy-wiki-prod.yaml/badge.svg?branch=main)](https://nestjs-cryptography.thewolfx41.dev)
4
5
 
5
6
  # NestJS - Cryptography
6
- ## Secure NestJS cryptography module 🔐
7
+
8
+ <p align="center">
9
+ <a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
10
+ </p>
11
+
7
12
 
8
13
  ## Quick Start
9
14
 
@@ -1,36 +1,34 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
1
  import * as crypto from 'node:crypto';
4
- import { CryptographyOptionsInterface } from './interfaces';
2
+ import { CryptographyOptionsInterface, GenericOptionsInterface } from './interfaces';
5
3
  export declare class CryptographyService {
6
4
  private options;
7
5
  constructor(options: CryptographyOptionsInterface);
8
- private convertDataToBuffer;
6
+ private convertInputData;
9
7
  private extractIV;
10
8
  private extractAuthTagFromCypheredData;
11
9
  private extractCipheredData;
12
10
  private extractSalt;
11
+ private extractSaltFromHmac;
13
12
  private extractCipheredDEK;
14
13
  private extractCipheredDataWithDEK;
15
- private createSaferRandomData;
16
- private generateKeyDEK;
14
+ private createHmacSecureKey;
15
+ createSafeRandomData(length: number): Buffer;
17
16
  genUUID(secure?: boolean): string;
18
- genRandomPassword(length: number, encoding: 'base64' | 'hex'): string;
17
+ genRandomPassword(length: number): string;
19
18
  generateSymmetricKey(length?: number): crypto.KeyObject;
20
- deriveMasterKey(masterKey: string | Buffer, salt: Buffer, length: number): Promise<Buffer>;
21
- createArgonHashFromPassword(data: string | Buffer): Promise<Buffer>;
22
- verifyArgonHashFromPassword(hash: string, data: string | Buffer): Promise<boolean>;
23
- createCustomHash(algorithm: string, data: string, outputLength?: number): Buffer;
24
- verifyCustomHash(algorithm: string, data: string, oldHash: string | Buffer, outputLength?: number): boolean;
25
- createSecureHash(data: string): Buffer;
26
- verifySecureHash(data: string, oldHash: string | Buffer): boolean;
27
- createCustomHmac(algorithm: string, key: Buffer, data: string): Buffer;
28
- verifyCustomHmac(algorithm: string, key: Buffer, data: string, oldHmac: string | Buffer): boolean;
29
- createSecureHmac(data: string): Buffer;
30
- verifySecureHmac(data: string, oldHmac: Buffer | string): boolean;
31
- createInsecureFastHash(data: string): Buffer;
32
- private symmetricDataEncrypt;
33
- private symmetricDataDecrypt;
34
- symmetricSecureDataEncrypt(data: string | Buffer): Promise<Buffer>;
35
- symmetricSecureDataDecrypt(data: string | Buffer): Promise<Buffer>;
19
+ deriveMasterKey(masterKey: string | Buffer, salt: Buffer, length?: number): Promise<Buffer>;
20
+ createArgon2HashFromPassword(data: string | Buffer): Promise<Buffer>;
21
+ verifyArgon2HashFromPassword(hash: string, data: string | Buffer): Promise<boolean>;
22
+ createCustomHash(algorithm: string, data: string | Buffer, options?: GenericOptionsInterface): Buffer;
23
+ verifyCustomHash(algorithm: string, data: string | Buffer, oldHash: string | Buffer, options?: GenericOptionsInterface): boolean;
24
+ createSecureHash(data: string | Buffer, options?: GenericOptionsInterface): Buffer;
25
+ verifySecureHash(data: string | Buffer, oldHash: string | Buffer, options?: GenericOptionsInterface): boolean;
26
+ createCustomHmac(algorithm: string, key: string | Buffer, data: string | Buffer, options?: GenericOptionsInterface): Buffer;
27
+ verifyCustomHmac(algorithm: string, key: string | Buffer, data: string | Buffer, oldHmac: string | Buffer, options?: GenericOptionsInterface): boolean;
28
+ createSecureHmac(data: string | Buffer, options?: GenericOptionsInterface): Buffer;
29
+ verifySecureHmac(data: string | Buffer, oldHmac: string | Buffer, options?: GenericOptionsInterface): boolean;
30
+ symmetricDataEncrypt(data: string | Buffer, key: string | Buffer, options?: GenericOptionsInterface): Promise<Buffer>;
31
+ symmetricDataDecrypt(data: string | Buffer, key: string | Buffer, options?: GenericOptionsInterface): Promise<Buffer>;
32
+ symmetricSecureDataEncrypt(data: string | Buffer, options?: GenericOptionsInterface): Promise<Buffer>;
33
+ symmetricSecureDataDecrypt(data: string | Buffer, options?: GenericOptionsInterface): Promise<Buffer>;
36
34
  }
@@ -44,8 +44,16 @@ let CryptographyService = class CryptographyService {
44
44
  constructor(options) {
45
45
  this.options = options;
46
46
  }
47
- convertDataToBuffer(data) {
48
- return Buffer.isBuffer(data) ? data : Buffer.from(data, 'hex');
47
+ convertInputData(data, inputEncoding) {
48
+ if (Buffer.isBuffer(data)) {
49
+ return data;
50
+ }
51
+ else if (typeof data === 'string') {
52
+ return Buffer.from(data, inputEncoding ?? 'utf8');
53
+ }
54
+ else {
55
+ throw new Error('Unsupported input type');
56
+ }
49
57
  }
50
58
  extractIV(data) {
51
59
  return data.subarray(0, 12);
@@ -59,32 +67,35 @@ let CryptographyService = class CryptographyService {
59
67
  extractSalt(data) {
60
68
  return data.subarray(12, 76);
61
69
  }
70
+ extractSaltFromHmac(data) {
71
+ return data.subarray(0, 16);
72
+ }
62
73
  extractCipheredDEK(data) {
63
74
  return data.subarray(0, 124);
64
75
  }
65
76
  extractCipheredDataWithDEK(data) {
66
77
  return data.subarray(124, data.length);
67
78
  }
68
- createSaferRandomData(length) {
69
- return Buffer.from(crypto.hkdfSync('sha3-256', crypto.createSecretKey(crypto.randomBytes(64)), crypto.randomBytes(64), Buffer.alloc(0), length));
79
+ createHmacSecureKey(key, salt) {
80
+ return Buffer.from(crypto.hkdfSync('sha3-256', crypto.createSecretKey(key), salt, Buffer.alloc(0), 64));
70
81
  }
71
- generateKeyDEK() {
72
- return crypto.createSecretKey(this.createSaferRandomData(32));
82
+ createSafeRandomData(length) {
83
+ return Buffer.from(crypto.hkdfSync('sha3-256', crypto.createSecretKey(crypto.randomBytes(64)), crypto.randomBytes(64), Buffer.alloc(0), length));
73
84
  }
74
85
  genUUID(secure = false) {
75
86
  return crypto.randomUUID({
76
87
  disableEntropyCache: secure,
77
88
  });
78
89
  }
79
- genRandomPassword(length, encoding) {
80
- return crypto.randomBytes(length).toString(encoding).slice(0, length);
90
+ genRandomPassword(length) {
91
+ return crypto.randomBytes(length).toString('base64').slice(0, length);
81
92
  }
82
93
  generateSymmetricKey(length = 256) {
83
94
  return crypto.generateKeySync('hmac', { length });
84
95
  }
85
96
  async deriveMasterKey(masterKey, salt, length) {
86
97
  return await argon2.hash(masterKey, {
87
- hashLength: length ? length : this.options.kdf.defaultOutputKeyLength,
98
+ hashLength: length ?? this.options.kdf.outputKeyLength,
88
99
  salt: salt,
89
100
  type: this.options.kdf.argon2Type,
90
101
  memoryCost: this.options.kdf.memoryCost,
@@ -92,7 +103,7 @@ let CryptographyService = class CryptographyService {
92
103
  raw: true,
93
104
  });
94
105
  }
95
- async createArgonHashFromPassword(data) {
106
+ async createArgon2HashFromPassword(data) {
96
107
  const tmpData = await argon2.hash(data, {
97
108
  hashLength: this.options.hashing.password.outputKeyLength,
98
109
  type: this.options.hashing.password.argon2Type,
@@ -102,113 +113,102 @@ let CryptographyService = class CryptographyService {
102
113
  });
103
114
  return Buffer.isBuffer(tmpData) ? tmpData : Buffer.from(tmpData);
104
115
  }
105
- async verifyArgonHashFromPassword(hash, data) {
116
+ async verifyArgon2HashFromPassword(hash, data) {
106
117
  return await argon2.verify(hash, data);
107
118
  }
108
- createCustomHash(algorithm, data, outputLength = 0) {
119
+ createCustomHash(algorithm, data, options) {
120
+ const inputData = this.convertInputData(data, options?.inputDataEncoding);
109
121
  const hash = crypto.createHash(algorithm, {
110
- ...(outputLength && { outputLength }),
122
+ ...(options?.outputLength && { outputLength: options?.outputLength }),
111
123
  });
112
- hash.update(data);
124
+ hash.update(inputData);
113
125
  return hash.digest();
114
126
  }
115
- verifyCustomHash(algorithm, data, oldHash, outputLength = 0) {
116
- const hash = this.createCustomHash(algorithm, data, outputLength);
117
- if (Buffer.isBuffer(oldHash)) {
118
- return crypto.timingSafeEqual(hash, oldHash);
119
- }
120
- else {
121
- return crypto.timingSafeEqual(Buffer.from(oldHash, 'hex'), hash);
122
- }
127
+ verifyCustomHash(algorithm, data, oldHash, options) {
128
+ const inputOldHashData = this.convertInputData(oldHash, options?.inputDataEncoding);
129
+ const hash = this.createCustomHash(algorithm, data, options);
130
+ return crypto.timingSafeEqual(hash, inputOldHashData);
123
131
  }
124
- createSecureHash(data) {
125
- return this.createCustomHash('shake256', data, 48);
132
+ createSecureHash(data, options) {
133
+ return this.createCustomHash('shake256', data, {
134
+ ...options,
135
+ outputLength: 48,
136
+ });
126
137
  }
127
- verifySecureHash(data, oldHash) {
128
- const hash = this.createCustomHash('shake256', data, 48);
129
- const buffOldHash = Buffer.isBuffer(oldHash)
130
- ? oldHash
131
- : Buffer.from(oldHash, 'hex');
132
- return crypto.timingSafeEqual(hash, buffOldHash);
138
+ verifySecureHash(data, oldHash, options) {
139
+ return this.verifyCustomHash('shake256', data, oldHash, {
140
+ ...options,
141
+ outputLength: 48,
142
+ });
133
143
  }
134
- createCustomHmac(algorithm, key, data) {
135
- const hmac = crypto.createHmac(algorithm, crypto.createSecretKey(key));
136
- hmac.update(data);
144
+ createCustomHmac(algorithm, key, data, options) {
145
+ const inputKey = this.convertInputData(key, options?.inputKeyEncoding);
146
+ const inputData = this.convertInputData(data, options?.inputDataEncoding);
147
+ const hmac = crypto.createHmac(algorithm, crypto.createSecretKey(inputKey));
148
+ hmac.update(inputData);
137
149
  key = null;
138
150
  return hmac.digest();
139
151
  }
140
- verifyCustomHmac(algorithm, key, data, oldHmac) {
141
- const hmac = this.createCustomHmac(algorithm, key, data);
142
- if (Buffer.isBuffer(oldHmac)) {
143
- return crypto.timingSafeEqual(hmac, oldHmac);
144
- }
145
- else {
146
- return crypto.timingSafeEqual(Buffer.from(oldHmac, 'hex'), hmac);
147
- }
152
+ verifyCustomHmac(algorithm, key, data, oldHmac, options) {
153
+ const inputOldHmacData = this.convertInputData(oldHmac, options?.inputDataEncoding);
154
+ const hmac = this.createCustomHmac(algorithm, key, data, options);
155
+ return crypto.timingSafeEqual(hmac, inputOldHmacData);
148
156
  }
149
- createSecureHmac(data) {
157
+ createSecureHmac(data, options) {
150
158
  const key = Buffer.from(this.options.hashing.hmac.masterKey, 'hex');
151
159
  const salt = crypto.randomBytes(16);
152
- const secureKey = Buffer.from(crypto.hkdfSync('sha3-256', crypto.createSecretKey(key), salt, Buffer.alloc(0), 64));
153
- const hmac = this.createCustomHmac('sha3-256', secureKey, data);
154
- return Buffer.concat([Buffer.from(salt), Buffer.from(hmac)], salt.length + hmac.length);
160
+ const secureKey = this.createHmacSecureKey(key, salt);
161
+ const hmac = this.createCustomHmac('sha3-256', secureKey, data, options);
162
+ return Buffer.concat([salt, hmac], salt.length + hmac.length);
155
163
  }
156
- verifySecureHmac(data, oldHmac) {
164
+ verifySecureHmac(data, oldHmac, options) {
157
165
  const key = Buffer.from(this.options.hashing.hmac.masterKey, 'hex');
158
- const buffOldHmac = Buffer.isBuffer(oldHmac)
159
- ? oldHmac
160
- : Buffer.from(oldHmac, 'hex');
161
- const saltOldHmac = buffOldHmac.subarray(0, 16);
166
+ const buffOldHmac = this.convertInputData(oldHmac, options?.inputDataEncoding);
167
+ const saltOldHmac = this.extractSaltFromHmac(buffOldHmac);
162
168
  const hashOldHmac = buffOldHmac.subarray(16, buffOldHmac.length);
163
- const secureKey = Buffer.from(crypto.hkdfSync('sha3-256', crypto.createSecretKey(key), saltOldHmac, Buffer.alloc(0), 64));
164
- const hmac = this.createCustomHmac('sha3-256', secureKey, data);
169
+ const secureKey = this.createHmacSecureKey(key, saltOldHmac);
170
+ const hmac = this.createCustomHmac('sha3-256', secureKey, data, options);
165
171
  return crypto.timingSafeEqual(hmac, hashOldHmac);
166
172
  }
167
- createInsecureFastHash(data) {
168
- return crypto.createHash('sha1').update(data).digest();
169
- }
170
- async symmetricDataEncrypt(data, key) {
171
- const iv = this.createSaferRandomData(12);
172
- const salt = this.createSaferRandomData(64);
173
- const secureEncryptionKey = await this.deriveMasterKey(key, salt, 32);
173
+ async symmetricDataEncrypt(data, key, options) {
174
+ const inputData = this.convertInputData(data, options?.inputDataEncoding);
175
+ const inputKey = this.convertInputData(key, options?.inputKeyEncoding);
176
+ const iv = this.createSafeRandomData(12);
177
+ const salt = this.createSafeRandomData(64);
178
+ const secureEncryptionKey = await this.deriveMasterKey(inputKey, salt, 32);
174
179
  const cipher = crypto.createCipheriv('aes-256-gcm', crypto.createSecretKey(secureEncryptionKey), iv, {
175
180
  authTagLength: 16,
176
181
  });
177
- let cipheredData = cipher.update(data);
178
- cipheredData = Buffer.concat([
179
- Buffer.from(cipheredData),
180
- Buffer.from(cipher.final()),
181
- ]);
182
+ let cipheredData = cipher.update(inputData);
183
+ cipheredData = Buffer.concat([cipheredData, cipher.final()]);
182
184
  return Buffer.concat([iv, salt, cipher.getAuthTag(), cipheredData]);
183
185
  }
184
- async symmetricDataDecrypt(data, key) {
185
- data = Buffer.isBuffer(data) ? data : Buffer.from(data, 'hex');
186
- const iv = this.extractIV(data);
187
- const salt = this.extractSalt(data);
188
- const authTag = this.extractAuthTagFromCypheredData(data);
189
- const cipheredData = this.extractCipheredData(data);
190
- const decryptionKey = await this.deriveMasterKey(key, salt, 32);
186
+ async symmetricDataDecrypt(data, key, options) {
187
+ const inputData = this.convertInputData(data, options?.inputDataEncoding);
188
+ const inputKey = this.convertInputData(key, options?.inputKeyEncoding);
189
+ const iv = this.extractIV(inputData);
190
+ const salt = this.extractSalt(inputData);
191
+ const authTag = this.extractAuthTagFromCypheredData(inputData);
192
+ const cipheredData = this.extractCipheredData(inputData);
193
+ const decryptionKey = await this.deriveMasterKey(inputKey, salt, 32);
191
194
  const decipher = crypto.createDecipheriv('aes-256-gcm', crypto.createSecretKey(decryptionKey), iv, {
192
195
  authTagLength: 16,
193
196
  });
194
197
  decipher.setAuthTag(authTag);
195
198
  let decipheredData = decipher.update(cipheredData);
196
- decipheredData = Buffer.concat([
197
- Buffer.from(decipheredData),
198
- Buffer.from(decipher.final()),
199
- ]);
199
+ decipheredData = Buffer.concat([decipheredData, decipher.final()]);
200
200
  return decipheredData;
201
201
  }
202
- async symmetricSecureDataEncrypt(data) {
203
- const dek = this.createSaferRandomData(32);
204
- const cipheredData = await this.symmetricDataEncrypt(data, dek);
202
+ async symmetricSecureDataEncrypt(data, options) {
203
+ const dek = this.createSafeRandomData(32);
204
+ const cipheredData = await this.symmetricDataEncrypt(data, dek, options);
205
205
  const cipheredDek = await this.symmetricDataEncrypt(dek, this.options.encryption.symmetric.masterKey);
206
206
  return Buffer.concat([cipheredDek, cipheredData]);
207
207
  }
208
- async symmetricSecureDataDecrypt(data) {
209
- data = Buffer.isBuffer(data) ? data : Buffer.from(data, 'hex');
210
- const cipheredDek = this.extractCipheredDEK(data);
211
- const cipheredData = this.extractCipheredDataWithDEK(data);
208
+ async symmetricSecureDataDecrypt(data, options) {
209
+ const inputData = this.convertInputData(data, options?.inputDataEncoding);
210
+ const cipheredDek = this.extractCipheredDEK(inputData);
211
+ const cipheredData = this.extractCipheredDataWithDEK(inputData);
212
212
  const decipheredDek = await this.symmetricDataDecrypt(cipheredDek, this.options.encryption.symmetric.masterKey);
213
213
  return await this.symmetricDataDecrypt(cipheredData, decipheredDek);
214
214
  }
@@ -5,7 +5,7 @@ export declare enum Argon2Type {
5
5
  }
6
6
  export interface CryptographyOptionsInterface {
7
7
  kdf: {
8
- defaultOutputKeyLength: number;
8
+ outputKeyLength: number;
9
9
  argon2Type: Argon2Type;
10
10
  memoryCost: number;
11
11
  timeCost: number;
@@ -0,0 +1,5 @@
1
+ export interface GenericOptionsInterface {
2
+ outputLength?: number;
3
+ inputDataEncoding?: BufferEncoding;
4
+ inputKeyEncoding?: BufferEncoding;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1 +1,2 @@
1
1
  export * from './cryptography-options.interface';
2
+ export * from './generic-options.interface';
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./cryptography-options.interface"), exports);
18
+ __exportStar(require("./generic-options.interface"), exports);
package/package.json CHANGED
@@ -1,15 +1,12 @@
1
1
  {
2
2
  "name": "nestjs-cryptography",
3
- "version": "2.2.3",
3
+ "version": "3.0.0",
4
4
  "author": {
5
5
  "name": "Marc Jorge Gonzalez",
6
6
  "url": "https://github.com/mjorgegulab"
7
7
  },
8
8
  "license": "MIT",
9
9
  "description": "Secure NestJS cryptography module 🔐",
10
- "publishConfig": {
11
- "registry": "https://npm.pkg.github.com/"
12
- },
13
10
  "homepage": "https://nestjs-cryptography.thewolfx41.dev",
14
11
  "repository": {
15
12
  "type": "git",
@@ -24,17 +21,18 @@
24
21
  "lint": "eslint --fix",
25
22
  "publish:npm": "npm publish --access=public",
26
23
  "prepublish": "yarn run build",
27
- "prepack": "yarn run build"
24
+ "prepack": "yarn run build",
25
+ "test": "jest",
26
+ "test:cov": "jest --coverage",
27
+ "all": "yarn format && yarn lint && yarn test && yarn prepack"
28
28
  },
29
29
  "dependencies": {
30
30
  "argon2": "^0.41.1"
31
31
  },
32
32
  "devDependencies": {
33
+ "@nestjs/cli": "^10.4.5",
33
34
  "@nestjs/common": "^10.4.1",
34
35
  "@nestjs/core": "^10.4.1",
35
- "@nestjs/cli": "^10.4.5",
36
- "reflect-metadata": "^0.2.2",
37
- "rxjs": "^7.8.1",
38
36
  "@nestjs/platform-express": "^10.4.1",
39
37
  "@nestjs/schematics": "^10.1.4",
40
38
  "@nestjs/testing": "^10.4.1",
@@ -46,17 +44,19 @@
46
44
  "@typescript-eslint/parser": "^7.12.0",
47
45
  "eslint": "^8.57.0",
48
46
  "eslint-config-prettier": "^9.1.0",
49
- "eslint-plugin-prettier": "^5.1.3",
47
+ "eslint-plugin-prettier": "^5.2.1",
50
48
  "jest": "29.7.0",
51
49
  "prettier": "^3.3.3",
50
+ "reflect-metadata": "^0.2.2",
51
+ "rimraf": "^6.0.1",
52
+ "rxjs": "^7.8.1",
52
53
  "source-map-support": "^0.5.21",
53
54
  "supertest": "^7.0.0",
54
55
  "ts-jest": "29.2.5",
55
56
  "ts-loader": "^9.5.1",
56
57
  "ts-node": "^10.9.2",
57
58
  "tsconfig-paths": "4.2.0",
58
- "typescript": "^5.4.5",
59
- "rimraf": "^5.0.7"
59
+ "typescript": "^5.6.2"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "@nestjs/common": "^9.0.0 || ^10.0.0",
@@ -68,15 +68,16 @@
68
68
  "json",
69
69
  "ts"
70
70
  ],
71
- "rootDir": "src",
72
- "testRegex": ".*\\.spec\\.ts$",
71
+ "rootDir": "./",
72
+ "testMatch": [
73
+ "**/test/**/?(*.)+(spec|test).[tj]s?(x)"
74
+ ],
73
75
  "transform": {
74
76
  "^.+\\.(t|j)s$": "ts-jest"
75
77
  },
76
78
  "collectCoverageFrom": [
77
- "**/*.(t|j)s"
79
+ "**/*.service.ts"
78
80
  ],
79
- "coverageDirectory": "../coverage",
80
81
  "testEnvironment": "node"
81
82
  }
82
83
  }
package/wiki/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # Website
2
+
3
+ This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.
4
+
5
+ ### Installation
6
+
7
+ ```
8
+ $ yarn
9
+ ```
10
+
11
+ ### Local Development
12
+
13
+ ```
14
+ $ yarn start
15
+ ```
16
+
17
+ This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
18
+
19
+ ### Build
20
+
21
+ ```
22
+ $ yarn build
23
+ ```
24
+
25
+ This command generates static content into the `build` directory and can be served using any static contents hosting service.
26
+
27
+ ### Deployment
28
+
29
+ Using SSH:
30
+
31
+ ```
32
+ $ USE_SSH=true yarn deploy
33
+ ```
34
+
35
+ Not using SSH:
36
+
37
+ ```
38
+ $ GIT_USER=<Your GitHub username> yarn deploy
39
+ ```
40
+
41
+ If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
3
+ };
@@ -0,0 +1,7 @@
1
+ {
2
+ "label": "Internals",
3
+ "position": 4,
4
+ "link": {
5
+ "type": "generated-index",
6
+ }
7
+ }
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Create Safe Random Data
3
+ sidebar_label: Create Safe Random Data
4
+ sidebar_position: 2
5
+ description: Internals of createSafeRandomData
6
+ ---
7
+
8
+ In the following section, you will see a diagram of the cryptographic operations performed when calling the method [`createSafeRandomData`][1]
9
+
10
+ This method generate a cryptographically secure random bytes of the desired lengths using **HKDF**
11
+ with `sha3-256` digest algorithm using the following params:
12
+ - Generate a random key using the secure random bytes' generator.
13
+ - Generate a salt using the secure random bytes' generator.
14
+
15
+
16
+ <div style={{ textAlign: 'center' }}>
17
+ ```mermaid
18
+ graph TD
19
+ A[Key Length: length]
20
+
21
+ A --> CRB[Create Random Bytes: 64 bytes]
22
+ CRB --> CSK[Create Secret Key]
23
+ CSK ==> SK(SECRET_KEY)
24
+
25
+ A --> CRB2[Create Random Bytes: 64 bytes]
26
+ CRB2 ==> RB[RANDOM_BYTES]
27
+
28
+ SK -.-> HKDF["HKDF ( sha3-256 + SECRET_KEY + RANDOM_BYTES + length )"]
29
+ RB -.-> HKDF --> F([Return Secure Random Bytes])
30
+
31
+
32
+ style CRB fill:#f9f,stroke:#333,stroke-width:2px
33
+ style CRB2 fill:#f9f,stroke:#333,stroke-width:2px
34
+ style SK fill:#bbf,stroke:#333,stroke-width:2px
35
+ style RB fill:#bbf,stroke:#333,stroke-width:2px
36
+ style HKDF fill:#bfb,stroke:#333,stroke-width:2px
37
+ style F fill:#00f0f0,stroke:#F0000,stroke-width:2px
38
+ ```
39
+ </div>
40
+
41
+ [1]: ../guides/generics#generate-secure-random-data
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Create Secure HMAC
3
+ sidebar_label: Create Secure HMAC
4
+ sidebar_position: 1
5
+ description: Internals of createSecureHmac
6
+ ---
7
+
8
+ In the following section, you will see a diagram of the cryptographic operations performed when calling the method [`createSecureHmac`][1]
9
+
10
+ This method performs several cryptographic operations, including generating a salt,
11
+ deriving a secure key using HKDF with the sha3-256 hashing algorithm, creating an HMAC,
12
+ and returning the concatenated salt and HMAC result. The diagram will illustrate these steps clearly.
13
+
14
+ <div style={{ textAlign: 'center' }}>
15
+ ```mermaid
16
+ graph TD
17
+ A[Input Data: data] --> B[Generate Master Key from Options]
18
+ B --> C[Generate Random Salt: 16 bytes]
19
+ C --> D[Use HKDF with sha3-256, Master Key, and Salt]
20
+ D --> E[Generate Secure Key: 64 bytes]
21
+ E --> F[Create HMAC with sha3-256, Secure Key, and Data]
22
+ F --> G[Concatenate Salt and HMAC]
23
+ G --> H[Return Combined Buffer: Salt + HMAC]
24
+
25
+ style B fill:#f9f,stroke:#333,stroke-width:2px
26
+ style D fill:#bbf,stroke:#333,stroke-width:2px
27
+ style F fill:#bfb,stroke:#333,stroke-width:2px
28
+ ```
29
+ </div>
30
+
31
+ [1]: ../guides/hmac#create-a-secure-hmac