Coverage Report

Created: 2026-03-12 06:35

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
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
62
/* don't use bcrypt when XP needs to be supported */
63
#include <bcrypt.h>
64
65
/* Common in other bcrypt implementations, but missing from VS2008. */
66
#ifndef BCRYPT_SUCCESS
67
#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)
68
#endif
69
70
#elif defined(HAVE_WINCRYPT_H)
71
#include <wincrypt.h>
72
#endif
73
#endif
74
75
#ifndef O_CLOEXEC
76
#define O_CLOEXEC 0
77
#endif
78
79
/*
80
 * Random number generator function.
81
 * This simply calls arc4random_buf function if the platform provides it.
82
 */
83
84
int
85
archive_random(void *buf, size_t nbytes)
86
0
{
87
#if defined(_WIN32) && !defined(__CYGWIN__)
88
# if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
89
  NTSTATUS status;
90
  BCRYPT_ALG_HANDLE hAlg;
91
92
  status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, NULL, 0);
93
  if (!BCRYPT_SUCCESS(status))
94
    return ARCHIVE_FAILED;
95
  status = BCryptGenRandom(hAlg, buf, (ULONG)nbytes, 0);
96
  BCryptCloseAlgorithmProvider(hAlg, 0);
97
  if (!BCRYPT_SUCCESS(status))
98
    return ARCHIVE_FAILED;
99
100
  return ARCHIVE_OK;
101
# else
102
  HCRYPTPROV hProv;
103
  BOOL success;
104
105
  success = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
106
      CRYPT_VERIFYCONTEXT);
107
  if (!success && GetLastError() == (DWORD)NTE_BAD_KEYSET) {
108
    success = CryptAcquireContext(&hProv, NULL, NULL,
109
        PROV_RSA_FULL, CRYPT_NEWKEYSET);
110
  }
111
  if (success) {
112
    success = CryptGenRandom(hProv, (DWORD)nbytes, (BYTE*)buf);
113
    CryptReleaseContext(hProv, 0);
114
    if (success)
115
      return ARCHIVE_OK;
116
  }
117
  /* TODO: Does this case really happen? */
118
  return ARCHIVE_FAILED;
119
# endif
120
#elif !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
121
  la_arc4random_buf(buf, nbytes);
122
0
  return ARCHIVE_OK;
123
#else
124
  arc4random_buf(buf, nbytes);
125
  return ARCHIVE_OK;
126
#endif
127
0
}
128
129
#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
130
131
/*  $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */
132
/*
133
 * Copyright (c) 1996, David Mazieres <dm@uun.org>
134
 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
135
 *
136
 * Permission to use, copy, modify, and distribute this software for any
137
 * purpose with or without fee is hereby granted, provided that the above
138
 * copyright notice and this permission notice appear in all copies.
139
 *
140
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
141
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
142
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
143
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
144
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
145
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
146
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
147
 */
148
149
/*
150
 * Arc4 random number generator for OpenBSD.
151
 *
152
 * This code is derived from section 17.1 of Applied Cryptography,
153
 * second edition, which describes a stream cipher allegedly
154
 * compatible with RSA Labs "RC4" cipher (the actual description of
155
 * which is a trade secret).  The same algorithm is used as a stream
156
 * cipher called "arcfour" in Tatu Ylonen's ssh package.
157
 *
158
 * RC4 is a registered trademark of RSA Laboratories.
159
 */
160
161
#ifdef __GNUC__
162
#define inline __inline
163
#else       /* !__GNUC__ */
164
#define inline
165
#endif        /* !__GNUC__ */
166
167
struct arc4_stream {
168
  uint8_t i;
169
  uint8_t j;
170
  uint8_t s[256];
171
};
172
173
0
#define RANDOMDEV "/dev/urandom"
174
0
#define KEYSIZE   128
175
#ifdef HAVE_PTHREAD_H
176
static pthread_mutex_t  arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
177
0
#define _ARC4_LOCK()  pthread_mutex_lock(&arc4random_mtx);
178
0
#define _ARC4_UNLOCK()  pthread_mutex_unlock(&arc4random_mtx);
179
#else
180
#define _ARC4_LOCK()
181
#define _ARC4_UNLOCK()
182
#endif
183
184
static int rs_initialized;
185
static struct arc4_stream rs;
186
static pid_t arc4_stir_pid;
187
static int arc4_count;
188
189
static inline uint8_t arc4_getbyte(void);
190
static void arc4_stir(void);
191
192
static inline void
193
arc4_init(void)
194
0
{
195
0
  int     n;
196
197
0
  for (n = 0; n < 256; n++)
198
0
    rs.s[n] = n;
199
0
  rs.i = 0;
200
0
  rs.j = 0;
201
0
}
202
203
static inline void
204
arc4_addrandom(uint8_t *dat, int datlen)
205
0
{
206
0
  int     n;
207
0
  uint8_t si;
208
209
0
  rs.i--;
210
0
  for (n = 0; n < 256; n++) {
211
0
    rs.i = (rs.i + 1);
212
0
    si = rs.s[rs.i];
213
0
    rs.j = (rs.j + si + dat[n % datlen]);
214
0
    rs.s[rs.i] = rs.s[rs.j];
215
0
    rs.s[rs.j] = si;
216
0
  }
217
0
  rs.j = rs.i;
218
0
}
219
220
static void
221
arc4_stir(void)
222
0
{
223
0
  int done, fd, i;
224
0
  struct {
225
0
    struct timeval  tv;
226
0
    pid_t   pid;
227
0
    uint8_t   rnd[KEYSIZE];
228
0
  } rdat;
229
230
0
  if (!rs_initialized) {
231
0
    arc4_init();
232
0
    rs_initialized = 1;
233
0
  }
234
0
  done = 0;
235
0
  fd = open(RANDOMDEV, O_RDONLY | O_CLOEXEC, 0);
236
0
  if (fd >= 0) {
237
0
    if (read(fd, &rdat, KEYSIZE) == KEYSIZE)
238
0
      done = 1;
239
0
    (void)close(fd);
240
0
  }
241
0
  if (!done) {
242
0
    (void)gettimeofday(&rdat.tv, NULL);
243
0
    rdat.pid = getpid();
244
    /* We'll just take whatever was on the stack too... */
245
0
  }
246
247
0
  arc4_addrandom((uint8_t *)&rdat, KEYSIZE);
248
249
  /*
250
   * Discard early keystream, as per recommendations in:
251
   * "(Not So) Random Shuffles of RC4" by Ilya Mironov.
252
   * As per the Network Operations Division, cryptographic requirements
253
   * published on wikileaks on March 2017.
254
   */
255
256
0
  for (i = 0; i < 3072; i++)
257
0
    (void)arc4_getbyte();
258
0
  arc4_count = 1600000;
259
0
}
260
261
static void
262
arc4_stir_if_needed(void)
263
0
{
264
0
  pid_t pid = getpid();
265
266
0
  if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) {
267
0
    arc4_stir_pid = pid;
268
0
    arc4_stir();
269
0
  }
270
0
}
271
272
static inline uint8_t
273
arc4_getbyte(void)
274
0
{
275
0
  uint8_t si, sj;
276
277
0
  rs.i = (rs.i + 1);
278
0
  si = rs.s[rs.i];
279
0
  rs.j = (rs.j + si);
280
0
  sj = rs.s[rs.j];
281
0
  rs.s[rs.i] = sj;
282
0
  rs.s[rs.j] = si;
283
0
  return (rs.s[(si + sj) & 0xff]);
284
0
}
285
286
static void
287
la_arc4random_buf(void *_buf, size_t n)
288
0
{
289
0
  uint8_t *buf = (uint8_t *)_buf;
290
0
  _ARC4_LOCK();
291
0
  arc4_stir_if_needed();
292
0
  while (n--) {
293
0
    if (--arc4_count <= 0)
294
0
      arc4_stir();
295
0
    buf[n] = arc4_getbyte();
296
0
  }
297
0
  _ARC4_UNLOCK();
298
0
}
299
300
#endif /* !HAVE_ARC4RANDOM_BUF */