Coverage Report

Created: 2026-03-08 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/unit/src/nxt_random.c
Line
Count
Source
1
2
/*
3
 * Copyright (C) Igor Sysoev
4
 * Copyright (C) NGINX, Inc.
5
 */
6
7
8
#include <nxt_main.h>
9
10
11
/*
12
 * The pseudorandom generator based on OpenBSD arc4random.  Although it is
13
 * usually stated that arc4random uses RC4 pseudorandom generation algorithm
14
 * they are actually different in nxt_random_add().
15
 */
16
17
18
40
#define NXT_RANDOM_KEY_SIZE  128
19
20
21
nxt_inline void nxt_random_start_schedule(nxt_random_t *r);
22
static void nxt_random_stir(nxt_random_t *r);
23
static void nxt_random_add(nxt_random_t *r, const u_char *key, uint32_t len);
24
nxt_inline uint8_t nxt_random_byte(nxt_random_t *r);
25
26
27
void
28
nxt_random_init(nxt_random_t *r)
29
10
{
30
10
    nxt_random_start_schedule(r);
31
32
10
    nxt_random_stir(r);
33
10
}
34
35
36
nxt_inline void
37
nxt_random_start_schedule(nxt_random_t *r)
38
10
{
39
10
    nxt_uint_t  i;
40
41
10
    r->i = 0;
42
10
    r->j = 0;
43
44
2.57k
    for (i = 0; i < 256; i++) {
45
2.56k
        r->s[i] = i;
46
2.56k
    }
47
10
}
48
49
50
static void
51
nxt_random_stir(nxt_random_t *r)
52
10
{
53
10
    int             fd;
54
10
    ssize_t         n;
55
10
    struct timeval  tv;
56
10
    union {
57
10
        uint32_t    value[4];
58
10
        u_char      bytes[NXT_RANDOM_KEY_SIZE];
59
10
    } key;
60
61
10
#if (NXT_HAVE_GETRANDOM)
62
63
10
    n = getrandom(&key, NXT_RANDOM_KEY_SIZE, 0);
64
65
#elif (NXT_HAVE_LINUX_SYS_GETRANDOM)
66
67
    /* Linux 3.17 SYS_getrandom. */
68
69
    n = syscall(SYS_getrandom, &key, NXT_RANDOM_KEY_SIZE, 0);
70
71
#elif (NXT_HAVE_GETENTROPY || NXT_HAVE_GETENTROPY_SYS_RANDOM)
72
73
    n = 0;
74
75
    if (getentropy(&key, NXT_RANDOM_KEY_SIZE) == 0) {
76
        n = NXT_RANDOM_KEY_SIZE;
77
    }
78
79
#else
80
81
    n = 0;
82
83
#endif
84
85
10
    if (n != NXT_RANDOM_KEY_SIZE) {
86
0
        fd = open("/dev/urandom", O_RDONLY);
87
88
0
        if (fd >= 0) {
89
0
            n = read(fd, &key, NXT_RANDOM_KEY_SIZE);
90
0
            (void) close(fd);
91
0
        }
92
0
    }
93
94
10
    if (n != NXT_RANDOM_KEY_SIZE) {
95
0
        (void) gettimeofday(&tv, NULL);
96
97
        /* XOR with stack garbage. */
98
99
0
        key.value[0] ^= tv.tv_usec;
100
0
        key.value[1] ^= tv.tv_sec;
101
0
        key.value[2] ^= nxt_pid;
102
0
        key.value[3] ^= (uintptr_t) nxt_thread_tid(nxt_thread());
103
0
    }
104
105
10
    nxt_random_add(r, key.bytes, NXT_RANDOM_KEY_SIZE);
106
107
    /* Drop the first 3072 bytes. */
108
30.7k
    for (n = 3072; n != 0; n--) {
109
30.7k
        (void) nxt_random_byte(r);
110
30.7k
    }
111
112
    /* Stir again after 1,600,000 bytes. */
113
10
    r->count = 400000;
114
10
}
115
116
117
static void
118
nxt_random_add(nxt_random_t *r, const u_char *key, uint32_t len)
119
10
{
120
10
    uint8_t   val;
121
10
    uint32_t  n;
122
123
2.57k
    for (n = 0; n < 256; n++) {
124
2.56k
        val = r->s[r->i];
125
2.56k
        r->j += val + key[n % len];
126
127
2.56k
        r->s[r->i] = r->s[r->j];
128
2.56k
        r->s[r->j] = val;
129
130
2.56k
        r->i++;
131
2.56k
    }
132
133
    /* This index is not decremented in RC4 algorithm. */
134
10
    r->i--;
135
136
10
    r->j = r->i;
137
10
}
138
139
140
uint32_t
141
nxt_random(nxt_random_t *r)
142
0
{
143
0
    uint32_t  val;
144
145
0
    r->count--;
146
147
0
    if (r->count <= 0) {
148
0
        nxt_random_stir(r);
149
0
    }
150
151
0
    val  = (uint32_t) nxt_random_byte(r) << 24;
152
0
    val |= (uint32_t) nxt_random_byte(r) << 16;
153
0
    val |= (uint32_t) nxt_random_byte(r) << 8;
154
0
    val |= (uint32_t) nxt_random_byte(r);
155
156
0
    return val;
157
0
}
158
159
160
nxt_inline uint8_t
161
nxt_random_byte(nxt_random_t *r)
162
30.7k
{
163
30.7k
    uint8_t  si, sj;
164
165
30.7k
    r->i++;
166
30.7k
    si = r->s[r->i];
167
30.7k
    r->j += si;
168
169
30.7k
    sj = r->s[r->j];
170
30.7k
    r->s[r->i] = sj;
171
30.7k
    r->s[r->j] = si;
172
173
30.7k
    si += sj;
174
175
30.7k
    return r->s[si];
176
30.7k
}
177
178
179
#if (NXT_TESTS)
180
181
nxt_int_t
182
nxt_random_test(nxt_thread_t *thr)
183
0
{
184
0
    nxt_uint_t    n;
185
0
    nxt_random_t  r;
186
187
0
    nxt_random_start_schedule(&r);
188
189
0
    r.count = 400000;
190
191
0
    nxt_random_add(&r, (u_char *) "arc4random", nxt_length("arc4random"));
192
193
    /*
194
     * Test arc4random() numbers.
195
     * RC4 pseudorandom numbers would be 0x4642AFC3 and 0xBAF0FFF0.
196
     */
197
198
0
    if (nxt_random(&r) == 0xD6270B27) {
199
200
0
        for (n = 100000; n != 0; n--) {
201
0
            (void) nxt_random(&r);
202
0
        }
203
204
0
        if (nxt_random(&r) == 0x6FCAE186) {
205
0
            nxt_log_error(NXT_LOG_NOTICE, thr->log, "arc4random test passed");
206
207
0
            return NXT_OK;
208
0
        }
209
0
    }
210
211
0
    nxt_log_error(NXT_LOG_NOTICE, thr->log, "arc4random test failed");
212
213
0
    return NXT_ERROR;
214
0
}
215
216
#endif