/ kems.c
kems.c
  1  #include <stdlib.h>
  2  #include <string.h>
  3  #include <lscore/index.h>
  4  #include <lscore/plugin.h>
  5  #include <lsplugin/mkobject.h>
  6  #include <lsplugin/mkoperator.h>
  7  #include <lsplugin/param.h>
  8  #include <oqs/kem.h>
  9  #include "local.h"
 10  
 11  /* The live key structure */
 12  struct oqs_key_st {
 13    uint8_t *sec; size_t sec_len; /* secret (private) key */
 14    uint8_t *pub; size_t pub_len; /* public key */
 15  };
 16  
 17  /* All data and descriptor structures for one OQS algorithm */
 18  struct oqs_impl_st {
 19    /* The self-standing encapsulator and decapsulator...  really just for convenience */
 20    LSplugin_encapsulator_desc_t encapsulator;
 21    LSplugin_decapsulator_desc_t decapsulator;
 22    /* The key associated encapsulator and decapsulator */
 23    LSplugin_encapsulator_desc_t assoc_encapsulator;
 24    LSplugin_decapsulator_desc_t assoc_decapsulator;
 25    LSplugin_key_generator_desc_t assoc_generator;
 26    LSplugin_key_constructor_desc_t assoc_constructor;
 27    LSplugin_key_extractor_desc_t assoc_extractor;
 28    /* The key itself */
 29    LSplugin_key_desc_t key;
 30  
 31    /* The parameters, made as a substructure to get pointers easily */
 32    struct oqs_data_st {
 33      OQS_KEM *kem;
 34      LSC_param_desc_t param_desc[3]; /* Space for the sec and pub key, and NULL */
 35    } _;
 36  };
 37  
 38  /* Param helpers */
 39  
 40  static LSplugin_param_functions_t sec_fns = {
 41    offsetof(struct oqs_key_st, sec),
 42    offsetof(struct oqs_key_st, sec_len),
 43    0, false,
 44    LSplugin_set_octetstring_param, LSplugin_get_octetstring_param
 45  };
 46  static LSplugin_param_functions_t pub_fns = {
 47    offsetof(struct oqs_key_st, pub),
 48    offsetof(struct oqs_key_st, pub_len),
 49    0, false,
 50    LSplugin_set_octetstring_param, LSplugin_get_octetstring_param
 51  };
 52  
 53  /*
 54   * The set of functions that actually do something
 55   */
 56  
 57  /* For encapsulator operations */
 58  
 59  static LE_STATUS set_encap_key(LSC_encapsulator_t *op, LSC_key_t *key)
 60  {
 61    op->lsc_data = key;
 62    return LE_STS_SUCCESS;
 63  }
 64  static LE_STATUS get_encap_key(LSC_encapsulator_t *op, LSC_key_t **key)
 65  {
 66    *key = op->lsc_data;
 67    return LE_STS_SUCCESS;
 68  }
 69  
 70  static LE_STATUS get_encap_shared_secret_size(LSC_encapsulator_t *encap, size_t *size)
 71  {
 72    const LSplugin_encapsulator_desc_t *desc = encap->lsc_dispatch_data;
 73    const struct oqs_data_st *data = desc->lsp_priv_desc;
 74    *size = data->kem->length_shared_secret;
 75    return LE_STS_SUCCESS;
 76  }
 77  static LE_STATUS get_encap_output_size(LSC_encapsulator_t *encap, size_t *size)
 78  {
 79    const LSplugin_encapsulator_desc_t *desc = encap->lsc_dispatch_data;
 80    const struct oqs_data_st *data = desc->lsp_priv_desc;
 81    *size = data->kem->length_ciphertext;
 82    return LE_STS_SUCCESS;
 83  }
 84  static LE_STATUS perform_encap_once(LSC_encapsulator_t *op,
 85                                      unsigned char *wrappedsecret,
 86                                      size_t wrappedsecretsize,
 87                                      size_t *wrappedsecretlen,
 88                                      unsigned char *sharedsecret,
 89                                      size_t sharedsecretsize,
 90                                      size_t *sharedsecretlen)
 91  {
 92    LSC_key_t *key = op->lsc_data;
 93    struct oqs_key_st *k = key->lsc_data;
 94    const LSplugin_encapsulator_desc_t *desc = op->lsc_dispatch_data;
 95    const struct oqs_data_st *data = desc->lsp_priv_desc;
 96    if (data->kem->length_ciphertext > wrappedsecretsize
 97        || data->kem->length_shared_secret > sharedsecretsize)
 98      return LE_STS_ERROR;
 99    if (k->pub == NULL)
100      return LE_STS_INVALID_PARAMETER;
101    OQS_STATUS oqssts = OQS_KEM_encaps(data->kem, wrappedsecret, sharedsecret, k->pub);
102    *wrappedsecretlen = data->kem->length_ciphertext;
103    *sharedsecretlen = data->kem->length_shared_secret;
104    return oqssts == OQS_SUCCESS ? LE_STS_SUCCESS : LE_STS_ERROR;
105  }
106  
107  /* For decapsulator operations */
108  
109  static LE_STATUS set_decap_key(LSC_decapsulator_t *op, LSC_key_t *key)
110  {
111    op->lsc_data = key;
112    return LE_STS_SUCCESS;
113  }
114  static LE_STATUS get_decap_key(LSC_decapsulator_t *op, LSC_key_t **key)
115  {
116    *key = op->lsc_data;
117    return LE_STS_SUCCESS;
118  }
119  static LE_STATUS get_decap_input_size(LSC_decapsulator_t *decap, size_t *size)
120  {
121    const LSplugin_decapsulator_desc_t *desc = decap->lsc_dispatch_data;
122    const struct oqs_data_st *data = desc->lsp_priv_desc;
123    *size = data->kem->length_ciphertext;
124    return LE_STS_SUCCESS;
125  }
126  static LE_STATUS get_decap_shared_secret_size(LSC_decapsulator_t *decap, size_t *size)
127  {
128    const LSplugin_decapsulator_desc_t *desc = decap->lsc_dispatch_data;
129    const struct oqs_data_st *data = desc->lsp_priv_desc;
130    *size = data->kem->length_shared_secret;
131    return LE_STS_SUCCESS;
132  }
133  static LE_STATUS perform_decap_once(LSC_decapsulator_t *op, 
134                                    const unsigned char *wrappedsecret,
135                                    size_t wrappedsecretlen,
136                                    unsigned char *sharedsecret,
137                                    size_t sharedsecretsize,
138                                    size_t *sharedsecretlen)
139  {
140    LSC_key_t *key = op->lsc_data;
141    struct oqs_key_st *k = key->lsc_data;
142    const LSplugin_encapsulator_desc_t *desc = op->lsc_dispatch_data;
143    const const struct oqs_data_st *data = desc->lsp_priv_desc;
144    if (data->kem->length_ciphertext != wrappedsecretlen
145        || data->kem->length_shared_secret > sharedsecretsize)
146      return LE_STS_ERROR;
147    if (k->sec == NULL)
148      return LE_STS_INVALID_PARAMETER;
149    OQS_STATUS oqssts = OQS_KEM_decaps(data->kem, sharedsecret, wrappedsecret, k->sec);
150    *sharedsecretlen = data->kem->length_shared_secret;
151    return oqssts == OQS_SUCCESS ? LE_STS_SUCCESS : LE_STS_ERROR;
152  }
153  
154  /* For generator operations */
155  
156  static LE_STATUS set_gen_key(LSC_key_generator_t *op, LSC_key_t *key)
157  {
158    op->lsc_data = key;
159    return LE_STS_SUCCESS;
160  }
161  
162  static LE_STATUS get_gen_key(LSC_key_generator_t *op, LSC_key_t **key)
163  {
164    *key = op->lsc_data;
165    return LE_STS_SUCCESS;
166  }
167  
168  static LE_STATUS generate_key(LSC_key_generator_t *op)
169  {
170    LSC_key_t *key = op->lsc_data;
171    struct oqs_key_st *k = key->lsc_data;
172    const LSplugin_key_generator_desc_t *desc = op->lsc_dispatch_data;
173    const struct oqs_data_st *data = desc->lsp_priv_desc;
174    k->sec = realloc(k->sec, data->kem->length_secret_key);
175    k->pub = realloc(k->pub, data->kem->length_public_key);
176    if (k->sec == NULL || k->pub == NULL)
177      return LE_STS_FATAL_ERROR;
178    OQS_STATUS oqssts = OQS_KEM_keypair(data->kem, k->pub, k->sec);
179    if (oqssts != OQS_SUCCESS)
180      return LE_STS_ERROR;
181    k->sec_len = data->kem->length_secret_key;
182    k->pub_len = data->kem->length_public_key;
183    return LE_STS_SUCCESS;
184  }
185  
186  /* For constructor operations */
187  
188  static LE_STATUS set_con_key(LSC_key_constructor_t *op, LSC_key_t *key)
189  {
190    op->lsc_data = key;
191    return LE_STS_SUCCESS;
192  }
193  
194  static LE_STATUS get_con_key(LSC_key_constructor_t *op, LSC_key_t **key)
195  {
196    *key = op->lsc_data;
197    return LE_STS_SUCCESS;
198  }
199  
200  static LE_STATUS get_con_param_data(LSC_key_constructor_t *op, void **data)
201  {
202    LSC_key_t *key = op->lsc_data;
203    *data = key->lsc_data;
204    return LE_STS_SUCCESS;
205  }
206  
207  static LE_STATUS
208  get_settable_con_param_desc(LSC_key_constructor_t *op,
209                              const LSC_param_desc_t **param_desc)
210  {
211    const LSplugin_key_constructor_desc_t *desc = op->lsc_dispatch_data;
212    const struct oqs_data_st *data = desc->lsp_priv_desc;
213    *param_desc = data->param_desc;
214    return LE_STS_SUCCESS;
215  }
216  
217  /* For extractor operations */
218  
219  static LE_STATUS set_ext_key(LSC_key_extractor_t *op, LSC_key_t *key)
220  {
221    op->lsc_data = key;
222    return LE_STS_SUCCESS;
223  }
224  
225  static LE_STATUS get_ext_key(LSC_key_extractor_t *op, LSC_key_t **key)
226  {
227    *key = op->lsc_data;
228    return LE_STS_SUCCESS;
229  }
230  
231  static LE_STATUS get_ext_param_data(LSC_key_extractor_t *op, void **data)
232  {
233    LSC_key_t *key = op->lsc_data;
234    *data = key->lsc_data;
235    return LE_STS_SUCCESS;
236  }
237  
238  static LE_STATUS
239  get_gettable_ext_param_desc(LSC_key_extractor_t *op,
240                              const LSC_param_desc_t **param_desc)
241  {
242    const LSplugin_key_extractor_desc_t *desc = op->lsc_dispatch_data;
243    const struct oqs_data_st *data = desc->lsp_priv_desc;
244    *param_desc = data->param_desc;
245    return LE_STS_SUCCESS;
246  }
247  
248  /* For the key objects */
249  
250  static LE_STATUS setup_key_data(LSC_key_t *key, const void *priv_desc)
251  {
252    const struct oqs_data_st *data = priv_desc;
253    struct oqs_key_st **k = (struct oqs_key_st **)&(key->lsc_data);
254    if (*k == NULL) {
255      (*k) = malloc(sizeof(**k));
256      memset(*k, 0, sizeof(**k));
257    }
258    return LE_STS_SUCCESS;
259  }
260  
261  static LE_STATUS clean_key_data(LSC_key_t *key)
262  {
263    struct oqs_key_st **k = (struct oqs_key_st **)&(key->lsc_data);
264    if (*k != NULL) {
265      free((*k)->sec); (*k)->sec = NULL;
266      free((*k)->pub); (*k)->pub = NULL;
267      free((*k)); *k = NULL;
268    }
269    return LE_STS_SUCCESS;
270  }
271  
272  /*
273   * Create the list of struct oqs_encap_st, save that list in our environment,
274   * and register all the algorithms in the plugin's parent environment
275   */
276  
277  static struct oqs_impl_st *mkkemlist(void)
278  {
279    int nkems = OQS_KEM_alg_count();
280    struct oqs_impl_st *kems = calloc(nkems + 1, sizeof(*kems));
281  
282    if (kems)
283      for (int i = 0, j = 0; i < nkems; i++) {
284        const char *name = OQS_KEM_alg_identifier(i);
285        if (!OQS_KEM_alg_is_enabled(name))
286          continue;
287        OQS_KEM *encap = OQS_KEM_new(name);
288        if (encap == NULL)
289          continue;
290        size_t seclen = encap->length_secret_key;
291        size_t publen = encap->length_public_key;
292  
293        kems[j] = (struct oqs_impl_st){
294          /* Descriptors for the free standing implementations */
295          .encapsulator = {
296            NULL, name, &kems[j]._, name,
297            NULL, NULL,
298            NULL,                   /* No lsp_set_key_encapsulator */
299            set_encap_key,
300            get_encap_key,
301            (int[]){ LSC_ENCAPSULATOR_TYPE_BASE_COMMANDS(),
302                     LSC_ENCAPSULATOR_SIZE_COMMANDS(),
303                     LSC_NR_perform_encapsulation_once, 0 },
304            NULL,
305            NULL,
306            NULL,
307            get_encap_shared_secret_size,
308            get_encap_output_size,
309            perform_encap_once,
310          },
311          .decapsulator = {
312            NULL, name, &kems[j]._, name,
313            NULL, NULL,
314            NULL,                   /* No lsp_set_key_decapsulation */
315            set_decap_key,
316            get_decap_key,
317            (int[]){ LSC_ENCAPSULATOR_TYPE_BASE_COMMANDS(),
318                     LSC_ENCAPSULATOR_SIZE_COMMANDS(),
319                     LSC_NR_perform_decapsulation_once, 0 },
320            NULL,
321            NULL,
322            NULL,
323            get_decap_input_size,
324            get_decap_shared_secret_size,
325            perform_decap_once,
326          },
327  
328          /* Descriptors for the key associated implementations */
329          .assoc_encapsulator = {
330            NULL, NULL, &kems[j]._, NULL,
331            NULL, NULL,
332            NULL,                   /* No lsp_set_key_encapsulator */
333            set_encap_key,
334            get_encap_key,
335            (int[]){ LSC_ENCAPSULATOR_TYPE_BASE_COMMANDS(),
336                     LSC_ENCAPSULATOR_SIZE_COMMANDS(),
337                     LSC_NR_perform_encapsulation_once, 0 },
338            NULL,
339            NULL,
340            NULL,
341            get_encap_shared_secret_size,
342            get_encap_output_size,
343            perform_encap_once,
344          },
345          .assoc_decapsulator = {
346            NULL, NULL, &kems[j]._, NULL,
347            NULL, NULL,
348            NULL,                   /* No lsp_set_key_decapsulation */
349            set_decap_key,
350            get_decap_key,
351            (int[]){ LSC_DECAPSULATOR_TYPE_BASE_COMMANDS(),
352                     LSC_DECAPSULATOR_SIZE_COMMANDS(),
353                     LSC_NR_perform_decapsulation_once, 0 },
354            NULL,
355            NULL,
356            NULL,
357            get_decap_input_size,
358            get_decap_shared_secret_size,
359            perform_decap_once,
360          },
361  
362          /* Descriptors for the key generator */
363          .assoc_generator = {
364            NULL, NULL, &kems[j]._, NULL,
365            NULL, NULL,
366            NULL,                   /* No lsp_set_key_generator */
367            set_gen_key,
368            get_gen_key,
369            (int[]){ LSC_KEY_TYPE_BASE_COMMANDS(),
370                     LSC_NR_generate_key, 0 },
371            NULL,
372            NULL,                   /* No gettable */
373            NULL,                   /* No settable */
374            generate_key,
375          },
376  
377          /* Descriptors for the key constructor */
378          .assoc_constructor = {
379            NULL, NULL, &kems[j]._, NULL,
380            NULL, NULL,
381            NULL,                   /* No lsp_set_key_constructor */
382            set_con_key,
383            get_con_key,
384            (int[]){ LSC_KEY_TYPE_BASE_COMMANDS(),
385                     LSC_NR_construct_key, 0 },
386            get_con_param_data,
387            NULL,                   /* No gettable */
388            get_settable_con_param_desc,
389            NULL,                   /* No constructor function */
390          },
391  
392          /* Descriptors for the key extractor */
393          .assoc_extractor = {
394            NULL, NULL, &kems[j]._, NULL,
395            NULL, NULL,
396            NULL,                   /* No lsp_set_key_extractor */
397            set_ext_key,
398            get_ext_key,
399            (int[]){ LSC_KEY_TYPE_BASE_COMMANDS(), 0 },
400            get_ext_param_data,
401            get_gettable_ext_param_desc,
402            NULL,                   /* No settable */
403          },
404  
405          /* Descriptors for the key itself */
406          .key = {
407            NULL, name, &kems[j]._,
408            setup_key_data, clean_key_data,
409            (int[]){ LSC_KEY_TYPE_BASE_COMMANDS(),
410                     LSC_NR_get_key_generator,
411                     LSC_NR_get_key_constructor,
412                     LSC_NR_get_key_extractor,
413                     LSC_NR_get_associated_encapsulator,
414                     LSC_NR_get_associated_decapsulator, 0 },
415            NULL,                   /* No get_key_size */
416            &kems[j].assoc_generator,
417            &kems[j].assoc_constructor,
418            &kems[j].assoc_extractor,
419            NULL,
420            NULL,
421            NULL,
422            NULL,
423            NULL,
424            NULL,
425            &kems[j].assoc_encapsulator,
426            &kems[j].assoc_decapsulator,
427          },
428  
429          ._ = {
430            encap,
431            {
432              { "sec", 1,
433                { LSC_DT_octet_string,
434                  { encap->length_secret_key, encap->length_secret_key } },
435                &sec_fns,
436                "The secret key" },
437              { "pub", 2,
438                { LSC_DT_octet_string,
439                  { encap->length_public_key, encap->length_public_key } },
440                &pub_fns,
441                "The public key" },
442              { NULL, 0 }                        
443            }
444          }
445        };
446        j++;
447      }
448  
449    return kems;
450  }
451  
452  static void freekemlist(struct oqs_impl_st *kems)
453  {
454    if (kems) {
455      for (struct oqs_impl_st *s = kems; s->key.lsp_id != NULL; s++)
456        OQS_KEM_free(s->_.kem);
457      free(kems);
458    }
459  }
460  
461  /* The tag to get an index could be better... */
462  static const char *tag = "oqs-kems";
463  
464  LE_STATUS oqs_register_kems(LSC_env_t *env, LSC_plugin_t *plugin)
465  {
466    LE_STATUS sts;
467    int index;
468    struct oqs_impl_st *kems = mkkemlist();
469  
470    if (kems == NULL)
471      return LE_STS_ALLOC_FAILURE;
472    if (LE_status_is_OK(sts = LSC_get_index(env, "oqs-kems", &index))
473        && LE_status_is_OK(sts = LSC_set_plugin_application_data(plugin, index, kems)))
474      for (struct oqs_impl_st *s = kems; s->key.lsp_id != NULL; s++) {
475        sts = LSC_register_encapsulator_implementation(env, plugin,
476                                                 s->encapsulator.lsp_id,
477                                                 LSplugin_encapsulator_dispatch,
478                                                 LSplugin_destroy_encapsulator,
479                                                 &s->encapsulator,
480                                                 s->encapsulator.lsp_docstring);
481        if (!LE_status_is_OK(sts))
482          break;
483        sts = LSC_register_decapsulator_implementation(env, plugin,
484                                                   s->decapsulator.lsp_id,
485                                                   LSplugin_decapsulator_dispatch,
486                                                   LSplugin_destroy_decapsulator,
487                                                   &s->decapsulator,
488                                                   s->decapsulator.lsp_docstring);
489        if (!LE_status_is_OK(sts))
490          break;
491        sts = LSC_register_key_implementation(env, plugin,
492                                              s->key.lsp_id,
493                                              LSplugin_key_dispatch,
494                                              LSplugin_destroy_key,
495                                              &s->key,
496                                              s->key.lsp_docstring);
497        if (!LE_status_is_OK(sts))
498          break;
499      }
500    
501    return sts;
502  }
503  
504  LE_STATUS oqs_deregister_kems(LSC_env_t *env, LSC_plugin_t *plugin)
505  {
506    LE_STATUS sts;
507    int index;
508    struct oqs_impl_st *kems = NULL;
509  
510    if (LE_status_is_OK(sts = LSC_get_index(env, "oqs-kems", &index))
511        && LE_status_is_OK(sts = LSC_get_plugin_application_data(plugin, index, &kems))) {
512      for (struct oqs_impl_st *s = kems; s->key.lsp_id != NULL; s++) {
513        sts = LSC_deregister_encapsulator_implementation(env, plugin,
514                                                   s->encapsulator.lsp_id,
515                                                   LSplugin_encapsulator_dispatch,
516                                                   LSplugin_destroy_encapsulator,
517                                                   &s->encapsulator,
518                                                   s->encapsulator.lsp_docstring);
519        if (!LE_status_is_OK(sts))
520          break;
521        sts = LSC_deregister_decapsulator_implementation(env, plugin,
522                                                     s->decapsulator.lsp_id,
523                                                     LSplugin_decapsulator_dispatch,
524                                                     LSplugin_destroy_decapsulator,
525                                                     &s->decapsulator,
526                                                     s->decapsulator.lsp_docstring);
527        if (!LE_status_is_OK(sts))
528          break;
529        sts = LSC_deregister_key_implementation(env, plugin,
530                                                s->key.lsp_id,
531                                                LSplugin_key_dispatch,
532                                                LSplugin_destroy_key,
533                                                &s->key,
534                                                s->key.lsp_docstring);
535        if (!LE_status_is_OK(sts))
536          break;
537      }
538      freekemlist(kems);
539    }
540    return sts;
541  }