@digitaldefiance/node-ecies-lib 1.1.22 → 1.1.24

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 (212) hide show
  1. package/README.md +8 -0
  2. package/package.json +6 -5
  3. package/src/constants.d.ts +32 -0
  4. package/src/constants.d.ts.map +1 -0
  5. package/src/constants.js +137 -0
  6. package/src/constants.js.map +1 -0
  7. package/src/enumerations/index.d.ts +2 -0
  8. package/src/enumerations/index.d.ts.map +1 -0
  9. package/src/enumerations/index.js +5 -0
  10. package/src/enumerations/index.js.map +1 -0
  11. package/src/enumerations/pbkdf2-profile.d.ts +9 -0
  12. package/src/enumerations/pbkdf2-profile.d.ts.map +1 -0
  13. package/src/enumerations/pbkdf2-profile.js +13 -0
  14. package/src/enumerations/pbkdf2-profile.js.map +1 -0
  15. package/src/i18n/ecies-i18n-factory.d.ts +54 -0
  16. package/src/i18n/ecies-i18n-factory.d.ts.map +1 -0
  17. package/src/i18n/ecies-i18n-factory.js +333 -0
  18. package/src/i18n/ecies-i18n-factory.js.map +1 -0
  19. package/src/i18n/{index.ts → index.d.ts} +1 -0
  20. package/src/i18n/index.d.ts.map +1 -0
  21. package/src/i18n/index.js +5 -0
  22. package/src/i18n/index.js.map +1 -0
  23. package/src/{index.ts → index.d.ts} +1 -0
  24. package/src/index.d.ts.map +1 -0
  25. package/src/index.js +11 -0
  26. package/src/index.js.map +1 -0
  27. package/src/interfaces/authenticated-cipher.d.ts +10 -0
  28. package/src/interfaces/authenticated-cipher.d.ts.map +1 -0
  29. package/src/interfaces/authenticated-cipher.js +3 -0
  30. package/src/interfaces/authenticated-cipher.js.map +1 -0
  31. package/src/interfaces/authenticated-decipher.d.ts +9 -0
  32. package/src/interfaces/authenticated-decipher.d.ts.map +1 -0
  33. package/src/interfaces/authenticated-decipher.js +3 -0
  34. package/src/interfaces/authenticated-decipher.js.map +1 -0
  35. package/src/interfaces/checksum-config.d.ts +5 -0
  36. package/src/interfaces/checksum-config.d.ts.map +1 -0
  37. package/src/interfaces/checksum-config.js +3 -0
  38. package/src/interfaces/checksum-config.js.map +1 -0
  39. package/src/interfaces/checksum-consts.d.ts +11 -0
  40. package/src/interfaces/checksum-consts.d.ts.map +1 -0
  41. package/src/interfaces/checksum-consts.js +3 -0
  42. package/src/interfaces/checksum-consts.js.map +1 -0
  43. package/src/interfaces/constants.d.ts +43 -0
  44. package/src/interfaces/constants.d.ts.map +1 -0
  45. package/src/interfaces/constants.js +3 -0
  46. package/src/interfaces/constants.js.map +1 -0
  47. package/src/interfaces/ecies-consts.d.ts +88 -0
  48. package/src/interfaces/ecies-consts.d.ts.map +1 -0
  49. package/src/interfaces/ecies-consts.js +3 -0
  50. package/src/interfaces/ecies-consts.js.map +1 -0
  51. package/src/interfaces/encryption-consts.d.ts +11 -0
  52. package/src/interfaces/encryption-consts.d.ts.map +1 -0
  53. package/src/interfaces/encryption-consts.js +3 -0
  54. package/src/interfaces/encryption-consts.js.map +1 -0
  55. package/src/interfaces/{index.ts → index.d.ts} +1 -0
  56. package/src/interfaces/index.d.ts.map +1 -0
  57. package/src/interfaces/index.js +21 -0
  58. package/src/interfaces/index.js.map +1 -0
  59. package/src/interfaces/keypair-buffer-with-un-encrypted-private-key.d.ts +6 -0
  60. package/src/interfaces/keypair-buffer-with-un-encrypted-private-key.d.ts.map +1 -0
  61. package/src/interfaces/keypair-buffer-with-un-encrypted-private-key.js +3 -0
  62. package/src/interfaces/keypair-buffer-with-un-encrypted-private-key.js.map +1 -0
  63. package/src/interfaces/keyring-consts.d.ts +6 -0
  64. package/src/interfaces/keyring-consts.d.ts.map +1 -0
  65. package/src/interfaces/keyring-consts.js +3 -0
  66. package/src/interfaces/keyring-consts.js.map +1 -0
  67. package/src/interfaces/member-operational.d.ts +36 -0
  68. package/src/interfaces/member-operational.d.ts.map +1 -0
  69. package/src/interfaces/member-operational.js +3 -0
  70. package/src/interfaces/member-operational.js.map +1 -0
  71. package/src/interfaces/{member-with-mnemonic.ts → member-with-mnemonic.d.ts} +3 -3
  72. package/src/interfaces/member-with-mnemonic.d.ts.map +1 -0
  73. package/src/interfaces/member-with-mnemonic.js +3 -0
  74. package/src/interfaces/member-with-mnemonic.js.map +1 -0
  75. package/src/interfaces/{multi-encrypted-message.ts → multi-encrypted-message.d.ts} +5 -5
  76. package/src/interfaces/multi-encrypted-message.d.ts.map +1 -0
  77. package/src/interfaces/multi-encrypted-message.js +3 -0
  78. package/src/interfaces/multi-encrypted-message.js.map +1 -0
  79. package/src/interfaces/multi-encrypted-parsed-header.d.ts +24 -0
  80. package/src/interfaces/multi-encrypted-parsed-header.d.ts.map +1 -0
  81. package/src/interfaces/multi-encrypted-parsed-header.js +3 -0
  82. package/src/interfaces/multi-encrypted-parsed-header.js.map +1 -0
  83. package/src/interfaces/{pbkdf-profiles.ts → pbkdf-profiles.d.ts} +2 -2
  84. package/src/interfaces/pbkdf-profiles.d.ts.map +1 -0
  85. package/src/interfaces/pbkdf-profiles.js +3 -0
  86. package/src/interfaces/pbkdf-profiles.js.map +1 -0
  87. package/src/interfaces/pbkdf2-result.d.ts +6 -0
  88. package/src/interfaces/pbkdf2-result.d.ts.map +1 -0
  89. package/src/interfaces/pbkdf2-result.js +3 -0
  90. package/src/interfaces/pbkdf2-result.js.map +1 -0
  91. package/src/interfaces/signing-key-private-key-info.d.ts +11 -0
  92. package/src/interfaces/signing-key-private-key-info.d.ts.map +1 -0
  93. package/src/interfaces/signing-key-private-key-info.js +3 -0
  94. package/src/interfaces/signing-key-private-key-info.js.map +1 -0
  95. package/src/interfaces/{simple-keypair-buffer.ts → simple-keypair-buffer.d.ts} +3 -3
  96. package/src/interfaces/simple-keypair-buffer.d.ts.map +1 -0
  97. package/src/interfaces/simple-keypair-buffer.js +3 -0
  98. package/src/interfaces/simple-keypair-buffer.js.map +1 -0
  99. package/src/interfaces/{simple-keypair.ts → simple-keypair.d.ts} +3 -3
  100. package/src/interfaces/simple-keypair.d.ts.map +1 -0
  101. package/src/interfaces/simple-keypair.js +3 -0
  102. package/src/interfaces/simple-keypair.js.map +1 -0
  103. package/src/interfaces/simple-public-key-only-buffer.d.ts +4 -0
  104. package/src/interfaces/simple-public-key-only-buffer.d.ts.map +1 -0
  105. package/src/interfaces/simple-public-key-only-buffer.js +3 -0
  106. package/src/interfaces/simple-public-key-only-buffer.js.map +1 -0
  107. package/src/interfaces/simple-public-key-only.d.ts +4 -0
  108. package/src/interfaces/simple-public-key-only.d.ts.map +1 -0
  109. package/src/interfaces/simple-public-key-only.js +3 -0
  110. package/src/interfaces/simple-public-key-only.js.map +1 -0
  111. package/src/interfaces/single-encrypted-parsed-header.d.ts +35 -0
  112. package/src/interfaces/single-encrypted-parsed-header.d.ts.map +1 -0
  113. package/src/interfaces/single-encrypted-parsed-header.js +3 -0
  114. package/src/interfaces/single-encrypted-parsed-header.js.map +1 -0
  115. package/src/interfaces/{wallet-seed.ts → wallet-seed.d.ts} +3 -3
  116. package/src/interfaces/wallet-seed.d.ts.map +1 -0
  117. package/src/interfaces/wallet-seed.js +3 -0
  118. package/src/interfaces/wallet-seed.js.map +1 -0
  119. package/src/interfaces/wrapped-key-consts.d.ts +7 -0
  120. package/src/interfaces/wrapped-key-consts.d.ts.map +1 -0
  121. package/src/interfaces/wrapped-key-consts.js +3 -0
  122. package/src/interfaces/wrapped-key-consts.js.map +1 -0
  123. package/src/member.d.ts +74 -0
  124. package/src/member.d.ts.map +1 -0
  125. package/src/member.js +273 -0
  126. package/src/member.js.map +1 -0
  127. package/src/services/aes-gcm.d.ts +66 -0
  128. package/src/services/aes-gcm.d.ts.map +1 -0
  129. package/src/services/aes-gcm.js +115 -0
  130. package/src/services/aes-gcm.js.map +1 -0
  131. package/src/services/ecies/crypto-core.d.ts +83 -0
  132. package/src/services/ecies/crypto-core.d.ts.map +1 -0
  133. package/src/services/ecies/crypto-core.js +166 -0
  134. package/src/services/ecies/crypto-core.js.map +1 -0
  135. package/src/services/ecies/file.d.ts +30 -0
  136. package/src/services/ecies/file.d.ts.map +1 -0
  137. package/src/services/ecies/file.js +112 -0
  138. package/src/services/ecies/file.js.map +1 -0
  139. package/src/services/ecies/{index.ts → index.d.ts} +1 -0
  140. package/src/services/ecies/index.d.ts.map +1 -0
  141. package/src/services/ecies/index.js +11 -0
  142. package/src/services/ecies/index.js.map +1 -0
  143. package/src/services/ecies/multi-recipient.d.ts +82 -0
  144. package/src/services/ecies/multi-recipient.d.ts.map +1 -0
  145. package/src/services/ecies/multi-recipient.js +360 -0
  146. package/src/services/ecies/multi-recipient.js.map +1 -0
  147. package/src/services/ecies/service.d.ts +70 -0
  148. package/src/services/ecies/service.d.ts.map +1 -0
  149. package/src/services/ecies/service.js +167 -0
  150. package/src/services/ecies/service.js.map +1 -0
  151. package/src/services/ecies/signature.d.ts +38 -0
  152. package/src/services/ecies/signature.d.ts.map +1 -0
  153. package/src/services/ecies/signature.js +69 -0
  154. package/src/services/ecies/signature.js.map +1 -0
  155. package/src/services/ecies/single-recipient.d.ts +85 -0
  156. package/src/services/ecies/single-recipient.d.ts.map +1 -0
  157. package/src/services/ecies/single-recipient.js +399 -0
  158. package/src/services/ecies/single-recipient.js.map +1 -0
  159. package/src/services/ecies/utilities.d.ts +22 -0
  160. package/src/services/ecies/utilities.d.ts.map +1 -0
  161. package/src/services/ecies/utilities.js +75 -0
  162. package/src/services/ecies/utilities.js.map +1 -0
  163. package/src/services/index.d.ts +4 -0
  164. package/src/services/index.d.ts.map +1 -0
  165. package/src/services/index.js +7 -0
  166. package/src/services/index.js.map +1 -0
  167. package/src/services/pbkdf2.d.ts +106 -0
  168. package/src/services/pbkdf2.d.ts.map +1 -0
  169. package/src/services/pbkdf2.js +195 -0
  170. package/src/services/pbkdf2.js.map +1 -0
  171. package/src/{types.ts → types.d.ts} +9 -26
  172. package/src/types.d.ts.map +1 -0
  173. package/src/types.js +3 -0
  174. package/src/types.js.map +1 -0
  175. package/src/utils.d.ts +11 -0
  176. package/src/utils.d.ts.map +1 -0
  177. package/src/utils.js +82 -0
  178. package/src/utils.js.map +1 -0
  179. package/LICENSE +0 -21
  180. package/src/constants.ts +0 -182
  181. package/src/enumerations/index.ts +0 -1
  182. package/src/enumerations/pbkdf2-profile.ts +0 -8
  183. package/src/i18n/ecies-i18n-factory.ts +0 -435
  184. package/src/interfaces/authenticated-cipher.ts +0 -9
  185. package/src/interfaces/authenticated-decipher.ts +0 -8
  186. package/src/interfaces/checksum-config.ts +0 -4
  187. package/src/interfaces/checksum-consts.ts +0 -13
  188. package/src/interfaces/constants.ts +0 -43
  189. package/src/interfaces/ecies-consts.ts +0 -99
  190. package/src/interfaces/encryption-consts.ts +0 -10
  191. package/src/interfaces/keypair-buffer-with-un-encrypted-private-key.ts +0 -7
  192. package/src/interfaces/keyring-consts.ts +0 -5
  193. package/src/interfaces/member-operational.ts +0 -52
  194. package/src/interfaces/multi-encrypted-parsed-header.ts +0 -24
  195. package/src/interfaces/pbkdf2-result.ts +0 -5
  196. package/src/interfaces/signing-key-private-key-info.ts +0 -12
  197. package/src/interfaces/simple-public-key-only-buffer.ts +0 -3
  198. package/src/interfaces/simple-public-key-only.ts +0 -3
  199. package/src/interfaces/single-encrypted-parsed-header.ts +0 -35
  200. package/src/interfaces/wrapped-key-consts.ts +0 -6
  201. package/src/member.ts +0 -463
  202. package/src/services/aes-gcm.ts +0 -160
  203. package/src/services/ecies/crypto-core.ts +0 -213
  204. package/src/services/ecies/file.ts +0 -174
  205. package/src/services/ecies/multi-recipient.ts +0 -583
  206. package/src/services/ecies/service.ts +0 -351
  207. package/src/services/ecies/signature.ts +0 -91
  208. package/src/services/ecies/single-recipient.ts +0 -676
  209. package/src/services/ecies/utilities.ts +0 -111
  210. package/src/services/index.ts +0 -3
  211. package/src/services/pbkdf2.ts +0 -307
  212. package/src/utils.ts +0 -104
@@ -1,676 +0,0 @@
1
- import {
2
- ECIES,
3
- EciesEncryptionType,
4
- EciesEncryptionTypeEnum,
5
- EciesEncryptionTypeMap,
6
- ECIESError,
7
- ECIESErrorTypeEnum,
8
- encryptionTypeEnumToType,
9
- encryptionTypeToString,
10
- ensureEciesEncryptionTypeEnum,
11
- IECIESConfig,
12
- UINT32_MAX,
13
- UINT64_SIZE,
14
- } from '@digitaldefiance/ecies-lib';
15
- import { PluginI18nEngine, CoreLanguageCode } from '@digitaldefiance/i18n-lib';
16
- import { EciesStringKey } from '@digitaldefiance/ecies-lib';
17
- import {
18
- createCipheriv,
19
- createDecipheriv,
20
- createECDH,
21
- randomBytes,
22
- } from 'crypto';
23
- import { createEciesTranslationEngine, getEciesPluginI18nEngine, NodeEciesComponentId, NodeEciesStringKey } from '../../i18n/ecies-i18n-factory';
24
- import { AuthenticatedCipher } from '../../interfaces/authenticated-cipher';
25
- import { AuthenticatedDecipher } from '../../interfaces/authenticated-decipher';
26
- import { ISingleEncryptedParsedHeader } from '../../interfaces/single-encrypted-parsed-header';
27
- import { EciesCryptoCore } from './crypto-core';
28
-
29
- export class EciesSingleRecipientCore {
30
- protected readonly cryptoCore: EciesCryptoCore;
31
- protected readonly config: IECIESConfig;
32
- protected readonly engine: PluginI18nEngine<CoreLanguageCode>;
33
-
34
- constructor(config: IECIESConfig, engine?: PluginI18nEngine<CoreLanguageCode>) {
35
- this.config = config;
36
- this.cryptoCore = new EciesCryptoCore(config);
37
- this.engine = engine || createEciesTranslationEngine();
38
- }
39
-
40
- /**
41
- * Get the size of the header for a given encryption type
42
- * @param encryptionType The encryption type (single, simple, etc.)
43
- * @returns
44
- */
45
- public getHeaderSize(encryptionType: EciesEncryptionType): number {
46
- switch (encryptionType) {
47
- case 'simple':
48
- return this.cryptoCore.consts.SIMPLE.FIXED_OVERHEAD_SIZE;
49
- case 'single':
50
- return this.cryptoCore.consts.SINGLE.FIXED_OVERHEAD_SIZE;
51
- default:
52
- throw new ECIESError(
53
- ECIESErrorTypeEnum.InvalidEncryptionType,
54
- this.engine,
55
- );
56
- }
57
- }
58
-
59
- /**
60
- * Encrypt a message with a public key
61
- * @param encryptSimple Whether to simple encrypt (without crc, length)
62
- * @param receiverPublicKey The public key of the receiver
63
- * @param message The message to encrypt
64
- * @param preamble Optional preamble to prepend to the encrypted message
65
- * @param options Optional encryption options
66
- * @param options.recipientCount The number of recipients for multiple encryption mode
67
- * @returns The encrypted message
68
- */
69
- public encrypt(
70
- encryptSimple: boolean,
71
- receiverPublicKey: Buffer,
72
- message: Buffer,
73
- preamble: Buffer = Buffer.alloc(0),
74
- ): Buffer {
75
- const encryptionType: EciesEncryptionType = encryptSimple
76
- ? 'simple'
77
- : 'single';
78
- const encryptionTypeBuffer = Buffer.alloc(1);
79
- encryptionTypeBuffer.writeUint8(
80
- EciesEncryptionTypeMap[
81
- encryptionType as keyof typeof EciesEncryptionTypeMap
82
- ] as number,
83
- );
84
- if (message.length > this.cryptoCore.consts.MAX_RAW_DATA_SIZE) {
85
- const pluginEngine = getEciesPluginI18nEngine();
86
- throw new ECIESError(
87
- ECIESErrorTypeEnum.InvalidDataLength,
88
- this.engine,
89
- undefined,
90
- undefined,
91
- {
92
- error: pluginEngine.translate(NodeEciesComponentId, NodeEciesStringKey.Error_MessageLengthExceedsMaximumAllowedSize),
93
- maxLength: String(UINT32_MAX),
94
- messageLength: String(message.length),
95
- },
96
- );
97
- }
98
- // Generate ephemeral ECDH key pair
99
- const ecdh = createECDH(this.config.curveName);
100
- ecdh.generateKeys();
101
-
102
- // Compute shared secret
103
- let sharedSecret: Buffer;
104
- try {
105
- // Make sure we normalize the receiver's public key
106
- const normalizedReceiverPublicKey =
107
- this.cryptoCore.normalizePublicKey(receiverPublicKey);
108
-
109
- // Ensure we're using the properly formatted public key (with 0x04 prefix)
110
- // Our debugging shows only the full format with prefix works correctly
111
- sharedSecret = ecdh.computeSecret(normalizedReceiverPublicKey);
112
- } catch (error: unknown) {
113
- console.error('[ERROR][encrypt] Failed to compute shared secret:', error);
114
- if (error instanceof Error) {
115
- if (
116
- 'code' in error &&
117
- error.code === 'ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY'
118
- ) {
119
- throw new ECIESError(
120
- ECIESErrorTypeEnum.InvalidRecipientPublicKey,
121
- this.engine,
122
- undefined,
123
- undefined,
124
- {
125
- nodeError: error.code,
126
- },
127
- );
128
- }
129
- throw new ECIESError(
130
- ECIESErrorTypeEnum.SecretComputationFailed,
131
- this.engine,
132
- undefined,
133
- undefined,
134
- {
135
- error: error.message,
136
- },
137
- );
138
- }
139
- throw new ECIESError(
140
- ECIESErrorTypeEnum.SecretComputationFailed,
141
- this.engine,
142
- );
143
- }
144
-
145
- // Get the ephemeral public key and ensure it has the 0x04 prefix
146
- let ephemeralPublicKey = ecdh.getPublicKey();
147
- if (ephemeralPublicKey.length === this.cryptoCore.consts.RAW_PUBLIC_KEY_LENGTH) {
148
- ephemeralPublicKey = Buffer.concat([
149
- Buffer.from([this.cryptoCore.consts.PUBLIC_KEY_MAGIC]),
150
- ephemeralPublicKey,
151
- ]);
152
- }
153
-
154
- // Generate random IV
155
- const iv = randomBytes(this.cryptoCore.consts.IV_SIZE);
156
-
157
- // Get the key from the shared secret (always use first 32 bytes)
158
- const symKey = sharedSecret.subarray(0, this.cryptoCore.consts.SYMMETRIC.KEY_SIZE);
159
-
160
- // Create cipher with the derived symmetric key
161
- const cipher = createCipheriv(
162
- this.cryptoCore.consts.SYMMETRIC_ALGORITHM_CONFIGURATION,
163
- symKey,
164
- iv,
165
- ) as unknown as AuthenticatedCipher;
166
-
167
- // Ensure auto padding is enabled
168
- cipher.setAutoPadding(true);
169
-
170
- // Encrypt the message
171
- let encrypted = cipher.update(message);
172
- encrypted = Buffer.concat([encrypted, cipher.final()]);
173
-
174
- // Get and explicitly set the authentication tag to max tag length for consistency
175
- const authTag = cipher.getAuthTag();
176
-
177
- // Add a length prefix to the encrypted data to ensure we can extract the exact number of bytes during decryption
178
- const lengthBuffer =
179
- encryptionType === 'simple' ? Buffer.alloc(0) : Buffer.alloc(UINT64_SIZE);
180
- if (encryptionType === 'single') {
181
- lengthBuffer.writeBigUInt64BE(BigInt(encrypted.length));
182
- }
183
-
184
- // Format: [optional preamble] | type (1) | ephemeralPublicKey (65) | iv (16) | authTag (16) | length (8) | encryptedData
185
- return Buffer.concat([
186
- preamble,
187
- encryptionTypeBuffer,
188
- ephemeralPublicKey,
189
- iv,
190
- authTag,
191
- lengthBuffer,
192
- encrypted,
193
- ]);
194
- }
195
-
196
- /**
197
- * Parse the header from encrypted data
198
- * @param encryptionType The type of encryption (single, simple, etc.) or undefined if not known
199
- * @param data The encrypted data
200
- * @param preambleSize The size of the preamble, if any
201
- * @param options Optional parsing options
202
- * @param options.dataLength The expected length of the data
203
- * @returns The parsed header components
204
- */
205
- public parseEncryptedMessage(
206
- encryptionType: EciesEncryptionTypeEnum | undefined,
207
- data: Buffer,
208
- preambleSize: number = 0,
209
- options?: {
210
- dataLength?: number;
211
- },
212
- ): { header: ISingleEncryptedParsedHeader; data: Buffer; remainder: Buffer } {
213
- // read the encryption type from the first byte after the preamble
214
- const actualEncryptionTypeEnum = ensureEciesEncryptionTypeEnum(
215
- data.readUInt8(preambleSize),
216
- );
217
- // if a type is provided, ensure it matches the actual type
218
- if (
219
- encryptionType !== undefined &&
220
- actualEncryptionTypeEnum !== encryptionType
221
- ) {
222
- throw new ECIESError(
223
- ECIESErrorTypeEnum.InvalidEncryptionType,
224
- this.engine,
225
- undefined,
226
- undefined,
227
- {
228
- expected: encryptionTypeToString(encryptionType),
229
- actual: encryptionTypeToString(actualEncryptionTypeEnum),
230
- },
231
- );
232
- }
233
-
234
- if (actualEncryptionTypeEnum === EciesEncryptionTypeEnum.Multiple) {
235
- throw new ECIESError(
236
- ECIESErrorTypeEnum.InvalidEncryptionType,
237
- this.engine,
238
- undefined,
239
- undefined,
240
- {
241
- expected: 'single or simple',
242
- actual: encryptionTypeToString(actualEncryptionTypeEnum),
243
- },
244
- );
245
- }
246
- const includeLengthAndCrc =
247
- actualEncryptionTypeEnum === EciesEncryptionTypeEnum.Single;
248
-
249
- // check for impossible message
250
- if (
251
- data.length <
252
- (includeLengthAndCrc
253
- ? this.cryptoCore.consts.SINGLE.FIXED_OVERHEAD_SIZE
254
- : this.cryptoCore.consts.SIMPLE.FIXED_OVERHEAD_SIZE)
255
- ) {
256
- throw new ECIESError(
257
- ECIESErrorTypeEnum.InvalidEncryptedDataLength,
258
- this.engine,
259
- undefined,
260
- undefined,
261
- {
262
- required: String(this.cryptoCore.consts.SINGLE.FIXED_OVERHEAD_SIZE),
263
- actual: String(data.length),
264
- },
265
- );
266
- }
267
-
268
- let offset = 0;
269
- const preamble = data.subarray(0, preambleSize);
270
- offset += preambleSize;
271
-
272
- // skip the already-read encryption type
273
- offset += 1;
274
-
275
- // Extract components from the header
276
- const ephemeralPublicKey = data.subarray(
277
- offset,
278
- offset + this.cryptoCore.consts.PUBLIC_KEY_LENGTH,
279
- );
280
- offset += this.cryptoCore.consts.PUBLIC_KEY_LENGTH;
281
-
282
- // Make sure we normalize the ephemeral public key
283
- const normalizedKey =
284
- this.cryptoCore.normalizePublicKey(ephemeralPublicKey);
285
-
286
- const iv = data.subarray(offset, offset + this.cryptoCore.consts.IV_SIZE);
287
- offset += this.cryptoCore.consts.IV_SIZE;
288
-
289
- const authTag = data.subarray(offset, offset + this.cryptoCore.consts.AUTH_TAG_SIZE);
290
- offset += this.cryptoCore.consts.AUTH_TAG_SIZE;
291
-
292
- // Extract the length prefix (4 bytes) after the header components
293
- const dataLengthBuffer = includeLengthAndCrc
294
- ? data.subarray(offset, offset + this.cryptoCore.consts.SINGLE.DATA_LENGTH_SIZE)
295
- : Buffer.alloc(0);
296
- if (includeLengthAndCrc) {
297
- offset += this.cryptoCore.consts.SINGLE.DATA_LENGTH_SIZE;
298
- }
299
-
300
- const dataLength = includeLengthAndCrc
301
- ? Number(dataLengthBuffer.readBigUInt64BE(0))
302
- : options?.dataLength ?? -1;
303
-
304
- if (
305
- includeLengthAndCrc &&
306
- options?.dataLength !== undefined &&
307
- dataLength !== options.dataLength
308
- ) {
309
- const pluginEngine = getEciesPluginI18nEngine();
310
- throw new ECIESError(
311
- ECIESErrorTypeEnum.InvalidEncryptedDataLength,
312
- this.engine,
313
- undefined,
314
- undefined,
315
- {
316
- error: pluginEngine.translate(NodeEciesComponentId, NodeEciesStringKey.Error_EncryptedDataLengthMismatch),
317
- expected: String(dataLength),
318
- actual: String(options.dataLength),
319
- },
320
- );
321
- }
322
-
323
- // No CRC in Single encryption (AES-GCM provides authentication)
324
-
325
- const encryptedData =
326
- dataLength > 0
327
- ? data.subarray(offset, offset + dataLength)
328
- : data.subarray(offset);
329
- if (includeLengthAndCrc) {
330
- offset += dataLength;
331
- }
332
-
333
- if (includeLengthAndCrc && encryptedData.length !== dataLength) {
334
- throw new ECIESError(
335
- ECIESErrorTypeEnum.InvalidEncryptedDataLength,
336
- this.engine,
337
- undefined,
338
- undefined,
339
- {
340
- expected: String(dataLength),
341
- actual: String(encryptedData.length),
342
- },
343
- );
344
- }
345
-
346
- const remainder = includeLengthAndCrc
347
- ? data.subarray(offset)
348
- : Buffer.alloc(0);
349
-
350
- // No CRC validation needed (AES-GCM provides authentication)
351
-
352
- // Validate all header components have the correct lengths
353
- if (normalizedKey.length !== this.cryptoCore.consts.PUBLIC_KEY_LENGTH) {
354
- const pluginEngine = getEciesPluginI18nEngine();
355
- throw new ECIESError(
356
- ECIESErrorTypeEnum.InvalidEphemeralPublicKey,
357
- this.engine,
358
- undefined,
359
- undefined,
360
- {
361
- error:
362
- pluginEngine.translate(NodeEciesComponentId, NodeEciesStringKey.Error_EphemeralPublicKeyLengthMismatch),
363
- expected: String(this.cryptoCore.consts.PUBLIC_KEY_LENGTH),
364
- actual: String(normalizedKey.length),
365
- },
366
- );
367
- }
368
-
369
- if (iv.length !== this.cryptoCore.consts.IV_SIZE) {
370
- throw new ECIESError(
371
- ECIESErrorTypeEnum.InvalidIVLength,
372
- this.engine,
373
- undefined,
374
- undefined,
375
- {
376
- expected: String(this.cryptoCore.consts.IV_SIZE),
377
- actual: String(iv.length),
378
- },
379
- );
380
- }
381
-
382
- if (authTag.length !== this.cryptoCore.consts.AUTH_TAG_SIZE) {
383
- throw new ECIESError(
384
- ECIESErrorTypeEnum.InvalidAuthTagLength,
385
- this.engine,
386
- undefined,
387
- undefined,
388
- {
389
- expected: String(this.cryptoCore.consts.AUTH_TAG_SIZE),
390
- actual: String(authTag.length),
391
- },
392
- );
393
- }
394
-
395
- return {
396
- header: {
397
- encryptionType: actualEncryptionTypeEnum,
398
- ephemeralPublicKey: normalizedKey,
399
- iv,
400
- authTag,
401
- dataLength,
402
- headerSize: includeLengthAndCrc
403
- ? this.cryptoCore.consts.SINGLE.FIXED_OVERHEAD_SIZE
404
- : this.cryptoCore.consts.SINGLE.FIXED_OVERHEAD_SIZE,
405
- },
406
- data: encryptedData,
407
- remainder,
408
- };
409
- }
410
-
411
- /**
412
- * Decrypts data encrypted with ECIES using a header
413
- * This method maintains backward compatibility with the original implementation
414
- * by returning just the Buffer. For detailed information, use decryptSingleWithHeaderEx
415
- * @param encryptionType The type of encryption (single, simple, etc.)
416
- * @param privateKey The private key to decrypt the data
417
- * @param encryptedData The data to decrypt
418
- * @param preambleSize The size of the preamble, if any
419
- * @param options Optional decryption options
420
- * @param options.dataLength The expected length of the data
421
- * @returns The decrypted data buffer
422
- */
423
- public decryptWithHeader(
424
- encryptionType: EciesEncryptionTypeEnum | undefined,
425
- privateKey: Buffer,
426
- encryptedData: Buffer,
427
- preambleSize: number = 0,
428
- options?: {
429
- dataLength?: number;
430
- },
431
- ): Buffer {
432
- const readEncryptionType = encryptedData.readUInt8(
433
- preambleSize,
434
- ) as EciesEncryptionTypeEnum;
435
- const actualEncryptionTypeEnum =
436
- ensureEciesEncryptionTypeEnum(readEncryptionType);
437
- if (
438
- encryptionType !== undefined &&
439
- actualEncryptionTypeEnum !== encryptionType
440
- ) {
441
- const expectedType = encryptionTypeEnumToType(encryptionType);
442
- const actualEncryptionType = encryptionTypeEnumToType(
443
- actualEncryptionTypeEnum,
444
- );
445
- throw new ECIESError(
446
- ECIESErrorTypeEnum.InvalidEncryptionType,
447
- this.engine,
448
- undefined,
449
- undefined,
450
- {
451
- expected: expectedType,
452
- actual: actualEncryptionType,
453
- },
454
- );
455
- }
456
- try {
457
- // Call the extended version and return only the decrypted buffer for backward compatibility
458
- const result = this.decryptWithHeaderEx(
459
- actualEncryptionTypeEnum,
460
- privateKey,
461
- encryptedData,
462
- preambleSize,
463
- options,
464
- );
465
- return result.decrypted;
466
- } catch (error) {
467
- if (error instanceof ECIESError) {
468
- throw error;
469
- }
470
- throw new ECIESError(
471
- ECIESErrorTypeEnum.DecryptionFailed,
472
- this.engine,
473
- undefined,
474
- undefined,
475
- {
476
- error: error instanceof Error ? error.message : String(error),
477
- },
478
- );
479
- }
480
- }
481
-
482
- /**
483
- * Extended version of decryptSingleWithHeader that provides more detailed information
484
- * @param encryptionType The type of encryption (single, simple, etc.)
485
- * @param privateKey The private key to decrypt the data
486
- * @param encryptedData The data to decrypt
487
- * @param preambleSize The size of the preamble, if any
488
- * @param options Optional decryption options
489
- * @param options.dataLength The expected length of the data
490
- * @returns The decrypted data and the number of bytes consumed from the input buffer
491
- */
492
- public decryptWithHeaderEx(
493
- encryptionType: EciesEncryptionTypeEnum | undefined,
494
- privateKey: Buffer,
495
- encryptedData: Buffer,
496
- preambleSize: number = 0,
497
- options?: {
498
- dataLength?: number;
499
- },
500
- ): { decrypted: Buffer; consumedBytes: number } {
501
- try {
502
- const { data, header } = this.parseEncryptedMessage(
503
- encryptionType,
504
- encryptedData,
505
- preambleSize,
506
- options,
507
- );
508
-
509
- // Normalize the public key (ensuring 0x04 prefix)
510
- const normalizedKey = this.cryptoCore.normalizePublicKey(
511
- header.ephemeralPublicKey,
512
- );
513
-
514
- // Decrypt using components with the normalized key
515
- const decrypted = this.decryptWithComponents(
516
- privateKey,
517
- normalizedKey,
518
- header.iv,
519
- header.authTag,
520
- data,
521
- );
522
-
523
- return {
524
- decrypted,
525
- consumedBytes: header.dataLength + header.headerSize,
526
- };
527
- } catch (error) {
528
- if (error instanceof ECIESError) {
529
- throw error;
530
- }
531
- throw new ECIESError(
532
- ECIESErrorTypeEnum.DecryptionFailed,
533
- this.engine,
534
- undefined,
535
- undefined,
536
- {
537
- error: error instanceof Error ? error.message : String(error),
538
- },
539
- );
540
- }
541
- }
542
-
543
- /**
544
- * Decrypts data encrypted with ECIES using components
545
- * @param privateKey The private key to decrypt the data
546
- * @param ephemeralPublicKey The ephemeral public key used to encrypt the data
547
- * @param iv The initialization vector used to encrypt the data
548
- * @param authTag The authentication tag used to encrypt the data
549
- * @param encrypted The encrypted data
550
- * @returns The decrypted data
551
- */
552
- public decryptWithComponents(
553
- privateKey: Buffer,
554
- ephemeralPublicKey: Buffer,
555
- iv: Buffer,
556
- authTag: Buffer,
557
- encrypted: Buffer,
558
- ): Buffer {
559
- try {
560
- // Ensure the ephemeral public key has the correct format
561
- const normalizedEphemeralKey =
562
- this.cryptoCore.normalizePublicKey(ephemeralPublicKey);
563
-
564
- // Set up ECDH with the private key
565
- const ecdh = createECDH(this.config.curveName);
566
- ecdh.setPrivateKey(privateKey);
567
-
568
- // Based on our ECDH test, we need to consistently use the full key with 0x04 prefix
569
- // Our debugging showed the raw keys without prefix always fail
570
- let sharedSecret: Buffer;
571
- try {
572
- sharedSecret = ecdh.computeSecret(normalizedEphemeralKey);
573
- } catch (err) {
574
- console.error('[ERROR][decrypt] Failed to compute shared secret:', err);
575
- throw new ECIESError(
576
- ECIESErrorTypeEnum.DecryptionFailed,
577
- this.engine,
578
- undefined,
579
- undefined,
580
- {
581
- originalError: err instanceof Error ? err.message : String(err),
582
- stage: 'shared_secret_computation',
583
- },
584
- );
585
- }
586
-
587
- // Get the key from the shared secret (always use first 32 bytes)
588
- const symKey = sharedSecret.subarray(0, this.cryptoCore.consts.SYMMETRIC.KEY_SIZE);
589
-
590
- // Create decipher with shared secret-derived key
591
- const decipher = createDecipheriv(
592
- this.cryptoCore.consts.SYMMETRIC_ALGORITHM_CONFIGURATION,
593
- symKey,
594
- iv,
595
- ) as unknown as AuthenticatedDecipher;
596
-
597
- // Validate the tag and IV
598
- if (authTag.length !== this.cryptoCore.consts.AUTH_TAG_SIZE) {
599
- throw new ECIESError(
600
- ECIESErrorTypeEnum.DecryptionFailed,
601
- this.engine,
602
- undefined,
603
- undefined,
604
- {
605
- expected: String(this.cryptoCore.consts.AUTH_TAG_SIZE),
606
- actual: String(authTag.length),
607
- stage: 'auth_tag_validation',
608
- },
609
- );
610
- }
611
-
612
- if (iv.length !== this.cryptoCore.consts.IV_SIZE) {
613
- throw new ECIESError(
614
- ECIESErrorTypeEnum.DecryptionFailed,
615
- this.engine,
616
- undefined,
617
- undefined,
618
- {
619
- expected: String(this.cryptoCore.consts.IV_SIZE),
620
- actual: String(iv.length),
621
- stage: 'iv_validation',
622
- },
623
- );
624
- }
625
-
626
- // Set the authentication tag for GCM mode
627
- decipher.setAuthTag(authTag);
628
-
629
- // Decrypt the data
630
- try {
631
- // Handle edge case where encrypted data might be empty or malformed
632
- const pluginEngine = getEciesPluginI18nEngine();
633
- if (encrypted.length === 0) {
634
- throw new Error(pluginEngine.translate(NodeEciesComponentId, NodeEciesStringKey.Error_EncryptedDataIsEmpty));
635
- }
636
-
637
- const firstPart = decipher.update(encrypted);
638
- const finalPart = decipher.final();
639
- const result = Buffer.concat([firstPart, finalPart]);
640
-
641
- return result;
642
- } catch (err) {
643
- throw new ECIESError(
644
- ECIESErrorTypeEnum.DecryptionFailed,
645
- this.engine,
646
- undefined,
647
- undefined,
648
- {
649
- error: err instanceof Error ? err.message : String(err),
650
- stage: 'decipher_operation',
651
- },
652
- );
653
- }
654
- } catch (error) {
655
- if (error instanceof ECIESError) {
656
- throw error;
657
- }
658
-
659
- // Wrap non-EciesError in an EciesError
660
- throw new ECIESError(
661
- ECIESErrorTypeEnum.DecryptionFailed,
662
- this.engine,
663
- undefined,
664
- undefined,
665
- {
666
- error: error instanceof Error ? error.message : String(error),
667
- privateKeyLength: String(privateKey.length),
668
- ephemeralPublicKeyLength: String(ephemeralPublicKey.length),
669
- ivLength: String(iv.length),
670
- authTagLength: String(authTag.length),
671
- encryptedLength: String(encrypted.length),
672
- },
673
- );
674
- }
675
- }
676
- }