Welcome to mirror list, hosted at ThFree Co, Russian Federation.

pal_random.c « System.Native « Unix « Native « libraries « src - github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: b824b2968f95cfed7d23672be4bc9185d0e24426 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>

#include "pal_config.h"
#include "pal_random.h"

/*

Generate random bytes. The generated bytes are not cryptographically strong.

*/

void SystemNative_GetNonCryptographicallySecureRandomBytes(uint8_t* buffer, int32_t bufferLength)
{
    assert(buffer != NULL);

#if HAVE_ARC4RANDOM_BUF
    arc4random_buf(buffer, (size_t)bufferLength);
#else
    long num = 0;
    static bool sInitializedMRand;

    // Fall back to the secure version
    SystemNative_GetCryptographicallySecureRandomBytes(buffer, bufferLength);

    if (!sInitializedMRand)
    {
        srand48(time(NULL));
        sInitializedMRand = true;
    }

    // always xor srand48 over the whole buffer to get some randomness
    // in case /dev/urandom is not really random

    for (int i = 0; i < bufferLength; i++)
    {
        if (i % 4 == 0)
        {
            num = lrand48();
        }

        *(buffer + i) ^= num;
        num >>= 8;
    }
#endif // HAVE_ARC4RANDOM_BUF
}

/*

Generate cryptographically strong random bytes.

Return 0 on success, -1 on failure.
*/
int32_t SystemNative_GetCryptographicallySecureRandomBytes(uint8_t* buffer, int32_t bufferLength)
{
    assert(buffer != NULL);

#ifdef __EMSCRIPTEN__
    extern int32_t dotnet_browser_entropy(uint8_t* buffer, int32_t bufferLength);
    static bool sMissingBrowserCrypto;
    if (!sMissingBrowserCrypto)
    {
        int32_t bff = dotnet_browser_entropy(buffer, bufferLength);
        if (bff == -1)
            sMissingBrowserCrypto = true;
        else
            return 0;
    }
#else

    static volatile int rand_des = -1;
    static bool sMissingDevURandom;

    if (!sMissingDevURandom)
    {
        if (rand_des == -1)
        {
            int fd;

            do
            {
#if HAVE_O_CLOEXEC
                fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
#else
                fd = open("/dev/urandom", O_RDONLY);
                fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif
            }
            while ((fd == -1) && (errno == EINTR));

            if (fd != -1)
            {
                int expected = -1;
                if (!__atomic_compare_exchange_n(&rand_des, &expected, fd, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
                {
                    // Another thread has already set the rand_des
                    close(fd);
                }
            }
            else if (errno == ENOENT)
            {
                sMissingDevURandom = true;
            }
        }

        if (rand_des != -1)
        {
            int32_t offset = 0;
            do
            {
                ssize_t n = read(rand_des, buffer + offset , (size_t)(bufferLength - offset));
                if (n == -1)
                {
                    if (errno == EINTR)
                    {
                        continue;
                    }
                    return -1;
                }

                offset += n;
            }
            while (offset != bufferLength);
            return 0;
        }
    }
#endif
    return -1;
}