asherah 1.3.24 → 1.3.25

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/.asherah-version CHANGED
@@ -1 +1 @@
1
- ASHERAH_VERSION=v0.4.26
1
+ ASHERAH_VERSION=v0.4.27
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "asherah",
3
- "version": "1.3.24",
3
+ "version": "1.3.25",
4
4
  "description": "Asherah envelope encryption and key rotation library",
5
5
  "exports": {
6
6
  "node-addons": "./dist/asherah.node"
package/src/asherah.cc CHANGED
@@ -7,572 +7,575 @@
7
7
  #include <mutex>
8
8
  #include <napi.h>
9
9
 
10
- size_t est_intermediate_key_overhead;
11
- size_t maximum_stack_alloc_size = 2048;
12
-
13
- int32_t setup_state = 0;
14
- std::mutex asherah_lock;
15
-
16
- void setup(const Napi::CallbackInfo &info) {
17
- std::lock_guard<std::mutex> lock(asherah_lock);
18
-
19
- if (unlikely(verbose_flag)) {
20
- debug_log(__func__, "called");
21
- }
22
-
23
- if (unlikely(setup_state == 1)) {
24
- log_error_and_throw(__func__, "setup called twice");
25
- }
26
-
27
- if (unlikely(info.Length() < 1)) {
28
- log_error_and_throw(__func__, "Wrong number of arguments");
29
- }
30
-
31
- Napi::String config;
32
- Napi::Object config_json;
33
- Napi::Env env = info.Env();
34
- Napi::Object json = env.Global().Get("JSON").As<Napi::Object>();
35
- if (likely(info[0].IsObject())) {
36
- config_json = info[0].As<Napi::Object>();
37
- Napi::Function stringify = json.Get("stringify").As<Napi::Function>();
38
- config = stringify.Call(json, {config_json}).As<Napi::String>();
39
- } else if (likely(info[0].IsString())) {
40
- config = info[0].As<Napi::String>();
41
- Napi::Function parse = json.Get("parse").As<Napi::Function>();
42
- config_json = parse.Call(json, {config}).As<Napi::Object>();
43
- } else {
44
- log_error_and_throw(__func__, "Wrong argument type");
45
- }
46
-
47
- Napi::String product_id = config_json.Get("ProductID").As<Napi::String>();
48
- Napi::String service_name = config_json.Get("ServiceName").As<Napi::String>();
49
-
50
- est_intermediate_key_overhead =
51
- product_id.Utf8Value().length() + service_name.Utf8Value().length();
52
-
53
- Napi::Value verbose = config_json.Get("Verbose");
54
- if (likely(verbose.IsBoolean())) {
55
- verbose_flag = verbose.As<Napi::Boolean>().Value();
56
- debug_log(__func__, "verbose_flag: " + std::to_string(verbose_flag));
57
- } else {
58
- verbose_flag = 0;
59
- debug_log(__func__, "verbose_flag: defaulting to false");
60
- }
61
-
62
- char *config_cobhan_buffer;
63
- size_t config_copied_bytes;
64
- NAPI_STRING_TO_CBUFFER(env, config, config_cobhan_buffer, config_copied_bytes,
65
- maximum_stack_alloc_size, __func__);
66
-
67
- char *config_canary_ptr = get_canary_ptr(config_cobhan_buffer);
68
- if (unlikely(!check_canary_ptr(config_canary_ptr))) {
69
- log_error_and_throw(__func__,
70
- "Failed initial canary check for config_cobhan_buffer");
71
- }
72
-
73
- // extern GoInt32 SetupJson(void* configJson);
74
- GoInt32 result = SetupJson(config_cobhan_buffer);
75
-
76
- if (unlikely(verbose_flag)) {
77
- debug_log(__func__, "Returned from asherah-cobhan SetupJson");
78
- }
79
-
80
- if (unlikely(!check_canary_ptr(config_canary_ptr))) {
81
- log_error_and_throw(
82
- __func__, "Failed post-call canary check for config_cobhan_buffer");
83
- }
84
-
85
- if (unlikely(result < 0)) {
86
- log_error_and_throw(__func__, asherah_cobhan_error_to_string(result));
87
- }
88
- setup_state = 1;
89
- }
90
-
91
- Napi::String encrypt(const Napi::CallbackInfo &info) {
92
- std::lock_guard<std::mutex> lock(asherah_lock);
93
-
94
- if (unlikely(verbose_flag)) {
95
- debug_log(__func__, "called");
96
- }
97
-
98
- if (unlikely(setup_state == 0)) {
99
- log_error_and_throw(__func__, "setup() not called");
100
- }
101
-
102
- if (unlikely(info.Length() < 2)) {
103
- log_error_and_throw(__func__, "Wrong number of arguments");
104
- }
105
-
106
- if (unlikely(!info[0].IsString() || !info[1].IsBuffer())) {
107
- log_error_and_throw(__func__, "Wrong argument types");
108
- }
109
-
110
- Napi::Env env = info.Env();
111
-
112
- Napi::String partition_id = info[0].As<Napi::String>();
113
- char *partition_id_cobhan_buffer;
114
- size_t partition_id_copied_bytes;
115
- NAPI_STRING_TO_CBUFFER(env, partition_id, partition_id_cobhan_buffer,
116
- partition_id_copied_bytes, maximum_stack_alloc_size,
117
- __func__);
118
-
119
- Napi::Buffer<unsigned char> input_napi_buffer =
120
- info[1].As<Napi::Buffer<unsigned char>>();
121
- char *input_cobhan_buffer;
122
- size_t input_copied_bytes;
123
- NAPI_BUFFER_TO_CBUFFER(env, input_napi_buffer, input_cobhan_buffer,
124
- input_copied_bytes, maximum_stack_alloc_size,
125
- __func__);
126
-
127
- Napi::String output =
128
- encrypt_to_json(env, partition_id_copied_bytes, input_copied_bytes,
129
- partition_id_cobhan_buffer, input_cobhan_buffer);
130
-
131
- if (unlikely(verbose_flag)) {
132
- debug_log(__func__, "finished");
133
- }
134
-
135
- return output;
136
- }
137
-
138
- Napi::String encrypt_string(const Napi::CallbackInfo &info) {
139
- std::lock_guard<std::mutex> lock(asherah_lock);
140
-
141
- if (unlikely(verbose_flag)) {
142
- debug_log(__func__, "called");
143
- }
144
-
145
- if (unlikely(setup_state == 0)) {
146
- log_error_and_throw(__func__, "setup() not called");
147
- }
148
-
149
- if (unlikely(info.Length() < 2)) {
150
- log_error_and_throw(__func__, "Wrong number of arguments");
151
- }
152
-
153
- if (unlikely(!info[0].IsString() || !info[1].IsString())) {
154
- log_error_and_throw(__func__, "Wrong argument types");
155
- }
156
-
157
- Napi::Env env = info.Env();
158
-
159
- Napi::String partition_id = info[0].As<Napi::String>();
160
- char *partition_id_cobhan_buffer;
161
- size_t partition_id_copied_bytes;
162
- NAPI_STRING_TO_CBUFFER(env, partition_id, partition_id_cobhan_buffer,
163
- partition_id_copied_bytes, maximum_stack_alloc_size,
164
- __func__);
165
-
166
- Napi::String input = info[1].As<Napi::String>();
167
- char *input_cobhan_buffer;
168
- size_t input_copied_bytes;
169
- NAPI_STRING_TO_CBUFFER(env, input, input_cobhan_buffer, input_copied_bytes,
170
- maximum_stack_alloc_size, __func__);
171
-
172
- Napi::String output =
173
- encrypt_to_json(env, partition_id_copied_bytes, input_copied_bytes,
174
- partition_id_cobhan_buffer, input_cobhan_buffer);
175
-
176
- if (unlikely(verbose_flag)) {
177
- debug_log(__func__, "finished");
178
- }
179
-
180
- return output;
181
- }
182
-
183
- Napi::String encrypt_to_json(Napi::Env &env, size_t partition_bytes,
184
- size_t data_bytes,
185
- char *partition_id_cobhan_buffer,
186
- char *input_cobhan_buffer) {
187
-
188
- size_t asherah_output_size_bytes =
189
- estimate_asherah_output_size_bytes(data_bytes, partition_bytes);
190
-
191
- if (unlikely(verbose_flag)) {
192
- debug_log(__func__, " asherah_output_size_bytes " +
193
- std::to_string(asherah_output_size_bytes));
194
- }
195
-
196
- char *output_cobhan_buffer;
197
- ALLOCATE_CBUFFER(output_cobhan_buffer, asherah_output_size_bytes,
198
- maximum_stack_alloc_size, __func__);
199
-
200
- char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
201
- if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
202
- log_error_and_throw(
203
- __func__, "Failed initial canary check for partition_id_cobhan_buffer");
204
- }
205
- char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
206
- if (unlikely(!check_canary_ptr(input_canary_ptr))) {
207
- log_error_and_throw(__func__,
208
- "Failed initial canary check for input_cobhan_buffer");
209
- }
210
- char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
211
- if (unlikely(!check_canary_ptr(output_canary_ptr))) {
212
- log_error_and_throw(__func__,
213
- "Failed initial canary check for output_cobhan_buffer");
214
- }
215
-
216
- if (unlikely(verbose_flag)) {
217
- debug_log(__func__, "Calling asherah-cobhan EncryptToJson");
218
- }
219
-
220
- // extern GoInt32 EncryptToJson(void* partitionIdPtr, void* dataPtr, void*
221
- // jsonPtr);
222
- GoInt32 result = EncryptToJson(partition_id_cobhan_buffer,
223
- input_cobhan_buffer, output_cobhan_buffer);
224
-
225
- if (unlikely(verbose_flag)) {
226
- debug_log(__func__, "Returning from asherah-cobhan EncryptToJson");
227
- }
228
-
229
- if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
230
- log_error_and_throw(
231
- __func__,
232
- "Failed post-call canary check for partition_id_cobhan_buffer");
233
- }
234
- if (unlikely(!check_canary_ptr(input_canary_ptr))) {
235
- log_error_and_throw(
236
- __func__, "Failed post-call canary check for input_cobhan_buffer");
237
- }
238
- if (unlikely(!check_canary_ptr(output_canary_ptr))) {
239
- log_error_and_throw(
240
- __func__, "Failed post-call canary check for output_cobhan_buffer");
241
- }
242
-
243
- if (unlikely(result < 0)) {
244
- log_error_and_throw(__func__, asherah_cobhan_error_to_string(result));
245
- }
246
-
247
- Napi::String output = cbuffer_to_nstring(env, output_cobhan_buffer);
248
- return output;
249
- }
250
-
251
- Napi::Buffer<unsigned char> decrypt(const Napi::CallbackInfo &info) {
252
- std::lock_guard<std::mutex> lock(asherah_lock);
253
-
254
- if (unlikely(verbose_flag)) {
255
- debug_log(__func__, "called");
256
- }
257
-
258
- if (unlikely(setup_state == 0)) {
259
- log_error_and_throw(__func__, "setup() not called");
260
- }
261
-
262
- if (unlikely(info.Length() < 2)) {
263
- log_error_and_throw(__func__, "Wrong number of arguments");
264
- }
265
-
266
- if (unlikely(!info[0].IsString() || !info[1].IsString())) {
267
- log_error_and_throw(__func__, "Wrong argument types");
268
- }
269
-
270
- Napi::Env env = info.Env();
271
-
272
- Napi::String partition_id = info[0].As<Napi::String>();
273
- char *partition_id_cobhan_buffer;
274
- size_t partition_id_copied_bytes;
275
- NAPI_STRING_TO_CBUFFER(env, partition_id, partition_id_cobhan_buffer,
276
- partition_id_copied_bytes, maximum_stack_alloc_size,
277
- __func__);
278
-
279
- Napi::String input = info[1].As<Napi::String>();
280
- char *input_cobhan_buffer;
281
- size_t input_copied_bytes;
282
- NAPI_STRING_TO_CBUFFER(env, input, input_cobhan_buffer, input_copied_bytes,
283
- maximum_stack_alloc_size, __func__);
284
-
285
- char *output_cobhan_buffer;
286
- ALLOCATE_CBUFFER(output_cobhan_buffer, input_copied_bytes,
287
- maximum_stack_alloc_size, __func__);
288
-
289
- char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
290
- if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
291
- log_error_and_throw(
292
- __func__, "Failed initial canary check for partition_id_cobhan_buffer");
293
- }
294
- char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
295
- if (unlikely(!check_canary_ptr(input_canary_ptr))) {
296
- log_error_and_throw(__func__,
297
- "Failed initial canary check for input_cobhan_buffer");
298
- }
299
- char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
300
- if (unlikely(!check_canary_ptr(output_canary_ptr))) {
301
- log_error_and_throw(__func__,
302
- "Failed initial canary check for output_cobhan_buffer");
303
- }
304
-
305
- if (unlikely(verbose_flag)) {
306
- debug_log(__func__, "Calling asherah-cobhan DecryptFromJson");
307
- }
308
-
309
- // extern GoInt32 DecryptFromJson(void* partitionIdPtr, void* jsonPtr, void*
310
- // dataPtr);
311
- GoInt32 result = DecryptFromJson(partition_id_cobhan_buffer,
312
- input_cobhan_buffer, output_cobhan_buffer);
313
-
314
- if (unlikely(verbose_flag)) {
315
- debug_log(__func__, "Returned from asherah-cobhan DecryptFromJson");
316
- }
317
-
318
- if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
319
- log_error_and_throw(
320
- __func__,
321
- "Failed post-call canary check for partition_id_cobhan_buffer");
322
- }
323
- if (unlikely(!check_canary_ptr(input_canary_ptr))) {
324
- log_error_and_throw(
325
- __func__, "Failed post-call canary check for input_cobhan_buffer");
326
- }
327
- if (unlikely(!check_canary_ptr(output_canary_ptr))) {
328
- log_error_and_throw(
329
- __func__, "Failed post-call canary check for output_cobhan_buffer");
330
- }
331
-
332
- if (unlikely(result < 0)) {
333
- log_error_and_throw(__func__, asherah_cobhan_error_to_string(result));
334
- }
335
-
336
- Napi::Buffer<unsigned char> output =
337
- cbuffer_to_nbuffer(env, output_cobhan_buffer);
338
-
339
- if (unlikely(verbose_flag)) {
340
- debug_log(__func__, "finished");
341
- }
342
-
343
- return output;
344
- }
345
-
346
- Napi::String decrypt_string(const Napi::CallbackInfo &info) {
347
- std::lock_guard<std::mutex> lock(asherah_lock);
348
-
349
- if (unlikely(verbose_flag)) {
350
- debug_log(__func__, "called");
351
- }
352
-
353
- if (unlikely(setup_state == 0)) {
354
- log_error_and_throw(__func__, "setup() not called");
355
- }
356
-
357
- if (unlikely(info.Length() < 2)) {
358
- log_error_and_throw(__func__, "Wrong number of arguments");
359
- }
360
-
361
- if (unlikely(!info[0].IsString() || !info[1].IsString())) {
362
- log_error_and_throw(__func__, "Wrong argument types");
363
- }
364
-
365
- Napi::Env env = info.Env();
366
-
367
- Napi::String partition_id = info[0].As<Napi::String>();
368
- char *partition_id_cobhan_buffer;
369
- size_t partition_id_copied_bytes;
370
- NAPI_STRING_TO_CBUFFER(env, partition_id, partition_id_cobhan_buffer,
371
- partition_id_copied_bytes, maximum_stack_alloc_size,
372
- __func__);
373
-
374
- Napi::String input = info[1].As<Napi::String>();
375
- char *input_cobhan_buffer;
376
- size_t input_copied_bytes;
377
- NAPI_STRING_TO_CBUFFER(env, input, input_cobhan_buffer, input_copied_bytes,
378
- maximum_stack_alloc_size, __func__);
379
-
380
- char *output_cobhan_buffer;
381
- ALLOCATE_CBUFFER(output_cobhan_buffer, input_copied_bytes,
382
- maximum_stack_alloc_size, __func__);
383
-
384
- char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
385
- if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
386
- log_error_and_throw(
387
- __func__, "Failed initial canary check for partition_id_cobhan_buffer");
388
- }
389
- char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
390
- if (unlikely(!check_canary_ptr(input_canary_ptr))) {
391
- log_error_and_throw(__func__,
392
- "Failed initial canary check for input_cobhan_buffer");
393
- }
394
- char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
395
- if (unlikely(!check_canary_ptr(output_canary_ptr))) {
396
- log_error_and_throw(__func__,
397
- "Failed initial canary check for output_cobhan_buffer");
398
- }
399
-
400
- if (unlikely(verbose_flag)) {
401
- debug_log(__func__, "Calling asherah-cobhan DecryptFromJson");
402
- }
403
-
404
- // extern GoInt32 DecryptFromJson(void* partitionIdPtr, void* jsonPtr, void*
405
- // dataPtr);
406
- GoInt32 result = DecryptFromJson(partition_id_cobhan_buffer,
10
+ class Asherah : public Napi::Addon<Asherah> {
11
+ public:
12
+ Asherah(Napi::Env env, Napi::Object exports) {
13
+ DefineAddon(exports,
14
+ {InstanceMethod("setup", &Asherah::SetupAsherah),
15
+ InstanceMethod("encrypt", &Asherah::Encrypt),
16
+ InstanceMethod("encrypt_string", &Asherah::EncryptString),
17
+ InstanceMethod("decrypt", &Asherah::Decrypt),
18
+ InstanceMethod("decrypt_string", &Asherah::DecryptString),
19
+ InstanceMethod("shutdown", &Asherah::ShutdownAsherah),
20
+ InstanceMethod("set_max_stack_alloc_item_size",
21
+ &Asherah::SetMaxStackAllocItemSize),
22
+ InstanceMethod("set_safety_padding_overhead",
23
+ &Asherah::SetSafetyPaddingOverhead)});
24
+ }
25
+
26
+ private:
27
+ size_t est_intermediate_key_overhead;
28
+ size_t maximum_stack_alloc_size = 2048;
29
+
30
+ int32_t setup_state = 0;
31
+ std::mutex asherah_lock;
32
+
33
+ void SetupAsherah(const Napi::CallbackInfo &info) {
34
+ std::lock_guard<std::mutex> lock(asherah_lock);
35
+
36
+ if (unlikely(verbose_flag)) {
37
+ debug_log(__func__, "called");
38
+ }
39
+
40
+ if (unlikely(setup_state == 1)) {
41
+ log_error_and_throw(__func__, "setup called twice");
42
+ }
43
+
44
+ if (unlikely(info.Length() < 1)) {
45
+ log_error_and_throw(__func__, "Wrong number of arguments");
46
+ }
47
+
48
+ Napi::String config;
49
+ Napi::Object config_json;
50
+ Napi::Env env = info.Env();
51
+ Napi::Object json = env.Global().Get("JSON").As<Napi::Object>();
52
+ if (likely(info[0].IsObject())) {
53
+ config_json = info[0].As<Napi::Object>();
54
+ Napi::Function stringify = json.Get("stringify").As<Napi::Function>();
55
+ config = stringify.Call(json, {config_json}).As<Napi::String>();
56
+ } else if (likely(info[0].IsString())) {
57
+ config = info[0].As<Napi::String>();
58
+ Napi::Function parse = json.Get("parse").As<Napi::Function>();
59
+ config_json = parse.Call(json, {config}).As<Napi::Object>();
60
+ } else {
61
+ log_error_and_throw(__func__, "Wrong argument type");
62
+ }
63
+
64
+ Napi::String product_id = config_json.Get("ProductID").As<Napi::String>();
65
+ Napi::String service_name =
66
+ config_json.Get("ServiceName").As<Napi::String>();
67
+
68
+ est_intermediate_key_overhead =
69
+ product_id.Utf8Value().length() + service_name.Utf8Value().length();
70
+
71
+ Napi::Value verbose = config_json.Get("Verbose");
72
+ if (likely(verbose.IsBoolean())) {
73
+ verbose_flag = verbose.As<Napi::Boolean>().Value();
74
+ debug_log(__func__, "verbose_flag: " + std::to_string(verbose_flag));
75
+ } else {
76
+ verbose_flag = 0;
77
+ debug_log(__func__, "verbose_flag: defaulting to false");
78
+ }
79
+
80
+ char *config_cobhan_buffer;
81
+ size_t config_copied_bytes;
82
+ NAPI_STRING_TO_CBUFFER(env, config, config_cobhan_buffer,
83
+ config_copied_bytes, maximum_stack_alloc_size,
84
+ __func__);
85
+
86
+ char *config_canary_ptr = get_canary_ptr(config_cobhan_buffer);
87
+ if (unlikely(!check_canary_ptr(config_canary_ptr))) {
88
+ log_error_and_throw(
89
+ __func__, "Failed initial canary check for config_cobhan_buffer");
90
+ }
91
+
92
+ // extern GoInt32 SetupJson(void* configJson);
93
+ GoInt32 result = SetupJson(config_cobhan_buffer);
94
+
95
+ if (unlikely(verbose_flag)) {
96
+ debug_log(__func__, "Returned from asherah-cobhan SetupJson");
97
+ }
98
+
99
+ if (unlikely(!check_canary_ptr(config_canary_ptr))) {
100
+ log_error_and_throw(
101
+ __func__, "Failed post-call canary check for config_cobhan_buffer");
102
+ }
103
+
104
+ if (unlikely(result < 0)) {
105
+ log_error_and_throw(__func__, AsherahCobhanErrorToString(result));
106
+ }
107
+ setup_state = 1;
108
+ }
109
+
110
+ Napi::Value Encrypt(const Napi::CallbackInfo &info) {
111
+ std::lock_guard<std::mutex> lock(asherah_lock);
112
+
113
+ if (unlikely(verbose_flag)) {
114
+ debug_log(__func__, "called");
115
+ }
116
+
117
+ if (unlikely(setup_state == 0)) {
118
+ log_error_and_throw(__func__, "setup() not called");
119
+ }
120
+
121
+ if (unlikely(info.Length() < 2)) {
122
+ log_error_and_throw(__func__, "Wrong number of arguments");
123
+ }
124
+
125
+ if (unlikely(!info[0].IsString() || !info[1].IsBuffer())) {
126
+ log_error_and_throw(__func__, "Wrong argument types");
127
+ }
128
+
129
+ Napi::Env env = info.Env();
130
+
131
+ Napi::String partition_id = info[0].As<Napi::String>();
132
+ char *partition_id_cobhan_buffer;
133
+ size_t partition_id_copied_bytes;
134
+ NAPI_STRING_TO_CBUFFER(env, partition_id, partition_id_cobhan_buffer,
135
+ partition_id_copied_bytes, maximum_stack_alloc_size,
136
+ __func__);
137
+
138
+ Napi::Buffer<unsigned char> input_napi_buffer =
139
+ info[1].As<Napi::Buffer<unsigned char>>();
140
+ char *input_cobhan_buffer;
141
+ size_t input_copied_bytes;
142
+ NAPI_BUFFER_TO_CBUFFER(env, input_napi_buffer, input_cobhan_buffer,
143
+ input_copied_bytes, maximum_stack_alloc_size,
144
+ __func__);
145
+
146
+ Napi::String output = EncryptCobhanBufferToJson(
147
+ env, partition_id_copied_bytes, input_copied_bytes,
148
+ partition_id_cobhan_buffer, input_cobhan_buffer);
149
+
150
+ if (unlikely(verbose_flag)) {
151
+ debug_log(__func__, "finished");
152
+ }
153
+
154
+ return output;
155
+ }
156
+
157
+ Napi::Value EncryptString(const Napi::CallbackInfo &info) {
158
+ std::lock_guard<std::mutex> lock(asherah_lock);
159
+
160
+ if (unlikely(verbose_flag)) {
161
+ debug_log(__func__, "called");
162
+ }
163
+
164
+ if (unlikely(setup_state == 0)) {
165
+ log_error_and_throw(__func__, "setup() not called");
166
+ }
167
+
168
+ if (unlikely(info.Length() < 2)) {
169
+ log_error_and_throw(__func__, "Wrong number of arguments");
170
+ }
171
+
172
+ if (unlikely(!info[0].IsString() || !info[1].IsString())) {
173
+ log_error_and_throw(__func__, "Wrong argument types");
174
+ }
175
+
176
+ Napi::Env env = info.Env();
177
+
178
+ Napi::String partition_id = info[0].As<Napi::String>();
179
+ char *partition_id_cobhan_buffer;
180
+ size_t partition_id_copied_bytes;
181
+ NAPI_STRING_TO_CBUFFER(env, partition_id, partition_id_cobhan_buffer,
182
+ partition_id_copied_bytes, maximum_stack_alloc_size,
183
+ __func__);
184
+
185
+ Napi::String input = info[1].As<Napi::String>();
186
+ char *input_cobhan_buffer;
187
+ size_t input_copied_bytes;
188
+ NAPI_STRING_TO_CBUFFER(env, input, input_cobhan_buffer, input_copied_bytes,
189
+ maximum_stack_alloc_size, __func__);
190
+
191
+ Napi::String output = EncryptCobhanBufferToJson(
192
+ env, partition_id_copied_bytes, input_copied_bytes,
193
+ partition_id_cobhan_buffer, input_cobhan_buffer);
194
+
195
+ if (unlikely(verbose_flag)) {
196
+ debug_log(__func__, "finished");
197
+ }
198
+
199
+ return output;
200
+ }
201
+
202
+ Napi::String EncryptCobhanBufferToJson(Napi::Env &env, size_t partition_bytes,
203
+ size_t data_bytes,
204
+ char *partition_id_cobhan_buffer,
205
+ char *input_cobhan_buffer) {
206
+
207
+ size_t asherah_output_size_bytes =
208
+ EstimateAsherahOutputSize(data_bytes, partition_bytes);
209
+
210
+ if (unlikely(verbose_flag)) {
211
+ debug_log(__func__, " asherah_output_size_bytes " +
212
+ std::to_string(asherah_output_size_bytes));
213
+ }
214
+
215
+ char *output_cobhan_buffer;
216
+ ALLOCATE_CBUFFER(output_cobhan_buffer, asherah_output_size_bytes,
217
+ maximum_stack_alloc_size, __func__);
218
+
219
+ char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
220
+ if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
221
+ log_error_and_throw(
222
+ __func__,
223
+ "Failed initial canary check for partition_id_cobhan_buffer");
224
+ }
225
+ char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
226
+ if (unlikely(!check_canary_ptr(input_canary_ptr))) {
227
+ log_error_and_throw(
228
+ __func__, "Failed initial canary check for input_cobhan_buffer");
229
+ }
230
+ char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
231
+ if (unlikely(!check_canary_ptr(output_canary_ptr))) {
232
+ log_error_and_throw(
233
+ __func__, "Failed initial canary check for output_cobhan_buffer");
234
+ }
235
+
236
+ if (unlikely(verbose_flag)) {
237
+ debug_log(__func__, "Calling asherah-cobhan EncryptToJson");
238
+ }
239
+
240
+ // extern GoInt32 EncryptToJson(void* partitionIdPtr, void* dataPtr, void*
241
+ // jsonPtr);
242
+ GoInt32 result = EncryptToJson(partition_id_cobhan_buffer,
407
243
  input_cobhan_buffer, output_cobhan_buffer);
408
244
 
409
- if (unlikely(verbose_flag)) {
410
- debug_log(__func__, "Returned from asherah-cobhan DecryptFromJson");
411
- }
412
-
413
- if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
414
- log_error_and_throw(
415
- __func__,
416
- "Failed post-call canary check for partition_id_cobhan_buffer");
417
- }
418
- if (unlikely(!check_canary_ptr(input_canary_ptr))) {
419
- log_error_and_throw(
420
- __func__, "Failed post-call canary check for input_cobhan_buffer");
421
- }
422
- if (unlikely(!check_canary_ptr(output_canary_ptr))) {
423
- log_error_and_throw(
424
- __func__, "Failed post-call canary check for output_cobhan_buffer");
425
- }
426
-
427
- if (unlikely(result < 0)) {
428
- log_error_and_throw(__func__, asherah_cobhan_error_to_string(result));
429
- }
430
-
431
- Napi::String output = cbuffer_to_nstring(env, output_cobhan_buffer);
432
-
433
- if (unlikely(verbose_flag)) {
434
- debug_log(__func__, "finished");
435
- }
436
-
437
- return output;
438
- }
439
-
440
- void shutdown(const Napi::CallbackInfo &info) {
441
- std::lock_guard<std::mutex> lock(asherah_lock);
442
-
443
- if (unlikely(verbose_flag)) {
444
- debug_log(__func__, "called");
445
- }
446
-
447
- setup_state = 0;
245
+ if (unlikely(verbose_flag)) {
246
+ debug_log(__func__, "Returning from asherah-cobhan EncryptToJson");
247
+ }
248
+
249
+ if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
250
+ log_error_and_throw(
251
+ __func__,
252
+ "Failed post-call canary check for partition_id_cobhan_buffer");
253
+ }
254
+ if (unlikely(!check_canary_ptr(input_canary_ptr))) {
255
+ log_error_and_throw(
256
+ __func__, "Failed post-call canary check for input_cobhan_buffer");
257
+ }
258
+ if (unlikely(!check_canary_ptr(output_canary_ptr))) {
259
+ log_error_and_throw(
260
+ __func__, "Failed post-call canary check for output_cobhan_buffer");
261
+ }
262
+
263
+ if (unlikely(result < 0)) {
264
+ log_error_and_throw(__func__, AsherahCobhanErrorToString(result));
265
+ }
266
+
267
+ Napi::String output = cbuffer_to_nstring(env, output_cobhan_buffer);
268
+ return output;
269
+ }
270
+
271
+ Napi::Value Decrypt(const Napi::CallbackInfo &info) {
272
+ std::lock_guard<std::mutex> lock(asherah_lock);
273
+
274
+ if (unlikely(verbose_flag)) {
275
+ debug_log(__func__, "called");
276
+ }
277
+
278
+ if (unlikely(setup_state == 0)) {
279
+ log_error_and_throw(__func__, "setup() not called");
280
+ }
281
+
282
+ if (unlikely(info.Length() < 2)) {
283
+ log_error_and_throw(__func__, "Wrong number of arguments");
284
+ }
285
+
286
+ if (unlikely(!info[0].IsString() || !info[1].IsString())) {
287
+ log_error_and_throw(__func__, "Wrong argument types");
288
+ }
289
+
290
+ Napi::Env env = info.Env();
291
+
292
+ Napi::String partition_id = info[0].As<Napi::String>();
293
+ char *partition_id_cobhan_buffer;
294
+ size_t partition_id_copied_bytes;
295
+ NAPI_STRING_TO_CBUFFER(env, partition_id, partition_id_cobhan_buffer,
296
+ partition_id_copied_bytes, maximum_stack_alloc_size,
297
+ __func__);
298
+
299
+ Napi::String input = info[1].As<Napi::String>();
300
+ char *input_cobhan_buffer;
301
+ size_t input_copied_bytes;
302
+ NAPI_STRING_TO_CBUFFER(env, input, input_cobhan_buffer, input_copied_bytes,
303
+ maximum_stack_alloc_size, __func__);
304
+
305
+ char *output_cobhan_buffer;
306
+ ALLOCATE_CBUFFER(output_cobhan_buffer, input_copied_bytes,
307
+ maximum_stack_alloc_size, __func__);
308
+
309
+ char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
310
+ if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
311
+ log_error_and_throw(
312
+ __func__,
313
+ "Failed initial canary check for partition_id_cobhan_buffer");
314
+ }
315
+ char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
316
+ if (unlikely(!check_canary_ptr(input_canary_ptr))) {
317
+ log_error_and_throw(
318
+ __func__, "Failed initial canary check for input_cobhan_buffer");
319
+ }
320
+ char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
321
+ if (unlikely(!check_canary_ptr(output_canary_ptr))) {
322
+ log_error_and_throw(
323
+ __func__, "Failed initial canary check for output_cobhan_buffer");
324
+ }
325
+
326
+ if (unlikely(verbose_flag)) {
327
+ debug_log(__func__, "Calling asherah-cobhan DecryptFromJson");
328
+ }
329
+
330
+ // extern GoInt32 DecryptFromJson(void* partitionIdPtr, void* jsonPtr, void*
331
+ // dataPtr);
332
+ GoInt32 result = DecryptFromJson(partition_id_cobhan_buffer,
333
+ input_cobhan_buffer, output_cobhan_buffer);
334
+
335
+ if (unlikely(verbose_flag)) {
336
+ debug_log(__func__, "Returned from asherah-cobhan DecryptFromJson");
337
+ }
338
+
339
+ if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
340
+ log_error_and_throw(
341
+ __func__,
342
+ "Failed post-call canary check for partition_id_cobhan_buffer");
343
+ }
344
+ if (unlikely(!check_canary_ptr(input_canary_ptr))) {
345
+ log_error_and_throw(
346
+ __func__, "Failed post-call canary check for input_cobhan_buffer");
347
+ }
348
+ if (unlikely(!check_canary_ptr(output_canary_ptr))) {
349
+ log_error_and_throw(
350
+ __func__, "Failed post-call canary check for output_cobhan_buffer");
351
+ }
352
+
353
+ if (unlikely(result < 0)) {
354
+ log_error_and_throw(__func__, AsherahCobhanErrorToString(result));
355
+ }
356
+
357
+ Napi::Buffer<unsigned char> output =
358
+ cbuffer_to_nbuffer(env, output_cobhan_buffer);
359
+
360
+ if (unlikely(verbose_flag)) {
361
+ debug_log(__func__, "finished");
362
+ }
363
+
364
+ return output;
365
+ }
366
+
367
+ Napi::Value DecryptString(const Napi::CallbackInfo &info) {
368
+ std::lock_guard<std::mutex> lock(asherah_lock);
369
+
370
+ if (unlikely(verbose_flag)) {
371
+ debug_log(__func__, "called");
372
+ }
373
+
374
+ if (unlikely(setup_state == 0)) {
375
+ log_error_and_throw(__func__, "setup() not called");
376
+ }
377
+
378
+ if (unlikely(info.Length() < 2)) {
379
+ log_error_and_throw(__func__, "Wrong number of arguments");
380
+ }
381
+
382
+ if (unlikely(!info[0].IsString() || !info[1].IsString())) {
383
+ log_error_and_throw(__func__, "Wrong argument types");
384
+ }
385
+
386
+ Napi::Env env = info.Env();
387
+
388
+ Napi::String partition_id = info[0].As<Napi::String>();
389
+ char *partition_id_cobhan_buffer;
390
+ size_t partition_id_copied_bytes;
391
+ NAPI_STRING_TO_CBUFFER(env, partition_id, partition_id_cobhan_buffer,
392
+ partition_id_copied_bytes, maximum_stack_alloc_size,
393
+ __func__);
394
+
395
+ Napi::String input = info[1].As<Napi::String>();
396
+ char *input_cobhan_buffer;
397
+ size_t input_copied_bytes;
398
+ NAPI_STRING_TO_CBUFFER(env, input, input_cobhan_buffer, input_copied_bytes,
399
+ maximum_stack_alloc_size, __func__);
400
+
401
+ char *output_cobhan_buffer;
402
+ ALLOCATE_CBUFFER(output_cobhan_buffer, input_copied_bytes,
403
+ maximum_stack_alloc_size, __func__);
404
+
405
+ char *partition_id_canary_ptr = get_canary_ptr(partition_id_cobhan_buffer);
406
+ if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
407
+ log_error_and_throw(
408
+ __func__,
409
+ "Failed initial canary check for partition_id_cobhan_buffer");
410
+ }
411
+ char *input_canary_ptr = get_canary_ptr(input_cobhan_buffer);
412
+ if (unlikely(!check_canary_ptr(input_canary_ptr))) {
413
+ log_error_and_throw(
414
+ __func__, "Failed initial canary check for input_cobhan_buffer");
415
+ }
416
+ char *output_canary_ptr = get_canary_ptr(output_cobhan_buffer);
417
+ if (unlikely(!check_canary_ptr(output_canary_ptr))) {
418
+ log_error_and_throw(
419
+ __func__, "Failed initial canary check for output_cobhan_buffer");
420
+ }
421
+
422
+ if (unlikely(verbose_flag)) {
423
+ debug_log(__func__, "Calling asherah-cobhan DecryptFromJson");
424
+ }
448
425
 
449
- if (unlikely(verbose_flag)) {
450
- debug_log(__func__, "Calling asherah-cobhan Shutdown");
451
- }
452
-
453
- // extern void Shutdown();
454
- Shutdown();
455
-
456
- if (unlikely(verbose_flag)) {
457
- debug_log(__func__, "Returned from asherah-cobhan Shutdown");
458
- }
459
- }
460
-
461
- void set_max_stack_alloc_item_size(const Napi::CallbackInfo &info) {
462
- std::lock_guard<std::mutex> lock(asherah_lock);
463
-
464
- if (unlikely(verbose_flag)) {
465
- debug_log(__func__, "called");
466
- }
467
-
468
- if (unlikely(info.Length() < 1)) {
469
- log_error_and_throw(__func__, "Wrong number of arguments");
470
- }
471
-
472
- Napi::Number item_size = info[0].ToNumber();
473
-
474
- maximum_stack_alloc_size = (size_t)item_size.Int32Value();
475
- }
476
-
477
- void set_safety_padding_overhead(const Napi::CallbackInfo &info) {
478
- std::lock_guard<std::mutex> lock(asherah_lock);
479
-
480
- if (unlikely(verbose_flag)) {
481
- debug_log(__func__, "called");
482
- }
483
-
484
- if (unlikely(info.Length() < 1)) {
485
- log_error_and_throw(__func__, "Wrong number of arguments");
486
- }
487
-
488
- Napi::Number safety_padding_number = info[0].ToNumber();
489
-
490
- set_safety_padding_bytes((size_t)safety_padding_number.Int32Value());
491
- }
492
-
493
- __attribute__((always_inline)) inline size_t
494
- estimate_asherah_output_size_bytes(size_t data_byte_len,
495
- size_t partition_byte_len) {
496
- const size_t est_encryption_overhead = 48;
497
- const size_t est_envelope_overhead = 185;
498
- const double base64_overhead = 1.34;
499
-
500
- // Add one rather than using std::ceil to round up
501
- double est_data_byte_len =
502
- (double(data_byte_len + est_encryption_overhead) * base64_overhead) + 1;
503
-
504
- size_t asherah_output_size_bytes =
505
- size_t(est_envelope_overhead + est_intermediate_key_overhead +
506
- partition_byte_len + est_data_byte_len);
507
- if (unlikely(verbose_flag)) {
508
- std::string log_msg =
509
- "estimate_asherah_output_size(" + std::to_string(data_byte_len) + ", " +
510
- std::to_string(partition_byte_len) +
511
- ") est_data_byte_len: " + std::to_string(est_data_byte_len) +
512
- " asherah_output_size_bytes: " +
513
- std::to_string(asherah_output_size_bytes);
514
- debug_log(__func__, log_msg);
515
- }
516
- return asherah_output_size_bytes;
517
- }
518
-
519
- __attribute__((always_inline)) inline const char *
520
- asherah_cobhan_error_to_string(int32_t error) {
521
- switch (error) {
522
- case 0:
523
- return "Success";
524
- case -1:
525
- return "Cobhan error: NULL pointer";
526
- case -2:
527
- return "Cobhan error: Buffer too large";
528
- case -3:
529
- return "Cobhan error: Buffer too small";
530
- case -4:
531
- return "Cobhan error: Copy failed";
532
- case -5:
533
- return "Cobhan error: JSON decode failed";
534
- case -6:
535
- return "Cobhan error: JSON encode failed";
536
- case -7:
537
- return "Cobhan error: Invalid UTF-8";
538
- case -8:
539
- return "Cobhan error: Read temp file failed";
540
- case -9:
541
- return "Cobhan error: Write temp file failed";
542
- case -100:
543
- return "Asherah error: Not initialized";
544
- case -101:
545
- return "Asherah error: Already initialized";
546
- case -102:
547
- return "Asherah error: Failed to get session";
548
- case -103:
549
- return "Asherah error: Encrypt operation failed";
550
- case -104:
551
- return "Asherah error: Decrypt operation failed";
552
- case -105:
553
- return "Asherah error: Invalid configuration";
554
- default:
555
- return "Unknown error";
556
- }
557
- }
558
-
559
- Napi::Object Init(Napi::Env env, Napi::Object exports) {
560
- exports.Set(Napi::String::New(env, "setup"), Napi::Function::New(env, setup));
561
- exports.Set(Napi::String::New(env, "encrypt"),
562
- Napi::Function::New(env, encrypt));
563
- exports.Set(Napi::String::New(env, "encrypt_string"),
564
- Napi::Function::New(env, encrypt_string));
565
- exports.Set(Napi::String::New(env, "decrypt"),
566
- Napi::Function::New(env, decrypt));
567
- exports.Set(Napi::String::New(env, "decrypt_string"),
568
- Napi::Function::New(env, decrypt_string));
569
- exports.Set(Napi::String::New(env, "set_safety_padding_overhead"),
570
- Napi::Function::New(env, set_safety_padding_overhead));
571
- exports.Set(Napi::String::New(env, "set_max_stack_alloc_item_size"),
572
- Napi::Function::New(env, set_max_stack_alloc_item_size));
573
- exports.Set(Napi::String::New(env, "shutdown"),
574
- Napi::Function::New(env, shutdown));
575
- return exports;
576
- }
577
-
578
- NODE_API_MODULE(asherah, Init)
426
+ // extern GoInt32 DecryptFromJson(void* partitionIdPtr, void* jsonPtr, void*
427
+ // dataPtr);
428
+ GoInt32 result = DecryptFromJson(partition_id_cobhan_buffer,
429
+ input_cobhan_buffer, output_cobhan_buffer);
430
+
431
+ if (unlikely(verbose_flag)) {
432
+ debug_log(__func__, "Returned from asherah-cobhan DecryptFromJson");
433
+ }
434
+
435
+ if (unlikely(!check_canary_ptr(partition_id_canary_ptr))) {
436
+ log_error_and_throw(
437
+ __func__,
438
+ "Failed post-call canary check for partition_id_cobhan_buffer");
439
+ }
440
+ if (unlikely(!check_canary_ptr(input_canary_ptr))) {
441
+ log_error_and_throw(
442
+ __func__, "Failed post-call canary check for input_cobhan_buffer");
443
+ }
444
+ if (unlikely(!check_canary_ptr(output_canary_ptr))) {
445
+ log_error_and_throw(
446
+ __func__, "Failed post-call canary check for output_cobhan_buffer");
447
+ }
448
+
449
+ if (unlikely(result < 0)) {
450
+ log_error_and_throw(__func__, AsherahCobhanErrorToString(result));
451
+ }
452
+
453
+ Napi::String output = cbuffer_to_nstring(env, output_cobhan_buffer);
454
+
455
+ if (unlikely(verbose_flag)) {
456
+ debug_log(__func__, "finished");
457
+ }
458
+
459
+ return output;
460
+ }
461
+
462
+ void ShutdownAsherah(const Napi::CallbackInfo &info) {
463
+ std::lock_guard<std::mutex> lock(asherah_lock);
464
+
465
+ if (unlikely(verbose_flag)) {
466
+ debug_log(__func__, "called");
467
+ }
468
+
469
+ setup_state = 0;
470
+
471
+ if (unlikely(verbose_flag)) {
472
+ debug_log(__func__, "Calling asherah-cobhan Shutdown");
473
+ }
474
+
475
+ // extern void Shutdown();
476
+ Shutdown();
477
+
478
+ if (unlikely(verbose_flag)) {
479
+ debug_log(__func__, "Returned from asherah-cobhan Shutdown");
480
+ }
481
+ }
482
+
483
+ void SetMaxStackAllocItemSize(const Napi::CallbackInfo &info) {
484
+ std::lock_guard<std::mutex> lock(asherah_lock);
485
+
486
+ if (unlikely(verbose_flag)) {
487
+ debug_log(__func__, "called");
488
+ }
489
+
490
+ if (unlikely(info.Length() < 1)) {
491
+ log_error_and_throw(__func__, "Wrong number of arguments");
492
+ }
493
+
494
+ Napi::Number item_size = info[0].ToNumber();
495
+
496
+ maximum_stack_alloc_size = (size_t)item_size.Int32Value();
497
+ }
498
+
499
+ void SetSafetyPaddingOverhead(const Napi::CallbackInfo &info) {
500
+ std::lock_guard<std::mutex> lock(asherah_lock);
501
+
502
+ if (unlikely(verbose_flag)) {
503
+ debug_log(__func__, "called");
504
+ }
505
+
506
+ if (unlikely(info.Length() < 1)) {
507
+ log_error_and_throw(__func__, "Wrong number of arguments");
508
+ }
509
+
510
+ Napi::Number safety_padding_number = info[0].ToNumber();
511
+
512
+ set_safety_padding_bytes((size_t)safety_padding_number.Int32Value());
513
+ }
514
+
515
+ __attribute__((always_inline)) inline size_t
516
+ EstimateAsherahOutputSize(size_t data_byte_len, size_t partition_byte_len) {
517
+ const size_t est_encryption_overhead = 48;
518
+ const size_t est_envelope_overhead = 185;
519
+ const double base64_overhead = 1.34;
520
+
521
+ // Add one rather than using std::ceil to round up
522
+ double est_data_byte_len =
523
+ (double(data_byte_len + est_encryption_overhead) * base64_overhead) + 1;
524
+
525
+ size_t asherah_output_size_bytes =
526
+ size_t(est_envelope_overhead + est_intermediate_key_overhead +
527
+ partition_byte_len + est_data_byte_len);
528
+ if (unlikely(verbose_flag)) {
529
+ std::string log_msg =
530
+ __func__ + ("(" + std::to_string(data_byte_len)) + ", " +
531
+ std::to_string(partition_byte_len) +
532
+ ") est_data_byte_len: " + std::to_string(est_data_byte_len) +
533
+ " asherah_output_size_bytes: " +
534
+ std::to_string(asherah_output_size_bytes);
535
+ debug_log(__func__, log_msg);
536
+ }
537
+ return asherah_output_size_bytes;
538
+ }
539
+
540
+ __attribute__((always_inline)) inline const char *
541
+ AsherahCobhanErrorToString(int32_t error) {
542
+ switch (error) {
543
+ case 0:
544
+ return "Success";
545
+ case -1:
546
+ return "Cobhan error: NULL pointer";
547
+ case -2:
548
+ return "Cobhan error: Buffer too large";
549
+ case -3:
550
+ return "Cobhan error: Buffer too small";
551
+ case -4:
552
+ return "Cobhan error: Copy failed";
553
+ case -5:
554
+ return "Cobhan error: JSON decode failed";
555
+ case -6:
556
+ return "Cobhan error: JSON encode failed";
557
+ case -7:
558
+ return "Cobhan error: Invalid UTF-8";
559
+ case -8:
560
+ return "Cobhan error: Read temp file failed";
561
+ case -9:
562
+ return "Cobhan error: Write temp file failed";
563
+ case -100:
564
+ return "Asherah error: Not initialized";
565
+ case -101:
566
+ return "Asherah error: Already initialized";
567
+ case -102:
568
+ return "Asherah error: Failed to get session";
569
+ case -103:
570
+ return "Asherah error: Encrypt operation failed";
571
+ case -104:
572
+ return "Asherah error: Decrypt operation failed";
573
+ case -105:
574
+ return "Asherah error: Invalid configuration";
575
+ default:
576
+ return "Unknown error";
577
+ }
578
+ }
579
+ };
580
+
581
+ NODE_API_NAMED_ADDON('asherah', Asherah)