secure_db_fields 0.1.1

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 (47) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +98 -0
  4. data/Rakefile +16 -0
  5. data/db_deployment/mysql/Makefile +62 -0
  6. data/db_deployment/mysql/README.md +33 -0
  7. data/db_deployment/mysql/bin/common +199 -0
  8. data/db_deployment/mysql/bin/disable +40 -0
  9. data/db_deployment/mysql/bin/doctor +57 -0
  10. data/db_deployment/mysql/bin/enable +56 -0
  11. data/db_deployment/mysql/bin/install +64 -0
  12. data/db_deployment/mysql/bin/status +11 -0
  13. data/db_deployment/mysql/bin/uninstall +46 -0
  14. data/db_deployment/mysql/bin/verify +27 -0
  15. data/db_deployment/mysql/sql/examples.sql +20 -0
  16. data/db_deployment/mysql/sql/install.sql +20 -0
  17. data/db_deployment/mysql/sql/uninstall.sql +8 -0
  18. data/docs/final_decision.md +202 -0
  19. data/docs/implementation_notes.md +63 -0
  20. data/docs/ruby_27_mysql_57.md +33 -0
  21. data/examples/clients_phone_migration.sql +6 -0
  22. data/examples/keys.env.example +6 -0
  23. data/examples/ruby_usage.rb +15 -0
  24. data/exe/secure_db_fields +49 -0
  25. data/ext/secure_db_fields/extconf.rb +21 -0
  26. data/ext/secure_db_fields/secure_db_fields_core.c +723 -0
  27. data/ext/secure_db_fields/secure_db_fields_core.h +140 -0
  28. data/ext/secure_db_fields/secure_db_fields_ext.c +426 -0
  29. data/lib/secure_db_fields/active_record.rb +58 -0
  30. data/lib/secure_db_fields/crypto.rb +115 -0
  31. data/lib/secure_db_fields/db_deployment.rb +285 -0
  32. data/lib/secure_db_fields/keys.rb +69 -0
  33. data/lib/secure_db_fields/phone.rb +17 -0
  34. data/lib/secure_db_fields/version.rb +5 -0
  35. data/lib/secure_db_fields.rb +8 -0
  36. data/mysql_udf/Makefile +25 -0
  37. data/mysql_udf/README.md +51 -0
  38. data/mysql_udf/bin/install +11 -0
  39. data/mysql_udf/bin/uninstall +4 -0
  40. data/mysql_udf/bin/verify +3 -0
  41. data/mysql_udf/sql/examples.sql +20 -0
  42. data/mysql_udf/sql/install.sql +20 -0
  43. data/mysql_udf/sql/uninstall.sql +8 -0
  44. data/mysql_udf/src/mysql_udf_abi_57.h +34 -0
  45. data/mysql_udf/src/secure_db_fields_mysql.c +513 -0
  46. data/mysql_udf/test/run_e2e.sh +216 -0
  47. metadata +137 -0
@@ -0,0 +1,34 @@
1
+ #ifndef SECURE_DB_FIELDS_MYSQL_UDF_ABI_57_H
2
+ #define SECURE_DB_FIELDS_MYSQL_UDF_ABI_57_H
3
+
4
+ typedef char my_bool;
5
+
6
+ enum Item_result {
7
+ STRING_RESULT = 0,
8
+ REAL_RESULT,
9
+ INT_RESULT,
10
+ ROW_RESULT,
11
+ DECIMAL_RESULT
12
+ };
13
+
14
+ typedef struct st_udf_args {
15
+ unsigned int arg_count;
16
+ enum Item_result *arg_type;
17
+ char **args;
18
+ unsigned long *lengths;
19
+ char *maybe_null;
20
+ char **attributes;
21
+ unsigned long *attribute_lengths;
22
+ char *extension;
23
+ } UDF_ARGS;
24
+
25
+ typedef struct st_udf_init {
26
+ my_bool maybe_null;
27
+ unsigned int decimals;
28
+ unsigned long max_length;
29
+ char *ptr;
30
+ my_bool const_item;
31
+ void *extension;
32
+ } UDF_INIT;
33
+
34
+ #endif
@@ -0,0 +1,513 @@
1
+ #include <stdint.h>
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+ #include <string.h>
5
+ #include <limits.h>
6
+
7
+ #ifdef SDF_MYSQL_UDF_ABI_57
8
+ #include "mysql_udf_abi_57.h"
9
+ typedef my_bool sdf_udf_init_result_t;
10
+ #else
11
+ #include <stdbool.h>
12
+ #include <mysql.h>
13
+ #if defined(MARIADB_BASE_VERSION) || defined(MARIADB_VERSION_ID) || \
14
+ (defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID < 80000)
15
+ typedef my_bool sdf_udf_init_result_t;
16
+ #else
17
+ typedef bool sdf_udf_init_result_t;
18
+ #endif
19
+ #endif
20
+
21
+ #include "secure_db_fields_core.h"
22
+
23
+ #ifndef SDF_UDF_KEY_FILE
24
+ #define SDF_UDF_KEY_FILE SDF_DEFAULT_KEY_FILE
25
+ #endif
26
+
27
+ typedef struct {
28
+ char *out;
29
+ unsigned long out_cap;
30
+ char *scratch;
31
+ unsigned long scratch_cap;
32
+ int enc_key_valid;
33
+ uint32_t enc_key_id;
34
+ unsigned char enc_key[SDF_KEY_BYTES];
35
+ int bidx_key_valid;
36
+ int bidx_prepared_valid;
37
+ char bidx_domain[128];
38
+ unsigned char bidx_key[SDF_KEY_BYTES];
39
+ sdf_hmac_sha256_key bidx_prepared;
40
+ } sdf_mysql_state;
41
+
42
+ static const char *sdf_mysql_key_file(void) {
43
+ const char *env = getenv("SECURE_DB_FIELDS_KEY_FILE");
44
+ return (env && env[0]) ? env : SDF_UDF_KEY_FILE;
45
+ }
46
+
47
+ static void sdf_mysql_u32be_write(char *dst, uint32_t value) {
48
+ dst[0] = (char)((value >> 24) & 0xff);
49
+ dst[1] = (char)((value >> 16) & 0xff);
50
+ dst[2] = (char)((value >> 8) & 0xff);
51
+ dst[3] = (char)(value & 0xff);
52
+ }
53
+
54
+ static sdf_mysql_state *sdf_mysql_state_new(void) {
55
+ return (sdf_mysql_state *)calloc(1, sizeof(sdf_mysql_state));
56
+ }
57
+
58
+ static void sdf_mysql_state_free(sdf_mysql_state *state) {
59
+ if (!state)
60
+ return;
61
+ if (state->out) {
62
+ sdf_secure_clear(state->out, state->out_cap);
63
+ free(state->out);
64
+ }
65
+ if (state->scratch) {
66
+ sdf_secure_clear(state->scratch, state->scratch_cap);
67
+ free(state->scratch);
68
+ }
69
+ if (state->enc_key_valid)
70
+ sdf_secure_clear(state->enc_key, sizeof(state->enc_key));
71
+ if (state->bidx_prepared_valid)
72
+ sdf_hmac_sha256_key_clear(&state->bidx_prepared);
73
+ if (state->bidx_key_valid)
74
+ sdf_secure_clear(state->bidx_key, sizeof(state->bidx_key));
75
+ free(state);
76
+ }
77
+
78
+ static int sdf_mysql_ensure(char **buf, unsigned long *cap, unsigned long need) {
79
+ char *next;
80
+ if (need == 0)
81
+ need = 1;
82
+ if (*cap >= need)
83
+ return 1;
84
+ next = (char *)realloc(*buf, need);
85
+ if (!next)
86
+ return 0;
87
+ *buf = next;
88
+ *cap = need;
89
+ return 1;
90
+ }
91
+
92
+ static int sdf_mysql_ensure_out(sdf_mysql_state *state, unsigned long need) {
93
+ return sdf_mysql_ensure(&state->out, &state->out_cap, need);
94
+ }
95
+
96
+ static int sdf_mysql_ensure_scratch(sdf_mysql_state *state, unsigned long need) {
97
+ return sdf_mysql_ensure(&state->scratch, &state->scratch_cap, need);
98
+ }
99
+
100
+ static char *sdf_udf_fail(sdf_status st, char *is_null, char *error) {
101
+ *is_null = 1;
102
+ if (st == SDF_ERR_KEY)
103
+ *error = 1;
104
+ return NULL;
105
+ }
106
+
107
+ static char *sdf_udf_nomem(char *is_null, char *error) {
108
+ *is_null = 1;
109
+ *error = 1;
110
+ return NULL;
111
+ }
112
+
113
+ static char *sdf_udf_return_bidx(sdf_mysql_state *state, sdf_status st,
114
+ const unsigned char out[SDF_BIDX_BYTES], unsigned long *length,
115
+ char *is_null, char *error) {
116
+ if (st != SDF_OK)
117
+ return sdf_udf_fail(st, is_null, error);
118
+ if (!sdf_mysql_ensure_out(state, SDF_BIDX_BYTES))
119
+ return sdf_udf_nomem(is_null, error);
120
+ memcpy(state->out, out, SDF_BIDX_BYTES);
121
+ *length = SDF_BIDX_BYTES;
122
+ *is_null = 0;
123
+ return state->out;
124
+ }
125
+
126
+ static sdf_status sdf_mysql_cached_encryption_key(sdf_mysql_state *state, uint32_t key_id,
127
+ char *err, size_t err_len) {
128
+ sdf_status st;
129
+ if (state->enc_key_valid && state->enc_key_id == key_id)
130
+ return SDF_OK;
131
+ if (state->enc_key_valid) {
132
+ sdf_secure_clear(state->enc_key, sizeof(state->enc_key));
133
+ state->enc_key_valid = 0;
134
+ }
135
+ st = sdf_load_encryption_key(key_id, sdf_mysql_key_file(), state->enc_key, err, err_len);
136
+ if (st == SDF_OK) {
137
+ state->enc_key_id = key_id;
138
+ state->enc_key_valid = 1;
139
+ }
140
+ return st;
141
+ }
142
+
143
+ static sdf_status sdf_mysql_cached_bidx_key(sdf_mysql_state *state, const char *domain, char *err,
144
+ size_t err_len) {
145
+ sdf_status st;
146
+ const char *effective_domain = domain ? domain : "";
147
+ if (strlen(effective_domain) >= sizeof(state->bidx_domain)) {
148
+ snprintf(err, err_len, "bidx domain is too long");
149
+ return SDF_ERR_KEY;
150
+ }
151
+ if (state->bidx_key_valid && state->bidx_prepared_valid &&
152
+ strcmp(state->bidx_domain, effective_domain) == 0)
153
+ return SDF_OK;
154
+ if (state->bidx_prepared_valid) {
155
+ sdf_hmac_sha256_key_clear(&state->bidx_prepared);
156
+ state->bidx_prepared_valid = 0;
157
+ }
158
+ if (state->bidx_key_valid) {
159
+ sdf_secure_clear(state->bidx_key, sizeof(state->bidx_key));
160
+ state->bidx_key_valid = 0;
161
+ }
162
+ st = sdf_load_bidx_key(sdf_mysql_key_file(), effective_domain, state->bidx_key, err, err_len);
163
+ if (st == SDF_OK)
164
+ st = sdf_hmac_sha256_key_prepare(&state->bidx_prepared, state->bidx_key,
165
+ sizeof(state->bidx_key), err, err_len);
166
+ if (st == SDF_OK) {
167
+ snprintf(state->bidx_domain, sizeof(state->bidx_domain), "%s", effective_domain);
168
+ state->bidx_key_valid = 1;
169
+ state->bidx_prepared_valid = 1;
170
+ } else {
171
+ sdf_secure_clear(state->bidx_key, sizeof(state->bidx_key));
172
+ state->bidx_key_valid = 0;
173
+ state->bidx_prepared_valid = 0;
174
+ }
175
+ return st;
176
+ }
177
+
178
+ static sdf_udf_init_result_t sdf_init_state_typed(UDF_INIT *initid, UDF_ARGS *args, char *message,
179
+ unsigned int argc, const char *signature,
180
+ unsigned long max_length,
181
+ const enum Item_result *types) {
182
+ unsigned int i;
183
+ sdf_mysql_state *state;
184
+ if (args->arg_count != argc) {
185
+ snprintf(message, 255, "%s takes exactly %u arguments", signature, argc);
186
+ return 1;
187
+ }
188
+ for (i = 0; i < argc; i++)
189
+ args->arg_type[i] = types ? types[i] : STRING_RESULT;
190
+ state = sdf_mysql_state_new();
191
+ if (!state) {
192
+ snprintf(message, 255, "out of memory");
193
+ return 1;
194
+ }
195
+ initid->ptr = (char *)state;
196
+ initid->maybe_null = 1;
197
+ initid->const_item = 0;
198
+ initid->max_length = max_length;
199
+ return 0;
200
+ }
201
+
202
+ static sdf_udf_init_result_t sdf_init_state(UDF_INIT *initid, UDF_ARGS *args, char *message,
203
+ unsigned int argc, const char *signature,
204
+ unsigned long max_length) {
205
+ return sdf_init_state_typed(initid, args, message, argc, signature, max_length, NULL);
206
+ }
207
+
208
+ static sdf_udf_init_result_t sdf_init_no_state(UDF_INIT *initid, UDF_ARGS *args, char *message,
209
+ unsigned int argc, const char *signature,
210
+ unsigned long max_length) {
211
+ if (args->arg_count != argc) {
212
+ snprintf(message, 255, "%s takes exactly %u arguments", signature, argc);
213
+ return 1;
214
+ }
215
+ initid->maybe_null = 1;
216
+ initid->const_item = 0;
217
+ initid->max_length = max_length;
218
+ return 0;
219
+ }
220
+
221
+ void secure_db_fields_deinit(UDF_INIT *initid) {
222
+ sdf_mysql_state_free((sdf_mysql_state *)initid->ptr);
223
+ initid->ptr = NULL;
224
+ }
225
+
226
+ #define SDF_UDF_DEINIT(name) \
227
+ void name##_deinit(UDF_INIT *initid) { \
228
+ secure_db_fields_deinit(initid); \
229
+ }
230
+
231
+ sdf_udf_init_result_t secure_db_fields_version_init(UDF_INIT *initid, UDF_ARGS *args,
232
+ char *message) {
233
+ (void)initid;
234
+ if (args->arg_count != 0) {
235
+ snprintf(message, 255, "secure_db_fields_version() takes no arguments");
236
+ return 1;
237
+ }
238
+ initid->maybe_null = 0;
239
+ initid->const_item = 1;
240
+ initid->max_length = 128;
241
+ return 0;
242
+ }
243
+
244
+ char *secure_db_fields_version(UDF_INIT *initid, UDF_ARGS *args, char *result,
245
+ unsigned long *length, char *is_null, char *error) {
246
+ int n;
247
+ (void)initid;
248
+ (void)args;
249
+ *is_null = 0;
250
+ *error = 0;
251
+ n = snprintf(result, 255, "secure_db_fields %s; MCEN1 AES-256-GCM + HMAC-SHA256", SDF_VERSION);
252
+ *length = (unsigned long)(n > 0 ? n : 0);
253
+ return result;
254
+ }
255
+
256
+ sdf_udf_init_result_t secure_db_fields_is_valid_envelope_init(UDF_INIT *initid, UDF_ARGS *args,
257
+ char *message) {
258
+ return sdf_init_no_state(initid, args, message, 1, "secure_db_fields_is_valid_envelope(blob)",
259
+ 1);
260
+ }
261
+
262
+ long long secure_db_fields_is_valid_envelope(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
263
+ char *error) {
264
+ (void)initid;
265
+ *error = 0;
266
+ if (!args->args[0]) {
267
+ *is_null = 1;
268
+ return 0;
269
+ }
270
+ *is_null = 0;
271
+ return sdf_is_valid_envelope((const unsigned char *)args->args[0], (size_t)args->lengths[0])
272
+ ? 1
273
+ : 0;
274
+ }
275
+
276
+ sdf_udf_init_result_t secure_db_fields_envelope_key_id_init(UDF_INIT *initid, UDF_ARGS *args,
277
+ char *message) {
278
+ return sdf_init_no_state(initid, args, message, 1, "secure_db_fields_envelope_key_id(blob)",
279
+ 11);
280
+ }
281
+
282
+ long long secure_db_fields_envelope_key_id(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
283
+ char *error) {
284
+ uint32_t key_id = 0;
285
+ char err[SDF_MAX_ERR];
286
+ (void)initid;
287
+ *error = 0;
288
+ if (!args->args[0]) {
289
+ *is_null = 1;
290
+ return 0;
291
+ }
292
+ if (sdf_parse_key_id((const unsigned char *)args->args[0], (size_t)args->lengths[0], &key_id,
293
+ err, sizeof(err)) != SDF_OK) {
294
+ *is_null = 1;
295
+ return 0;
296
+ }
297
+ *is_null = 0;
298
+ return (long long)key_id;
299
+ }
300
+
301
+ sdf_udf_init_result_t secure_db_fields_decrypt_init(UDF_INIT *initid, UDF_ARGS *args,
302
+ char *message) {
303
+ return sdf_init_state(initid, args, message, 2, "secure_db_fields_decrypt(envelope, aad)",
304
+ 1024 * 1024 * 16);
305
+ }
306
+
307
+ char *secure_db_fields_decrypt(UDF_INIT *initid, UDF_ARGS *args, char *result,
308
+ unsigned long *length, char *is_null, char *error) {
309
+ sdf_mysql_state *state = (sdf_mysql_state *)initid->ptr;
310
+ size_t out_cap;
311
+ size_t out_len = 0;
312
+ uint32_t key_id = 0;
313
+ char err[SDF_MAX_ERR];
314
+ sdf_status st;
315
+ (void)result;
316
+ *error = 0;
317
+ if (!args->args[0] || !args->args[1]) {
318
+ *is_null = 1;
319
+ return NULL;
320
+ }
321
+ st = sdf_parse_key_id((const unsigned char *)args->args[0], (size_t)args->lengths[0], &key_id,
322
+ err, sizeof(err));
323
+ if (st != SDF_OK)
324
+ return sdf_udf_fail(st, is_null, error);
325
+ st = sdf_mysql_cached_encryption_key(state, key_id, err, sizeof(err));
326
+ if (st != SDF_OK)
327
+ return sdf_udf_fail(st, is_null, error);
328
+ out_cap = sdf_decrypt_aes_256_gcm_output_cap((const unsigned char *)args->args[0],
329
+ (size_t)args->lengths[0]);
330
+ if (!sdf_mysql_ensure_out(state, (unsigned long)out_cap))
331
+ return sdf_udf_nomem(is_null, error);
332
+ st = sdf_decrypt_aes_256_gcm_into(
333
+ (const unsigned char *)args->args[0], (size_t)args->lengths[0], state->enc_key,
334
+ sizeof(state->enc_key), (const unsigned char *)args->args[1], (size_t)args->lengths[1],
335
+ (unsigned char *)state->out, out_cap, &out_len, err, sizeof(err));
336
+ if (st != SDF_OK)
337
+ return sdf_udf_fail(st, is_null, error);
338
+ *length = (unsigned long)out_len;
339
+ *is_null = 0;
340
+ return state->out;
341
+ }
342
+
343
+ SDF_UDF_DEINIT(secure_db_fields_decrypt)
344
+
345
+ sdf_udf_init_result_t secure_db_fields_decrypt_field_init(UDF_INIT *initid, UDF_ARGS *args,
346
+ char *message) {
347
+ return sdf_init_state(
348
+ initid, args, message, 4,
349
+ "secure_db_fields_decrypt_field(envelope, table_name, column_name, row_uid)",
350
+ 1024 * 1024 * 16);
351
+ }
352
+
353
+ char *secure_db_fields_decrypt_field(UDF_INIT *initid, UDF_ARGS *args, char *result,
354
+ unsigned long *length, char *is_null, char *error) {
355
+ sdf_mysql_state *state = (sdf_mysql_state *)initid->ptr;
356
+ unsigned long aad_len;
357
+ char *aad;
358
+ (void)result;
359
+ *error = 0;
360
+ if (!args->args[0] || !args->args[1] || !args->args[2] || !args->args[3] ||
361
+ args->lengths[3] != SDF_ROW_UID_BYTES) {
362
+ *is_null = 1;
363
+ return NULL;
364
+ }
365
+ if (args->lengths[1] > UINT32_MAX || args->lengths[2] > UINT32_MAX ||
366
+ args->lengths[1] > ULONG_MAX - args->lengths[2] ||
367
+ args->lengths[1] + args->lengths[2] > ULONG_MAX - 28) {
368
+ *is_null = 1;
369
+ return NULL;
370
+ }
371
+ aad_len = 4 + 4 + args->lengths[1] + 4 + args->lengths[2] + SDF_ROW_UID_BYTES;
372
+ if (!sdf_mysql_ensure_scratch(state, aad_len))
373
+ return sdf_udf_nomem(is_null, error);
374
+ aad = state->scratch;
375
+ memcpy(aad, "SDF1", 4);
376
+ sdf_mysql_u32be_write(aad + 4, (uint32_t)args->lengths[1]);
377
+ memcpy(aad + 8, args->args[1], args->lengths[1]);
378
+ sdf_mysql_u32be_write(aad + 8 + args->lengths[1], (uint32_t)args->lengths[2]);
379
+ memcpy(aad + 12 + args->lengths[1], args->args[2], args->lengths[2]);
380
+ memcpy(aad + 12 + args->lengths[1] + args->lengths[2], args->args[3], SDF_ROW_UID_BYTES);
381
+
382
+ {
383
+ size_t out_cap;
384
+ size_t out_len = 0;
385
+ uint32_t key_id = 0;
386
+ char err[SDF_MAX_ERR];
387
+ sdf_status st = sdf_parse_key_id((const unsigned char *)args->args[0],
388
+ (size_t)args->lengths[0], &key_id, err, sizeof(err));
389
+ if (st == SDF_OK)
390
+ st = sdf_mysql_cached_encryption_key(state, key_id, err, sizeof(err));
391
+ if (st != SDF_OK)
392
+ return sdf_udf_fail(st, is_null, error);
393
+ out_cap = sdf_decrypt_aes_256_gcm_output_cap((const unsigned char *)args->args[0],
394
+ (size_t)args->lengths[0]);
395
+ if (!sdf_mysql_ensure_out(state, (unsigned long)out_cap))
396
+ return sdf_udf_nomem(is_null, error);
397
+ st = sdf_decrypt_aes_256_gcm_into(
398
+ (const unsigned char *)args->args[0], (size_t)args->lengths[0], state->enc_key,
399
+ sizeof(state->enc_key), (const unsigned char *)aad, (size_t)aad_len,
400
+ (unsigned char *)state->out, out_cap, &out_len, err, sizeof(err));
401
+ if (st != SDF_OK)
402
+ return sdf_udf_fail(st, is_null, error);
403
+ *length = (unsigned long)out_len;
404
+ *is_null = 0;
405
+ *error = 0;
406
+ return state->out;
407
+ }
408
+ }
409
+
410
+ SDF_UDF_DEINIT(secure_db_fields_decrypt_field)
411
+
412
+ sdf_udf_init_result_t secure_db_fields_bidx_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
413
+ return sdf_init_state(initid, args, message, 2, "secure_db_fields_bidx(value, domain)",
414
+ SDF_BIDX_BYTES);
415
+ }
416
+
417
+ char *secure_db_fields_bidx(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length,
418
+ char *is_null, char *error) {
419
+ sdf_mysql_state *state = (sdf_mysql_state *)initid->ptr;
420
+ unsigned char out[SDF_BIDX_BYTES];
421
+ char domain[96];
422
+ char err[SDF_MAX_ERR];
423
+ sdf_status st;
424
+ (void)result;
425
+ *error = 0;
426
+ if (!args->args[0] || !args->args[1]) {
427
+ *is_null = 1;
428
+ return NULL;
429
+ }
430
+ if (args->lengths[1] >= sizeof(domain)) {
431
+ *is_null = 1;
432
+ return NULL;
433
+ }
434
+ memcpy(domain, args->args[1], args->lengths[1]);
435
+ domain[args->lengths[1]] = '\0';
436
+ st = sdf_mysql_cached_bidx_key(state, domain, err, sizeof(err));
437
+ if (st == SDF_OK) {
438
+ st =
439
+ sdf_blind_index_prepared((const unsigned char *)args->args[0], (size_t)args->lengths[0],
440
+ &state->bidx_prepared, out, err, sizeof(err));
441
+ }
442
+ return sdf_udf_return_bidx(state, st, out, length, is_null, error);
443
+ }
444
+
445
+ SDF_UDF_DEINIT(secure_db_fields_bidx)
446
+
447
+ sdf_udf_init_result_t secure_phone_bidx_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
448
+ return sdf_init_state(initid, args, message, 1, "secure_phone_bidx(e164)", SDF_BIDX_BYTES);
449
+ }
450
+
451
+ char *secure_phone_bidx(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length,
452
+ char *is_null, char *error) {
453
+ sdf_mysql_state *state = (sdf_mysql_state *)initid->ptr;
454
+ unsigned char out[SDF_BIDX_BYTES];
455
+ char err[SDF_MAX_ERR];
456
+ sdf_status st;
457
+ (void)result;
458
+ *error = 0;
459
+ if (!args->args[0]) {
460
+ *is_null = 1;
461
+ return NULL;
462
+ }
463
+ st = sdf_mysql_cached_bidx_key(state, "PHONE", err, sizeof(err));
464
+ if (st == SDF_OK) {
465
+ st = sdf_phone_exact_bidx_prepared((const unsigned char *)args->args[0],
466
+ (size_t)args->lengths[0], &state->bidx_prepared, out,
467
+ err, sizeof(err));
468
+ }
469
+ return sdf_udf_return_bidx(state, st, out, length, is_null, error);
470
+ }
471
+
472
+ SDF_UDF_DEINIT(secure_phone_bidx)
473
+
474
+ sdf_udf_init_result_t secure_phone_prefix_bidx_init(UDF_INIT *initid, UDF_ARGS *args,
475
+ char *message) {
476
+ static const enum Item_result types[2] = {STRING_RESULT, INT_RESULT};
477
+ return sdf_init_state_typed(initid, args, message, 2,
478
+ "secure_phone_prefix_bidx(e164, prefix_digits)", SDF_BIDX_BYTES,
479
+ types);
480
+ }
481
+
482
+ char *secure_phone_prefix_bidx(UDF_INIT *initid, UDF_ARGS *args, char *result,
483
+ unsigned long *length, char *is_null, char *error) {
484
+ sdf_mysql_state *state = (sdf_mysql_state *)initid->ptr;
485
+ unsigned char out[SDF_BIDX_BYTES];
486
+ char domain[32];
487
+ char err[SDF_MAX_ERR];
488
+ long long prefix_ll = 0;
489
+ unsigned int prefix_digits;
490
+ sdf_status st;
491
+ (void)result;
492
+ *error = 0;
493
+ if (!args->args[0] || !args->args[1]) {
494
+ *is_null = 1;
495
+ return NULL;
496
+ }
497
+ memcpy(&prefix_ll, args->args[1], sizeof(prefix_ll));
498
+ if (prefix_ll <= 0 || prefix_ll > 15) {
499
+ *is_null = 1;
500
+ return NULL;
501
+ }
502
+ prefix_digits = (unsigned int)prefix_ll;
503
+ snprintf(domain, sizeof(domain), "PHONE_P%u", prefix_digits);
504
+ st = sdf_mysql_cached_bidx_key(state, domain, err, sizeof(err));
505
+ if (st == SDF_OK) {
506
+ st = sdf_phone_prefix_bidx_prepared((const unsigned char *)args->args[0],
507
+ (size_t)args->lengths[0], prefix_digits,
508
+ &state->bidx_prepared, out, err, sizeof(err));
509
+ }
510
+ return sdf_udf_return_bidx(state, st, out, length, is_null, error);
511
+ }
512
+
513
+ SDF_UDF_DEINIT(secure_phone_prefix_bidx)