@futdevpro/fsm-dynamo 1.10.50 → 1.10.51
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/build/_modules/crypto/_collections/crypto-non-stable.util.d.ts +80 -0
- package/build/_modules/crypto/_collections/crypto-non-stable.util.d.ts.map +1 -0
- package/build/_modules/crypto/_collections/crypto-non-stable.util.js +229 -0
- package/build/_modules/crypto/_collections/crypto-non-stable.util.js.map +1 -0
- package/build/_modules/crypto/_collections/crypto.util.d.ts +13 -45
- package/build/_modules/crypto/_collections/crypto.util.d.ts.map +1 -1
- package/build/_modules/crypto/_collections/crypto.util.js +71 -96
- package/build/_modules/crypto/_collections/crypto.util.js.map +1 -1
- package/build/_modules/crypto/_collections/crypto.util.spec.js +6 -4
- package/build/_modules/crypto/_collections/crypto.util.spec.js.map +1 -1
- package/futdevpro-fsm-dynamo-01.10.51.tgz +0 -0
- package/package.json +1 -1
- package/src/_modules/crypto/_collections/crypto-non-stable.util.ts +285 -0
- package/src/_modules/crypto/_collections/crypto.util.spec.ts +6 -4
- package/src/_modules/crypto/_collections/crypto.util.ts +82 -143
- package/futdevpro-fsm-dynamo-01.10.50.tgz +0 -0
|
@@ -5,94 +5,36 @@ import {
|
|
|
5
5
|
} from '../../../_models/control-models/error.control-model';
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* Error codes for crypto operations
|
|
10
|
-
*/
|
|
11
|
-
/* export enum CryptoErrorCode {
|
|
12
|
-
INVALID_INPUT = 'DyFM-CRY-EA0',
|
|
13
|
-
DECRYPTION_FAILED = '',
|
|
14
|
-
ENCRYPTION_FAILED = 'DyFM-CRY-ENF',
|
|
15
|
-
INVALID_KEY = 'DyFM-CRY-IKY',
|
|
16
|
-
INVALID_DATA = 'DyFM-CRY-IDT'
|
|
17
|
-
} */
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Configuration options for encryption/decryption
|
|
21
|
-
*/
|
|
22
|
-
export interface CryptoConfig {
|
|
23
|
-
ivLength?: number;
|
|
24
|
-
saltLength?: number;
|
|
25
|
-
keyIterations?: number;
|
|
26
|
-
keySize?: number;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
8
|
/**
|
|
30
9
|
* A utility class for secure encryption and decryption of data
|
|
31
|
-
* Uses AES-256-CBC with
|
|
10
|
+
* Uses AES-256-CBC with deterministic IV and salt for consistent results
|
|
32
11
|
*/
|
|
33
12
|
export class DyFM_Crypto {
|
|
34
|
-
private static readonly DEFAULT_CONFIG: Required<CryptoConfig> = {
|
|
35
|
-
ivLength: 16, // 128 bits
|
|
36
|
-
saltLength: 16, // 128 bits
|
|
37
|
-
keyIterations: 10000,
|
|
38
|
-
keySize: 8 // 256 bits (8 * 32)
|
|
39
|
-
};
|
|
40
13
|
private static readonly defaultErrorUserMsg =
|
|
41
14
|
`We encountered an unhandled Authentication Error, ` +
|
|
42
15
|
`\nplease contact the responsible development team.`;
|
|
43
16
|
|
|
44
|
-
// Tömör: kb. 60–80 karakteres token, nem 200+
|
|
45
|
-
// Nem szabványos: nehéz visszafejteni
|
|
46
|
-
// Használható cookie, header, URL-ben
|
|
47
|
-
|
|
48
17
|
/**
|
|
49
|
-
* Validates the
|
|
50
|
-
* @throws {DyFM_Error} if validation fails
|
|
18
|
+
* Validates the encryption key
|
|
51
19
|
*/
|
|
52
|
-
private static
|
|
53
|
-
if (!key || typeof key !== 'string'
|
|
20
|
+
private static validateKey(key: string): void {
|
|
21
|
+
if (!key || typeof key !== 'string') {
|
|
54
22
|
throw new DyFM_Error({
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
23
|
+
status: 401,
|
|
24
|
+
message: 'Encryption key is required and must be a string',
|
|
25
|
+
errorCode: 'DyFM-CRY-KEY-REQ'
|
|
58
26
|
});
|
|
59
27
|
}
|
|
60
|
-
|
|
61
|
-
if (
|
|
28
|
+
|
|
29
|
+
if (key.trim().length === 0) {
|
|
62
30
|
throw new DyFM_Error({
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
31
|
+
status: 401,
|
|
32
|
+
message: 'Encryption key cannot be empty or whitespace-only',
|
|
33
|
+
errorCode: 'DyFM-CRY-KEY-EMPTY'
|
|
66
34
|
});
|
|
67
35
|
}
|
|
68
36
|
}
|
|
69
37
|
|
|
70
|
-
/**
|
|
71
|
-
* Generates a deterministic IV based on the input data and key
|
|
72
|
-
*/
|
|
73
|
-
private static generateIV(data: string, key: string, config: Required<CryptoConfig>): CryptoJS.lib.WordArray {
|
|
74
|
-
const hash = CryptoJS.SHA256(data + key);
|
|
75
|
-
return CryptoJS.lib.WordArray.create(hash.words.slice(0, config.ivLength / 4));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Generates a deterministic salt based on the input data and key
|
|
80
|
-
*/
|
|
81
|
-
private static generateSalt(data: string, key: string, config: Required<CryptoConfig>): CryptoJS.lib.WordArray {
|
|
82
|
-
const hash = CryptoJS.SHA256(key + data);
|
|
83
|
-
return CryptoJS.lib.WordArray.create(hash.words.slice(0, config.saltLength / 4));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Derives a key using PBKDF2
|
|
88
|
-
*/
|
|
89
|
-
private static deriveKey(key: string, salt: CryptoJS.lib.WordArray, config: Required<CryptoConfig>): CryptoJS.lib.WordArray {
|
|
90
|
-
return CryptoJS.PBKDF2(key, salt, {
|
|
91
|
-
keySize: config.keySize,
|
|
92
|
-
iterations: config.keyIterations
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
38
|
/**
|
|
97
39
|
* Safely serializes data to JSON
|
|
98
40
|
*/
|
|
@@ -141,40 +83,58 @@ export class DyFM_Crypto {
|
|
|
141
83
|
}
|
|
142
84
|
|
|
143
85
|
/**
|
|
144
|
-
*
|
|
86
|
+
* Derives a 256-bit key from the passphrase using SHA256
|
|
87
|
+
*/
|
|
88
|
+
private static deriveKey(key: string): CryptoJS.lib.WordArray {
|
|
89
|
+
return CryptoJS.SHA256(key);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Creates a deterministic IV from the key only
|
|
94
|
+
*/
|
|
95
|
+
private static createDeterministicIV(key: string): CryptoJS.lib.WordArray {
|
|
96
|
+
const hash = CryptoJS.SHA256(key + ':iv');
|
|
97
|
+
return CryptoJS.lib.WordArray.create(hash.words.slice(0, 4)); // Use first 16 bytes (128 bits)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Encrypts data using AES-256-CBC with deterministic key and IV
|
|
145
102
|
* @param data The data to encrypt
|
|
146
103
|
* @param key The encryption key
|
|
147
|
-
* @param config Optional configuration
|
|
148
104
|
* @returns URL-safe encrypted string
|
|
149
105
|
* @throws {DyFM_Error} if encryption fails
|
|
150
106
|
*/
|
|
151
|
-
static encrypt<T>(data: T, key: string
|
|
107
|
+
static encrypt<T>(data: T, key: string): string {
|
|
152
108
|
try {
|
|
153
|
-
|
|
154
|
-
|
|
109
|
+
// Validate key
|
|
110
|
+
this.validateKey(key);
|
|
111
|
+
|
|
112
|
+
// Validate data
|
|
113
|
+
if (data === undefined || data === null) {
|
|
114
|
+
throw new DyFM_Error({
|
|
115
|
+
status: 401,
|
|
116
|
+
message: 'Data cannot be undefined or null',
|
|
117
|
+
errorCode: 'DyFM-CRY-DATA-NULL'
|
|
118
|
+
});
|
|
119
|
+
}
|
|
155
120
|
|
|
156
121
|
// Convert data to string
|
|
157
122
|
const dataStr = this.safeSerialize(data);
|
|
158
123
|
|
|
159
|
-
//
|
|
160
|
-
const
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
// Derive key using PBKDF2
|
|
164
|
-
const derivedKey = this.deriveKey(key, salt, finalConfig);
|
|
124
|
+
// Derive key and IV
|
|
125
|
+
const aesKey = this.deriveKey(key);
|
|
126
|
+
const iv = this.createDeterministicIV(key);
|
|
165
127
|
|
|
166
|
-
// Encrypt the data
|
|
167
|
-
const encrypted = CryptoJS.AES.encrypt(dataStr,
|
|
128
|
+
// Encrypt the data with deterministic key and IV
|
|
129
|
+
const encrypted = CryptoJS.AES.encrypt(dataStr, aesKey, {
|
|
168
130
|
iv: iv,
|
|
169
131
|
mode: CryptoJS.mode.CBC,
|
|
170
132
|
padding: CryptoJS.pad.Pkcs7
|
|
171
133
|
});
|
|
172
134
|
|
|
173
|
-
// Combine IV + Salt + Ciphertext
|
|
174
|
-
const combined = iv.concat(salt).concat(encrypted.ciphertext);
|
|
175
|
-
|
|
176
135
|
// Convert to URL-safe base64
|
|
177
|
-
|
|
136
|
+
const base64 = encrypted.ciphertext.toString(CryptoJS.enc.Base64);
|
|
137
|
+
return base64
|
|
178
138
|
.replace(/\+/g, '-')
|
|
179
139
|
.replace(/\//g, '_')
|
|
180
140
|
.replace(/=+$/, '');
|
|
@@ -190,57 +150,57 @@ export class DyFM_Crypto {
|
|
|
190
150
|
* Decrypts data that was encrypted using encrypt()
|
|
191
151
|
* @param encryptedData The encrypted data
|
|
192
152
|
* @param key The decryption key
|
|
193
|
-
* @param config Optional configuration
|
|
194
153
|
* @returns The decrypted data
|
|
195
154
|
* @throws {DyFM_Error} if decryption fails
|
|
196
155
|
*/
|
|
197
|
-
static decrypt<T>(encryptedData: string, key: string
|
|
156
|
+
static decrypt<T>(encryptedData: string, key: string): T {
|
|
198
157
|
try {
|
|
199
|
-
|
|
200
|
-
|
|
158
|
+
// Validate key
|
|
159
|
+
this.validateKey(key);
|
|
160
|
+
|
|
161
|
+
// Validate encrypted data
|
|
162
|
+
if (!encryptedData || typeof encryptedData !== 'string') {
|
|
163
|
+
throw new DyFM_Error({
|
|
164
|
+
status: 401,
|
|
165
|
+
message: 'Encrypted data is required and must be a string',
|
|
166
|
+
errorCode: 'DyFM-CRY-DATA-REQ'
|
|
167
|
+
});
|
|
168
|
+
}
|
|
201
169
|
|
|
202
170
|
// Convert from URL-safe base64
|
|
203
|
-
|
|
171
|
+
let base64 = encryptedData
|
|
204
172
|
.replace(/-/g, '+')
|
|
205
173
|
.replace(/_/g, '/');
|
|
206
174
|
|
|
207
|
-
//
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
const minLength = (finalConfig.ivLength + finalConfig.saltLength + 16) / 4; // 16 bytes minimum for ciphertext
|
|
212
|
-
if (combined.words.length < minLength) {
|
|
213
|
-
throw new Error('Invalid encrypted data length');
|
|
175
|
+
// Add padding if needed
|
|
176
|
+
const padLength = 4 - (base64.length % 4);
|
|
177
|
+
if (padLength < 4) {
|
|
178
|
+
base64 += '='.repeat(padLength);
|
|
214
179
|
}
|
|
215
180
|
|
|
216
|
-
//
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
combined.words.slice(
|
|
220
|
-
finalConfig.ivLength / 4,
|
|
221
|
-
(finalConfig.ivLength + finalConfig.saltLength) / 4
|
|
222
|
-
)
|
|
223
|
-
);
|
|
224
|
-
const ciphertext = CryptoJS.lib.WordArray.create(
|
|
225
|
-
combined.words.slice((finalConfig.ivLength + finalConfig.saltLength) / 4)
|
|
226
|
-
);
|
|
227
|
-
|
|
228
|
-
// Derive key using PBKDF2
|
|
229
|
-
const derivedKey = this.deriveKey(key, salt, finalConfig);
|
|
181
|
+
// Derive key and IV
|
|
182
|
+
const aesKey = this.deriveKey(key);
|
|
183
|
+
const iv = this.createDeterministicIV(key);
|
|
230
184
|
|
|
231
185
|
// Decrypt the data
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
padding: CryptoJS.pad.Pkcs7
|
|
239
|
-
}
|
|
240
|
-
);
|
|
186
|
+
const encryptedWA = CryptoJS.enc.Base64.parse(base64);
|
|
187
|
+
const decrypted = CryptoJS.AES.decrypt({ ciphertext: encryptedWA }, aesKey, {
|
|
188
|
+
iv: iv,
|
|
189
|
+
mode: CryptoJS.mode.CBC,
|
|
190
|
+
padding: CryptoJS.pad.Pkcs7
|
|
191
|
+
});
|
|
241
192
|
|
|
242
193
|
// Parse JSON
|
|
243
194
|
const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8);
|
|
195
|
+
|
|
196
|
+
if (!decryptedStr) {
|
|
197
|
+
throw new DyFM_Error({
|
|
198
|
+
status: 401,
|
|
199
|
+
message: 'Failed to decrypt data - invalid key or corrupted data',
|
|
200
|
+
errorCode: 'DyFM-CRY-DEC-FAIL'
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
244
204
|
return this.safeDeserialize<T>(decryptedStr);
|
|
245
205
|
} catch (error) {
|
|
246
206
|
throw new DyFM_Error({
|
|
@@ -250,27 +210,6 @@ export class DyFM_Crypto {
|
|
|
250
210
|
}
|
|
251
211
|
}
|
|
252
212
|
|
|
253
|
-
/**
|
|
254
|
-
* Generates a secure random key
|
|
255
|
-
* @param length Length of the key in bytes (default: 32)
|
|
256
|
-
* @returns A secure random key
|
|
257
|
-
*/
|
|
258
|
-
static generateKey(length: number = 32): string {
|
|
259
|
-
return CryptoJS.lib.WordArray.random(length).toString();
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Validates if a string is a valid encrypted data
|
|
264
|
-
* @param encryptedData The data to validate
|
|
265
|
-
* @returns true if the data appears to be valid encrypted data
|
|
266
|
-
*/
|
|
267
|
-
static isValidEncryptedData(encryptedData: string): boolean {
|
|
268
|
-
if (!encryptedData || typeof encryptedData !== 'string') {
|
|
269
|
-
return false;
|
|
270
|
-
}
|
|
271
|
-
return /^[A-Za-z0-9\-_]+$/.test(encryptedData);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
213
|
/**
|
|
275
214
|
* Gets default error settings
|
|
276
215
|
*/
|
|
Binary file
|