Coverage Report

Created: 2024-02-25 06:34

/src/kamailio/src/core/rand/fortuna/random.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * random.c
3
 *    Acquire randomness from system, for seeding RNG.
4
 *    Get pseudo random numbers from RNG.
5
 *
6
 * Copyright (c) 2001 Marko Kreen
7
 * Copyright (c) 2019 Henning Westerholt
8
 * All rights reserved.
9
 *
10
 * Based on https://github.com/waitman/libfortuna, refactoring
11
 * done in this version: https://github.com/henningw/libfortuna
12
 *
13
 * Redistribution and use in source and binary forms, with or without
14
 * modification, are permitted provided that the following conditions
15
 * are met:
16
 * 1. Redistributions of source code must retain the above copyright
17
 *    notice, this list of conditions and the following disclaimer.
18
 * 2. Redistributions in binary form must reproduce the above copyright
19
 *    notice, this list of conditions and the following disclaimer in the
20
 *    documentation and/or other materials provided with the distribution.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 * SUCH DAMAGE.
33
 *
34
 * contrib/pgcrypto/random.c
35
 */
36
37
#include <errno.h>
38
#include <time.h>
39
#include <sys/types.h>
40
#include <string.h>
41
42
#include "../../dprint.h"
43
44
#include "random.h"
45
#include "fortuna.h"
46
47
/* how many bytes to ask from system random provider */
48
0
#define RND_BYTES 32
49
50
/*
51
 * Try to read from /dev/urandom or /dev/random on these OS'es.
52
 *
53
 * The list can be pretty liberal, as the device not existing
54
 * is expected event.
55
 */
56
57
#include <fcntl.h>
58
#include <unistd.h>
59
60
static time_t seed_time = 0;
61
static time_t check_time = 0;
62
63
int sr_get_pseudo_random_bytes(u_int8_t *dst, unsigned count);
64
65
/* private functions */
66
67
static int safe_read(int fd, void *buf, size_t count)
68
0
{
69
0
  int done = 0;
70
0
  char *p = buf;
71
0
  int res;
72
73
0
  while(count) {
74
0
    res = read(fd, p, count);
75
0
    if(res <= 0) {
76
0
      if(errno == EINTR)
77
0
        continue;
78
0
      return -10;
79
0
    }
80
0
    p += res;
81
0
    done += res;
82
0
    count -= res;
83
0
  }
84
0
  return done;
85
0
}
86
87
static u_int8_t *try_dev_random(u_int8_t *dst)
88
0
{
89
0
  int fd;
90
0
  int res;
91
92
0
  fd = open("/dev/urandom", O_RDONLY, 0);
93
0
  if(fd == -1) {
94
0
    fd = open("/dev/random", O_RDONLY, 0);
95
0
    if(fd == -1)
96
0
      return dst;
97
0
  }
98
0
  res = safe_read(fd, dst, RND_BYTES);
99
0
  close(fd);
100
0
  if(res > 0)
101
0
    dst += res;
102
0
  return dst;
103
0
}
104
105
/*
106
 * try to extract some randomness for initial seeding
107
 *
108
 * dst should have room for 1024 bytes.
109
 */
110
static unsigned acquire_system_randomness(u_int8_t *dst)
111
0
{
112
0
  u_int8_t *p = dst;
113
114
0
  p = try_dev_random(p);
115
0
  return p - dst;
116
0
}
117
118
static void system_reseed(void)
119
0
{
120
0
  u_int8_t buf[1024];
121
0
  int n;
122
0
  time_t t;
123
0
  int skip = 1;
124
125
0
  t = time(NULL);
126
127
0
  if(seed_time == 0)
128
0
    skip = 0;
129
0
  else if((t - seed_time) < SYSTEM_RESEED_MIN)
130
0
    skip = 1;
131
0
  else if((t - seed_time) > SYSTEM_RESEED_MAX)
132
0
    skip = 0;
133
0
  else if(check_time == 0 || (t - check_time) > SYSTEM_RESEED_CHECK_TIME) {
134
0
    check_time = t;
135
136
    /* roll dice */
137
0
    sr_get_pseudo_random_bytes(buf, 1);
138
0
    skip = buf[0] >= SYSTEM_RESEED_CHANCE;
139
0
  }
140
  /* clear 1 byte */
141
0
  memset(buf, 0, sizeof(buf));
142
143
0
  if(skip)
144
0
    return;
145
146
0
  n = acquire_system_randomness(buf);
147
0
  if(n > 0) {
148
0
    fortuna_add_entropy(buf, n);
149
0
    LM_DBG("cryptographic PRNG reseed done with %u bytes\n", n);
150
0
  }
151
152
0
  seed_time = t;
153
0
  memset(buf, 0, sizeof(buf));
154
0
}
155
156
157
/* public functions */
158
159
int sr_get_pseudo_random_bytes(u_int8_t *dst, unsigned count)
160
0
{
161
0
  system_reseed();
162
0
  fortuna_get_bytes(count, dst);
163
0
  return 0;
164
0
}
165
166
167
int sr_add_entropy(const u_int8_t *data, unsigned count)
168
0
{
169
0
  system_reseed();
170
0
  LM_DBG("additional %u bytes entropy added to cryptographic PRNG\n", count);
171
0
  fortuna_add_entropy(data, count);
172
0
  return 0;
173
0
}