/ ltc-rand.c
ltc-rand.c
  1  /*
  2   * Licensed under the Apache License, Version 2.0 (the "License");
  3   * you may not use this file except in compliance with the License.
  4   * See the NOTICE file distributed with this work for additional
  5   * information regarding copyright ownership.
  6   * You may obtain a copy of the License at
  7   *
  8   *     http://www.apache.org/licenses/LICENSE-2.0
  9   *
 10   * Unless required by applicable law or agreed to in writing, software
 11   * distributed under the License is distributed on an "AS IS" BASIS,
 12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13   * See the License for the specific language governing permissions and
 14   * limitations under the License.
 15   */
 16  
 17  #include <stdarg.h>
 18  #include <lscore/plugin.h>
 19  #include <lscrypto/rand.h>
 20  #include <tomcrypt.h>
 21  #include <lsplugin/param.h>
 22  #include <lsplugin/mkoperator.h>
 23  #include "ltc-methods.h"
 24  
 25  #define T(x) LE_status_is_OK(x)
 26  
 27  #define nelems(a) (sizeof(a) / sizeof(a[0]))
 28  
 29  struct ltc_rbg_st {
 30    const struct ltc_prng_descriptor *prng;
 31    prng_state state;         /* libtomcrypt prng state */
 32    int wprng;                /* libtomcrypt prng registration number */
 33  
 34    size_t min_entropy_bits;
 35  };
 36  
 37  static LE_STATUS setup_rbg_data(LSC_rbg_t *rbg)
 38  {
 39    assert(rbg != NULL);
 40  
 41    const LSplugin_rbg_desc_t *desc = rbg->lsc_dispatch_data;
 42    struct ltc_rbg_st **state = (struct ltc_rbg_st **)&rbg->lsc_data;
 43    if (*state == NULL) {
 44      *state = malloc(sizeof(**state));
 45      memset(*state, 0, sizeof(**state));
 46      (*state)->wprng = -1;
 47  
 48      LE_STATUS sts;
 49      int wprng = find_prng(desc->lsp_id);
 50  
 51      if (wprng == -1)
 52        wprng = register_prng(desc->lsp_priv_desc);
 53      if (wprng < 0)
 54        return LE_STS_ERROR;
 55      (*state)->prng = desc->lsp_priv_desc;
 56      (*state)->wprng = wprng;
 57      (*state)->min_entropy_bits = 128;
 58    }
 59    if (*state == NULL)
 60      return LE_STS_FATAL_ERROR;
 61  
 62    assert((*state)->prng == desc->lsp_priv_desc);
 63    assert((*state)->wprng >= 0);
 64  
 65    return LE_STS_SUCCESS;
 66  }
 67  
 68  static LE_STATUS clean_rbg_data(LSC_rbg_t *rbg)
 69  {
 70    return LE_STS_SUCCESS;
 71  }
 72  
 73  static LE_STATUS start_rbg(LSC_rbg_t *rbg, const char *personalization)
 74  {
 75    int err;                      /* libtomcrypt error code */
 76  
 77    assert(rbg != NULL && rbg->lsc_data != NULL);
 78  
 79    struct ltc_rbg_st *state = rbg->lsc_data;
 80  
 81    err = rng_make_prng(state->min_entropy_bits, state->wprng, &state->state, NULL);
 82    if (err != CRYPT_OK)
 83      return LE_STS_ERROR;
 84    if (personalization != NULL)
 85      err = state->prng->add_entropy((unsigned char *)personalization,
 86                                     strlen(personalization),
 87                                     &state->state);
 88    if (err != CRYPT_OK)
 89      return LE_STS_ERROR;
 90    return LE_STS_SUCCESS;
 91  }
 92  
 93  static LE_STATUS extract_rbg_output(LSC_rbg_t *rbg, size_t number_of_bits,
 94                                      size_t security_strength,
 95                                      _Bool prediction_resistance,
 96                                      const char *additional_input,
 97                                      unsigned char *out, size_t outsize,
 98                                      size_t *outlen)
 99  {
100    int err;                      /* libtomcrypt error code */
101  
102    assert(rbg != NULL && rbg->lsc_data != NULL);
103  
104    struct ltc_rbg_st *state = rbg->lsc_data;
105    size_t number_of_bytes = (number_of_bits + 7) / 8;
106  
107    if (number_of_bytes > outsize)
108      return LE_STS_ERROR;
109  
110    if (additional_input != NULL) {
111      err = state->prng->add_entropy((unsigned char *)additional_input,
112                                     strlen(additional_input),
113                                     &state->state);
114      if (err != CRYPT_OK)
115        return LE_STS_ERROR;
116    }
117  
118    size_t n = state->prng->read(out, number_of_bytes, &state->state);
119    *outlen = n;
120    return LE_STS_SUCCESS;
121  }
122  
123  static LE_STATUS reseed_rbg(LSC_rbg_t *rbg, const char *additional_input)
124  {
125    return LE_STS_ERROR;
126  }
127  
128  static LE_STATUS stop_rbg(LSC_rbg_t *rbg)
129  {
130    int err;                      /* libtomcrypt error code */
131  
132    assert(rbg != NULL && rbg->lsc_data != NULL);
133  
134    struct ltc_rbg_st *state = rbg->lsc_data;
135  
136    err = state->prng->done(&state->state);
137    if (err != CRYPT_OK)
138      return LE_STS_ERROR;
139    return LE_STS_SUCCESS;
140  }
141  
142  const LSplugin_rbg_desc_t ltc_fortuna_desc = {
143    NULL, "fortuna", &fortuna_desc, NULL,
144    setup_rbg_data, clean_rbg_data,
145    NULL, NULL, NULL,
146    (int[]){ LSC_RBG_TYPE_BASE_COMMANDS(),
147             LSC_NR_start_rbg,
148             LSC_NR_extract_rbg_output,
149             LSC_NR_stop_rbg, 0 },
150    NULL, /* No get_param_data */
151    NULL, /* No gettable */
152    NULL, /* No settable */
153    NULL, /* No set_entropy_source */
154    &start_rbg,
155    &extract_rbg_output,
156    NULL, /* No reseed */
157    &stop_rbg,
158  };