Coverage Report

Created: 2026-09-14 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmlibarchive/libarchive/archive_random.c
Line
Count
Source
1
/*-
2
 * Copyright (c) 2014 Michihiro NAKAJIMA
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
#include "archive_platform.h"
27
28
#ifdef HAVE_STDLIB_H
29
#include <stdlib.h>
30
#endif
31
32
#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
33
34
#ifdef HAVE_FCNTL
35
#include <fcntl.h>
36
#endif
37
#ifdef HAVE_LIMITS_H
38
#include <limits.h>
39
#endif
40
#ifdef HAVE_UNISTD_H
41
#include <unistd.h>
42
#endif
43
#ifdef HAVE_SYS_TYPES_H
44
#include <sys/types.h>
45
#endif
46
#ifdef HAVE_SYS_TIME_H
47
#include <sys/time.h>
48
#endif
49
#ifdef HAVE_PTHREAD_H
50
#include <pthread.h>
51
#endif
52
53
static void la_arc4random_buf(void *, size_t);
54
55
#endif /* HAVE_ARC4RANDOM_BUF */
56
57
#include "archive.h"
58
#include "archive_random_private.h"
59
60
#if defined(_WIN32) && !defined(__CYGWIN__)
61
#include <bcrypt.h>
62
63
/* Common in other bcrypt implementations, but missing from VS2008. */
64
#ifndef BCRYPT_SUCCESS
65
#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)
66
#endif
67
#endif
68
69
#ifndef O_CLOEXEC
70
#define O_CLOEXEC 0
71
#endif
72
73
/*
74
 * Random number generator function.
75
 * This simply calls arc4random_buf function if the platform provides it.
76
 */
77
78
int
79
archive_random(void *buf, size_t nbytes)
80
0
{
81
#if defined(_WIN32) && !defined(__CYGWIN__)
82
  NTSTATUS status;
83
  BCRYPT_ALG_HANDLE hAlg;
84
85
  status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, NULL, 0);
86
  if (!BCRYPT_SUCCESS(status))
87
    return ARCHIVE_FAILED;
88
  status = BCryptGenRandom(hAlg, buf, (ULONG)nbytes, 0);
89
  BCryptCloseAlgorithmProvider(hAlg, 0);
90
  if (!BCRYPT_SUCCESS(status))
91
    return ARCHIVE_FAILED;
92
93
  return ARCHIVE_OK;
94
#elif !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
95
  la_arc4random_buf(buf, nbytes);
96
0
  return ARCHIVE_OK;
97
#else
98
  arc4random_buf(buf, nbytes);
99
  return ARCHIVE_OK;
100
#endif
101
0
}
102
103
#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
104
105
/*  $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */
106
/*
107
 * Copyright (c) 1996, David Mazieres <dm@uun.org>
108
 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
109
 *
110
 * Permission to use, copy, modify, and distribute this software for any
111
 * purpose with or without fee is hereby granted, provided that the above
112
 * copyright notice and this permission notice appear in all copies.
113
 *
114
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
115
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
116
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
117
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
118
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
119
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
120
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
121
 */
122
123
/*
124
 * Arc4 random number generator for OpenBSD.
125
 *
126
 * This code is derived from section 17.1 of Applied Cryptography,
127
 * second edition, which describes a stream cipher allegedly
128
 * compatible with RSA Labs "RC4" cipher (the actual description of
129
 * which is a trade secret).  The same algorithm is used as a stream
130
 * cipher called "arcfour" in Tatu Ylonen's ssh package.
131
 *
132
 * RC4 is a registered trademark of RSA Laboratories.
133
 */
134
135
#ifdef __GNUC__
136
#define inline __inline
137
#else       /* !__GNUC__ */
138
#define inline
139
#endif        /* !__GNUC__ */
140
141
struct arc4_stream {
142
  uint8_t i;
143
  uint8_t j;
144
  uint8_t s[256];
145
};
146
147
0
#define RANDOMDEV "/dev/urandom"
148
0
#define KEYSIZE   128
149
#ifdef HAVE_PTHREAD_H
150
static pthread_mutex_t  arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
151
0
#define _ARC4_LOCK()  pthread_mutex_lock(&arc4random_mtx);
152
0
#define _ARC4_UNLOCK()  pthread_mutex_unlock(&arc4random_mtx);
153
#else
154
#define _ARC4_LOCK()
155
#define _ARC4_UNLOCK()
156
#endif
157
158
static int rs_initialized;
159
static struct arc4_stream rs;
160
static pid_t arc4_stir_pid;
161
static int arc4_count;
162
163
static inline uint8_t arc4_getbyte(void);
164
static void arc4_stir(void);
165
166
static inline void
167
arc4_init(void)
168
0
{
169
0
  int     n;
170
171
0
  for (n = 0; n < 256; n++)
172
0
    rs.s[n] = n;
173
0
  rs.i = 0;
174
0
  rs.j = 0;
175
0
}
176
177
static inline void
178
arc4_addrandom(uint8_t *dat, int datlen)
179
0
{
180
0
  int     n;
181
0
  uint8_t si;
182
183
0
  rs.i--;
184
0
  for (n = 0; n < 256; n++) {
185
0
    rs.i = (rs.i + 1);
186
0
    si = rs.s[rs.i];
187
0
    rs.j = (rs.j + si + dat[n % datlen]);
188
0
    rs.s[rs.i] = rs.s[rs.j];
189
0
    rs.s[rs.j] = si;
190
0
  }
191
0
  rs.j = rs.i;
192
0
}
193
194
static void
195
arc4_stir(void)
196
0
{
197
0
  int done, fd, i;
198
0
  struct {
199
0
    struct timeval  tv;
200
0
    pid_t   pid;
201
0
    uint8_t   rnd[KEYSIZE];
202
0
  } rdat;
203
204
0
  if (!rs_initialized) {
205
0
    arc4_init();
206
0
    rs_initialized = 1;
207
0
  }
208
0
  done = 0;
209
0
  fd = open(RANDOMDEV, O_RDONLY | O_CLOEXEC, 0);
210
0
  if (fd >= 0) {
211
0
    if (read(fd, &rdat, KEYSIZE) == KEYSIZE)
212
0
      done = 1;
213
0
    (void)close(fd);
214
0
  }
215
0
  if (!done) {
216
0
    (void)gettimeofday(&rdat.tv, NULL);
217
0
    rdat.pid = getpid();
218
    /* We'll just take whatever was on the stack too... */
219
0
  }
220
221
0
  arc4_addrandom((uint8_t *)&rdat, KEYSIZE);
222
223
  /*
224
   * Discard early keystream, as per recommendations in:
225
   * "(Not So) Random Shuffles of RC4" by Ilya Mironov.
226
   * As per the Network Operations Division, cryptographic requirements
227
   * published on wikileaks on March 2017.
228
   */
229
230
0
  for (i = 0; i < 3072; i++)
231
0
    (void)arc4_getbyte();
232
0
  arc4_count = 1600000;
233
0
}
234
235
static void
236
arc4_stir_if_needed(void)
237
0
{
238
0
  pid_t pid = getpid();
239
240
0
  if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) {
241
0
    arc4_stir_pid = pid;
242
0
    arc4_stir();
243
0
  }
244
0
}
245
246
static inline uint8_t
247
arc4_getbyte(void)
248
0
{
249
0
  uint8_t si, sj;
250
251
0
  rs.i = (rs.i + 1);
252
0
  si = rs.s[rs.i];
253
0
  rs.j = (rs.j + si);
254
0
  sj = rs.s[rs.j];
255
0
  rs.s[rs.i] = sj;
256
0
  rs.s[rs.j] = si;
257
0
  return (rs.s[(si + sj) & 0xff]);
258
0
}
259
260
static void
261
la_arc4random_buf(void *_buf, size_t n)
262
0
{
263
0
  uint8_t *buf = (uint8_t *)_buf;
264
0
  _ARC4_LOCK();
265
0
  arc4_stir_if_needed();
266
0
  while (n--) {
267
0
    if (--arc4_count <= 0)
268
0
      arc4_stir();
269
0
    buf[n] = arc4_getbyte();
270
0
  }
271
0
  _ARC4_UNLOCK();
272
0
}
273
274
#endif /* !HAVE_ARC4RANDOM_BUF */