sysrandom 1.0.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +34 -0
- data/.travis.yml +9 -0
- data/CHANGES.md +3 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +15 -0
- data/README.md +112 -0
- data/Rakefile +21 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ext/sysrandom/extconf.rb +4 -0
- data/ext/sysrandom/randombytes_sysrandom.c +275 -0
- data/ext/sysrandom/sysrandom_ext.c +77 -0
- data/lib/sysrandom/securerandom.rb +7 -0
- data/lib/sysrandom/version.rb +3 -0
- data/lib/sysrandom.rb +64 -0
- data/sysrandom.gemspec +26 -0
- metadata +62 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e24cd46b6417b143899bcec5491ded930fdff1b9
|
4
|
+
data.tar.gz: b4c37eded4ec30f2860538b3db047f3b12b5db78
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d91f8eb67cfa6c2a070fd06e7e15de5379e172d33d248eecce50e592fc8b1ebf1ab9d0bc22cfaef5380c34da9b8a8f979ee466406ece07270c158bead8976ee9
|
7
|
+
data.tar.gz: 708ede372c5493228dcdc63237c398a814df9b4ce47baac08dce981397346f945580cf29931c1dcd6cac2ff9afdb0c07b3d3ae208ae6e519499e3fe630ca40f6
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
AllCops:
|
2
|
+
DisplayCopNames: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# Style
|
6
|
+
#
|
7
|
+
|
8
|
+
LineLength:
|
9
|
+
Max: 128
|
10
|
+
|
11
|
+
Style/StringLiterals:
|
12
|
+
EnforcedStyle: double_quotes
|
13
|
+
|
14
|
+
Style/SpaceBeforeFirstArg:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Style/ConditionalAssignment:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
#
|
21
|
+
# Metrics
|
22
|
+
#
|
23
|
+
|
24
|
+
Metrics/MethodLength:
|
25
|
+
Max: 22
|
26
|
+
|
27
|
+
Metrics/AbcSize:
|
28
|
+
Max: 20
|
29
|
+
|
30
|
+
AllCops:
|
31
|
+
Include:
|
32
|
+
- '**/Rakefile'
|
33
|
+
Exclude:
|
34
|
+
- 'spec/**/*'
|
data/.travis.yml
ADDED
data/CHANGES.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Copyright (c) 2013-2016
|
2
|
+
Frank Denis <j at pureftpd dot org>
|
3
|
+
Tony Arcieri <bascule at gmail dot com>
|
4
|
+
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
# Sysrandom
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/sysrandom.svg)](https://rubygems.org/gems/sysrandom)
|
4
|
+
[![Build Status](https://secure.travis-ci.org/cryptosphere/sysrandom.svg?branch=master)](https://travis-ci.org/cryptosphere/sysrandom)
|
5
|
+
[![ISC licensed](https://img.shields.io/badge/license-ISC-blue.svg)](https://github.com/cryptosphere/sysrandom/blob/master/LICENSE.txt)
|
6
|
+
|
7
|
+
Secure random number generation for Ruby using system RNG facilities e.g. `/dev/urandom`, `getrandom(2)`
|
8
|
+
|
9
|
+
## Description
|
10
|
+
|
11
|
+
[Concerns have been raised][concerns] about the current implementation of Ruby's built-in
|
12
|
+
`SecureRandom` functionality, as it presently leverages the poorly reputed OpenSSL RNG.
|
13
|
+
|
14
|
+
In cryptography circles, [the prevailing advice is to use OS RNG functionality][/dev/urandom],
|
15
|
+
namely `/dev/urandom` or equivalent calls which use an OS-level CSPRNG to
|
16
|
+
produce random numbers.
|
17
|
+
|
18
|
+
This gem provides an easy-to-install repackaging of the `randombytes`
|
19
|
+
functionality from [libsodium] for the purpose of generating secure random
|
20
|
+
numbers trustworthy for use in cryptographic contexts, such as generating
|
21
|
+
cryptographic keys, initialization vectors, or nonces.
|
22
|
+
|
23
|
+
The following random number generators are utilized:
|
24
|
+
|
25
|
+
| OS | RNG |
|
26
|
+
|---------|-------------------------------------------------------------------|
|
27
|
+
| Linux | [getrandom(2)] if available, otherwise [/dev/urandom] |
|
28
|
+
| Windows | [RtlGenRandom] |
|
29
|
+
| OpenBSD | [arc4random(3)] with ChaCha20 CSPRNG (not RC4) |
|
30
|
+
| JRuby | [SecureRandom.getInstanceStrong] if available, otherwise SHA1PRNG |
|
31
|
+
| Others | [/dev/urandom] |
|
32
|
+
|
33
|
+
[concerns]: https://bugs.ruby-lang.org/issues/9569
|
34
|
+
[libsodium]: https://github.com/jedisct1/libsodium
|
35
|
+
[getrandom(2)]: http://man7.org/linux/man-pages/man2/getrandom.2.html
|
36
|
+
[/dev/urandom]: http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/
|
37
|
+
[RtlGenRandom]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694(v=vs.85).aspx
|
38
|
+
[arc4random(3)]: http://man.openbsd.org/arc4random.3
|
39
|
+
[SecureRandom.getInstanceStrong]: https://docs.oracle.com/javase/8/docs/api/java/security/SecureRandom.html#getInstanceStrong--
|
40
|
+
|
41
|
+
## Supported Platforms
|
42
|
+
|
43
|
+
Sysrandom is tested on the following Ruby implementations:
|
44
|
+
|
45
|
+
* Ruby (MRI) 2.0, 2.1, 2.2, 2.3
|
46
|
+
* JRuby 9.1.1.0
|
47
|
+
|
48
|
+
## Installation
|
49
|
+
|
50
|
+
Add this line to your application's Gemfile:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
gem 'sysrandom'
|
54
|
+
```
|
55
|
+
|
56
|
+
And then execute:
|
57
|
+
|
58
|
+
$ bundle
|
59
|
+
|
60
|
+
Or install it yourself as:
|
61
|
+
|
62
|
+
$ gem install sysrandom
|
63
|
+
|
64
|
+
## Usage
|
65
|
+
|
66
|
+
`Sysrandom` aims to be API-compatible with Ruby's built-in `SecureRandom` class,
|
67
|
+
but always prefers OS-level RNG wherever it's available:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
>> Sysrandom.random_number(42)
|
71
|
+
=> 15
|
72
|
+
>> Sysrandom.random_bytes(32)
|
73
|
+
=> "\xD6J\xB3\xD2\x8B\x7F*9D\xB7\xF9\xEA\xE2\\\xAAH\tV#\xEC\x84\xE3E\r\x97\xB9\b\xFCH\x17\xA0\v"
|
74
|
+
>> Sysrandom.base64(32)
|
75
|
+
=> "WXPkxfAuLRpnI6Z4zFb4E+MIenx6w6vKhe01+rMPuIQ="
|
76
|
+
>> Sysrandom.urlsafe_base64(32)
|
77
|
+
=> "37rsMfR4X8g7Bb-uDJEekRHnB3r_7nO03cv52ilaWqE="
|
78
|
+
>> Sysrandom.hex(32)
|
79
|
+
=> "c950496ce200abf7d18eb1414e9206c6335f971a37d0394114f56439b59831ba"
|
80
|
+
>> Sysrandom.uuid
|
81
|
+
=> "391c6f52-8017-4838-9790-131a9b979c63"
|
82
|
+
```
|
83
|
+
|
84
|
+
* [SecureRandom API docs](http://ruby-doc.org/stdlib-2.0.0/libdoc/securerandom/rdoc/SecureRandom.html)
|
85
|
+
|
86
|
+
## Patching SecureRandom with Sysrandom
|
87
|
+
|
88
|
+
Since Sysrandom is SecureRandom-compatible, it can be patched in-place of
|
89
|
+
SecureRandom if you prefer its RNG behavior.
|
90
|
+
|
91
|
+
To do this, require `sysrandom/securerandom`:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
>> SecureRandom
|
95
|
+
=> SecureRandom
|
96
|
+
>> require "sysrandom/securerandom"
|
97
|
+
=> true
|
98
|
+
>> SecureRandom
|
99
|
+
=> Sysrandom
|
100
|
+
>> SecureRandom.hex(32)
|
101
|
+
=> "d1bbe8c1ab78fc2fe514c5623d913a27ffd2dcdc9e002f3b358bb01a996962f1"
|
102
|
+
```
|
103
|
+
|
104
|
+
## Contributing
|
105
|
+
|
106
|
+
* Fork this repository on Github
|
107
|
+
* Make your changes and send a pull request
|
108
|
+
* If your changes look good, we'll merge them
|
109
|
+
|
110
|
+
## Copyright
|
111
|
+
|
112
|
+
Copyright (c) 2013-2016 Frank Denis, Tony Arcieri. See LICENSE.txt for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
require "rubocop/rake_task"
|
4
|
+
require "rake/clean"
|
5
|
+
|
6
|
+
unless defined? JRUBY_VERSION
|
7
|
+
require "rake/extensiontask"
|
8
|
+
Rake::ExtensionTask.new("sysrandom_ext") do |ext|
|
9
|
+
ext.ext_dir = "ext/sysrandom"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
RSpec::Core::RakeTask.new(:spec)
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
|
16
|
+
default_tasks = %w(spec rubocop)
|
17
|
+
default_tasks.unshift("compile") unless defined?(JRUBY_VERSION)
|
18
|
+
|
19
|
+
task default: default_tasks
|
20
|
+
|
21
|
+
CLEAN.include "**/*.o", "**/*.so", "**/*.bundle", "pkg", "tmp"
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "sysrandom"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,275 @@
|
|
1
|
+
/*
|
2
|
+
* __randombytes_sysrandom.c: adapted from libsodium
|
3
|
+
* Copyright (c) 2013-2016 Frank Denis <j at pureftpd dot org>
|
4
|
+
* https://github.com/jedisct1/libsodium
|
5
|
+
*/
|
6
|
+
|
7
|
+
#include <stdlib.h>
|
8
|
+
#include <sys/types.h>
|
9
|
+
#ifndef _WIN32
|
10
|
+
# include <sys/stat.h>
|
11
|
+
# include <sys/time.h>
|
12
|
+
#endif
|
13
|
+
#ifdef __linux__
|
14
|
+
# include <sys/syscall.h>
|
15
|
+
#endif
|
16
|
+
|
17
|
+
#include <assert.h>
|
18
|
+
#include <errno.h>
|
19
|
+
#include <fcntl.h>
|
20
|
+
#include <limits.h>
|
21
|
+
#include <stdint.h>
|
22
|
+
#include <string.h>
|
23
|
+
#ifndef _WIN32
|
24
|
+
# include <unistd.h>
|
25
|
+
#endif
|
26
|
+
|
27
|
+
#ifdef _WIN32
|
28
|
+
# include <windows.h>
|
29
|
+
# define RtlGenRandom SystemFunction036
|
30
|
+
# if defined(__cplusplus)
|
31
|
+
extern "C"
|
32
|
+
# endif
|
33
|
+
BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
|
34
|
+
# pragma comment(lib, "advapi32.lib")
|
35
|
+
#endif
|
36
|
+
|
37
|
+
#if defined(__OpenBSD__) || defined(__CloudABI__)
|
38
|
+
# define HAVE_SAFE_ARC4RANDOM 1
|
39
|
+
#endif
|
40
|
+
|
41
|
+
#ifndef SSIZE_MAX
|
42
|
+
# define SSIZE_MAX (SIZE_MAX / 2 - 1)
|
43
|
+
#endif
|
44
|
+
|
45
|
+
#ifdef HAVE_SAFE_ARC4RANDOM
|
46
|
+
|
47
|
+
uint32_t
|
48
|
+
__randombytes_sysrandom(void)
|
49
|
+
{
|
50
|
+
return arc4random();
|
51
|
+
}
|
52
|
+
|
53
|
+
static void
|
54
|
+
__randombytes_sysrandom_stir(void)
|
55
|
+
{
|
56
|
+
}
|
57
|
+
|
58
|
+
void
|
59
|
+
__randombytes_sysrandom_buf(void * const buf, const size_t size)
|
60
|
+
{
|
61
|
+
return arc4random_buf(buf, size);
|
62
|
+
}
|
63
|
+
|
64
|
+
#else /* __OpenBSD__ */
|
65
|
+
|
66
|
+
typedef struct SysRandom_ {
|
67
|
+
int random_data_source_fd;
|
68
|
+
int initialized;
|
69
|
+
int getrandom_available;
|
70
|
+
} SysRandom;
|
71
|
+
|
72
|
+
static SysRandom stream = {
|
73
|
+
.random_data_source_fd = -1,
|
74
|
+
.initialized = 0,
|
75
|
+
.getrandom_available = 0
|
76
|
+
};
|
77
|
+
|
78
|
+
#ifndef _WIN32
|
79
|
+
static ssize_t
|
80
|
+
safe_read(const int fd, void * const buf_, size_t size)
|
81
|
+
{
|
82
|
+
unsigned char *buf = (unsigned char *) buf_;
|
83
|
+
ssize_t readnb;
|
84
|
+
|
85
|
+
assert(size > (size_t) 0U);
|
86
|
+
assert(size <= SSIZE_MAX);
|
87
|
+
do {
|
88
|
+
while ((readnb = read(fd, buf, size)) < (ssize_t) 0 &&
|
89
|
+
(errno == EINTR || errno == EAGAIN)); /* LCOV_EXCL_LINE */
|
90
|
+
if (readnb < (ssize_t) 0) {
|
91
|
+
return readnb; /* LCOV_EXCL_LINE */
|
92
|
+
}
|
93
|
+
if (readnb == (ssize_t) 0) {
|
94
|
+
break; /* LCOV_EXCL_LINE */
|
95
|
+
}
|
96
|
+
size -= (size_t) readnb;
|
97
|
+
buf += readnb;
|
98
|
+
} while (size > (ssize_t) 0);
|
99
|
+
|
100
|
+
return (ssize_t) (buf - (unsigned char *) buf_);
|
101
|
+
}
|
102
|
+
#endif
|
103
|
+
|
104
|
+
#ifndef _WIN32
|
105
|
+
static int
|
106
|
+
__randombytes_sysrandom_random_dev_open(void)
|
107
|
+
{
|
108
|
+
/* LCOV_EXCL_START */
|
109
|
+
struct stat st;
|
110
|
+
static const char *devices[] = {
|
111
|
+
# ifndef USE_BLOCKING_RANDOM
|
112
|
+
"/dev/urandom",
|
113
|
+
# endif
|
114
|
+
"/dev/random", NULL
|
115
|
+
};
|
116
|
+
const char ** device = devices;
|
117
|
+
int fd;
|
118
|
+
|
119
|
+
do {
|
120
|
+
fd = open(*device, O_RDONLY);
|
121
|
+
if (fd != -1) {
|
122
|
+
if (fstat(fd, &st) == 0 &&
|
123
|
+
# ifdef __COMPCERT__
|
124
|
+
1
|
125
|
+
# elif defined(S_ISNAM)
|
126
|
+
(S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode))
|
127
|
+
# else
|
128
|
+
S_ISCHR(st.st_mode)
|
129
|
+
# endif
|
130
|
+
) {
|
131
|
+
# if defined(F_SETFD) && defined(FD_CLOEXEC)
|
132
|
+
(void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
|
133
|
+
# endif
|
134
|
+
return fd;
|
135
|
+
}
|
136
|
+
(void) close(fd);
|
137
|
+
} else if (errno == EINTR) {
|
138
|
+
continue;
|
139
|
+
}
|
140
|
+
device++;
|
141
|
+
} while (*device != NULL);
|
142
|
+
|
143
|
+
errno = EIO;
|
144
|
+
return -1;
|
145
|
+
/* LCOV_EXCL_STOP */
|
146
|
+
}
|
147
|
+
|
148
|
+
# ifdef SYS_getrandom
|
149
|
+
static int
|
150
|
+
_randombytes_linux_getrandom(void * const buf, const size_t size)
|
151
|
+
{
|
152
|
+
int readnb;
|
153
|
+
|
154
|
+
assert(size <= 256U);
|
155
|
+
do {
|
156
|
+
readnb = syscall(SYS_getrandom, buf, (int) size, 0);
|
157
|
+
} while (readnb < 0 && (errno == EINTR || errno == EAGAIN));
|
158
|
+
|
159
|
+
return (readnb == (int) size) - 1;
|
160
|
+
}
|
161
|
+
|
162
|
+
static int
|
163
|
+
randombytes_linux_getrandom(void * const buf_, size_t size)
|
164
|
+
{
|
165
|
+
unsigned char *buf = (unsigned char *) buf_;
|
166
|
+
size_t chunk_size = 256U;
|
167
|
+
|
168
|
+
do {
|
169
|
+
if (size < chunk_size) {
|
170
|
+
chunk_size = size;
|
171
|
+
assert(chunk_size > (size_t) 0U);
|
172
|
+
}
|
173
|
+
if (_randombytes_linux_getrandom(buf, chunk_size) != 0) {
|
174
|
+
return -1;
|
175
|
+
}
|
176
|
+
size -= chunk_size;
|
177
|
+
buf += chunk_size;
|
178
|
+
} while (size > (size_t) 0U);
|
179
|
+
|
180
|
+
return 0;
|
181
|
+
}
|
182
|
+
# endif
|
183
|
+
|
184
|
+
static void
|
185
|
+
__randombytes_sysrandom_init(void)
|
186
|
+
{
|
187
|
+
const int errno_save = errno;
|
188
|
+
|
189
|
+
# ifdef SYS_getrandom
|
190
|
+
{
|
191
|
+
unsigned char fodder[16];
|
192
|
+
|
193
|
+
if (randombytes_linux_getrandom(fodder, sizeof fodder) == 0) {
|
194
|
+
stream.getrandom_available = 1;
|
195
|
+
errno = errno_save;
|
196
|
+
return;
|
197
|
+
}
|
198
|
+
stream.getrandom_available = 0;
|
199
|
+
}
|
200
|
+
# endif
|
201
|
+
|
202
|
+
if ((stream.random_data_source_fd =
|
203
|
+
__randombytes_sysrandom_random_dev_open()) == -1) {
|
204
|
+
abort(); /* LCOV_EXCL_LINE */
|
205
|
+
}
|
206
|
+
errno = errno_save;
|
207
|
+
}
|
208
|
+
|
209
|
+
#else /* _WIN32 */
|
210
|
+
|
211
|
+
static void
|
212
|
+
__randombytes_sysrandom_init(void)
|
213
|
+
{
|
214
|
+
}
|
215
|
+
#endif
|
216
|
+
|
217
|
+
static void
|
218
|
+
__randombytes_sysrandom_stir(void)
|
219
|
+
{
|
220
|
+
if (stream.initialized == 0) {
|
221
|
+
__randombytes_sysrandom_init();
|
222
|
+
stream.initialized = 1;
|
223
|
+
}
|
224
|
+
}
|
225
|
+
|
226
|
+
static void
|
227
|
+
__randombytes_sysrandom_stir_if_needed(void)
|
228
|
+
{
|
229
|
+
if (stream.initialized == 0) {
|
230
|
+
__randombytes_sysrandom_stir();
|
231
|
+
}
|
232
|
+
}
|
233
|
+
|
234
|
+
void
|
235
|
+
__randombytes_sysrandom_buf(void * const buf, const size_t size)
|
236
|
+
{
|
237
|
+
__randombytes_sysrandom_stir_if_needed();
|
238
|
+
#ifdef ULONG_LONG_MAX
|
239
|
+
/* coverity[result_independent_of_operands] */
|
240
|
+
assert(size <= ULONG_LONG_MAX);
|
241
|
+
#endif
|
242
|
+
#ifndef _WIN32
|
243
|
+
# ifdef SYS_getrandom
|
244
|
+
if (stream.getrandom_available != 0) {
|
245
|
+
if (randombytes_linux_getrandom(buf, size) != 0) {
|
246
|
+
abort();
|
247
|
+
}
|
248
|
+
return;
|
249
|
+
}
|
250
|
+
# endif
|
251
|
+
if (stream.random_data_source_fd == -1 ||
|
252
|
+
safe_read(stream.random_data_source_fd, buf, size) != (ssize_t) size) {
|
253
|
+
abort(); /* LCOV_EXCL_LINE */
|
254
|
+
}
|
255
|
+
#else
|
256
|
+
if (size > (size_t) 0xffffffff) {
|
257
|
+
abort(); /* LCOV_EXCL_LINE */
|
258
|
+
}
|
259
|
+
if (! RtlGenRandom((PVOID) buf, (ULONG) size)) {
|
260
|
+
abort(); /* LCOV_EXCL_LINE */
|
261
|
+
}
|
262
|
+
#endif
|
263
|
+
}
|
264
|
+
|
265
|
+
uint32_t
|
266
|
+
__randombytes_sysrandom(void)
|
267
|
+
{
|
268
|
+
uint32_t r;
|
269
|
+
|
270
|
+
__randombytes_sysrandom_buf(&r, sizeof r);
|
271
|
+
|
272
|
+
return r;
|
273
|
+
}
|
274
|
+
|
275
|
+
#endif /* __OpenBSD__ */
|
@@ -0,0 +1,77 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
|
3
|
+
/* How many bytes to generate by default, matching SecureRandom
|
4
|
+
* Why SecureRandom has a default size argument is beyond me */
|
5
|
+
#define DEFAULT_N_BYTES 16
|
6
|
+
|
7
|
+
static VALUE mSysrandom = Qnil;
|
8
|
+
|
9
|
+
static VALUE Sysrandom_random_uint32(VALUE self);
|
10
|
+
static VALUE Sysrandom_random_bytes(int argc, VALUE *argv, VALUE self);
|
11
|
+
|
12
|
+
/* From randombytes_sysrandom.c */
|
13
|
+
uint32_t __randombytes_sysrandom(void);
|
14
|
+
void __randombytes_sysrandom_buf(void * const buf, const size_t size);
|
15
|
+
|
16
|
+
void Init_sysrandom_ext()
|
17
|
+
{
|
18
|
+
mSysrandom = rb_define_module("Sysrandom");
|
19
|
+
|
20
|
+
rb_define_singleton_method(mSysrandom, "__random_uint32", Sysrandom_random_uint32, 0);
|
21
|
+
rb_define_method(mSysrandom, "__random_uint32", Sysrandom_random_uint32, 0);
|
22
|
+
|
23
|
+
rb_define_singleton_method(mSysrandom, "random_bytes", Sysrandom_random_bytes, -1);
|
24
|
+
rb_define_method(mSysrandom, "random_bytes", Sysrandom_random_bytes, -1);
|
25
|
+
}
|
26
|
+
|
27
|
+
/**
|
28
|
+
* call-seq:
|
29
|
+
* Sysrandom#__random_uint32 -> Fixnum
|
30
|
+
*
|
31
|
+
* Generates a random unsigned 32-bit integer using the OS CSPRNG
|
32
|
+
*
|
33
|
+
*/
|
34
|
+
static VALUE
|
35
|
+
Sysrandom_random_uint32(VALUE self)
|
36
|
+
{
|
37
|
+
return UINT2NUM(__randombytes_sysrandom());
|
38
|
+
}
|
39
|
+
|
40
|
+
/**
|
41
|
+
* call-seq:
|
42
|
+
* Sysrandom#random_bytes(n=nil) -> String
|
43
|
+
*
|
44
|
+
* ::random_bytes generates a random binary string via the OS CSPRNG.
|
45
|
+
*
|
46
|
+
* The argument n specifies how long the resulting string should be.
|
47
|
+
*
|
48
|
+
* For compatibility with SecureRandom, if n is not specified, 16 is assumed.
|
49
|
+
*
|
50
|
+
* The resulting string may contain any byte (i.e. "x00" - "xff")
|
51
|
+
*
|
52
|
+
*/
|
53
|
+
static VALUE
|
54
|
+
Sysrandom_random_bytes(int argc, VALUE * argv, VALUE self)
|
55
|
+
{
|
56
|
+
VALUE n_obj, str;
|
57
|
+
int n;
|
58
|
+
|
59
|
+
if (rb_scan_args(argc, argv, "01", &n_obj) == 1) {
|
60
|
+
n = NUM2INT(n_obj);
|
61
|
+
|
62
|
+
if(n < 0) {
|
63
|
+
rb_raise(rb_eArgError, "negative string size");
|
64
|
+
}
|
65
|
+
} else {
|
66
|
+
n = DEFAULT_N_BYTES;
|
67
|
+
}
|
68
|
+
|
69
|
+
if(n > 0) {
|
70
|
+
str = rb_str_new(0, n);
|
71
|
+
__randombytes_sysrandom_buf(RSTRING_PTR(str), n);
|
72
|
+
} else {
|
73
|
+
str = rb_str_new2("");
|
74
|
+
}
|
75
|
+
|
76
|
+
return str;
|
77
|
+
}
|
data/lib/sysrandom.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require "sysrandom/version"
|
2
|
+
|
3
|
+
require "base64"
|
4
|
+
|
5
|
+
# Secure random number generation using system RNG facilities
|
6
|
+
module Sysrandom
|
7
|
+
module_function
|
8
|
+
|
9
|
+
# For some reason SecureRandom defaults to 16 bytes
|
10
|
+
DEFAULT_LENGTH = 16
|
11
|
+
|
12
|
+
if defined?(JRUBY_VERSION)
|
13
|
+
require "java"
|
14
|
+
|
15
|
+
if java.security.SecureRandom.respond_to?(:getInstanceStrong)
|
16
|
+
@_java_secure_random = java.security.SecureRandom.getInstanceStrong
|
17
|
+
else
|
18
|
+
@_java_secure_random = java.security.SecureRandom.getInstance("SHA1PRNG")
|
19
|
+
end
|
20
|
+
|
21
|
+
# Random uint32, used by random_number. The C extension provides an equivalent method
|
22
|
+
def __random_uint32
|
23
|
+
@_java_secure_random.nextLong & 0xFFFFFFFF
|
24
|
+
end
|
25
|
+
|
26
|
+
def random_bytes(n = DEFAULT_LENGTH)
|
27
|
+
raise ArgumentError, "negative string size" if n < 0
|
28
|
+
|
29
|
+
bytes = Java::byte[n].new
|
30
|
+
@_java_secure_random.nextBytes(bytes)
|
31
|
+
String.from_java_bytes(bytes)
|
32
|
+
end
|
33
|
+
else
|
34
|
+
require "sysrandom_ext"
|
35
|
+
end
|
36
|
+
|
37
|
+
def random_number(n = 0)
|
38
|
+
result = __random_uint32 / (2**32).to_f
|
39
|
+
|
40
|
+
if n <= 0
|
41
|
+
result
|
42
|
+
else
|
43
|
+
result *= n
|
44
|
+
n.is_a?(Fixnum) ? result.floor : result
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def base64(n = DEFAULT_LENGTH)
|
49
|
+
Base64.encode64(random_bytes(n)).chomp
|
50
|
+
end
|
51
|
+
|
52
|
+
def urlsafe_base64(n = DEFAULT_LENGTH)
|
53
|
+
Base64.urlsafe_encode64(random_bytes(n)).chomp
|
54
|
+
end
|
55
|
+
|
56
|
+
def hex(n = DEFAULT_LENGTH)
|
57
|
+
random_bytes(n).unpack("h*").first
|
58
|
+
end
|
59
|
+
|
60
|
+
def uuid
|
61
|
+
values = SecureRandom.hex(16).match(/\A(.{8})(.{4})(.)(.{3})(.)(.{3})(.{12})\z/)
|
62
|
+
"#{values[1]}-#{values[2]}-4#{values[4]}-#{'89ab'[values[5].ord % 4]}#{values[6]}-#{values[7]}"
|
63
|
+
end
|
64
|
+
end
|
data/sysrandom.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "sysrandom/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "sysrandom"
|
7
|
+
spec.version = Sysrandom::VERSION
|
8
|
+
spec.authors = ["Tony Arcieri"]
|
9
|
+
spec.email = ["bascule@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Secure random number generation using system RNG facilities"
|
12
|
+
spec.description = "Sysrandom generates secure random numbers using /dev/urandom, getrandom(), etc"
|
13
|
+
spec.homepage = "https://github.com/cryptosphere/sysrandom"
|
14
|
+
spec.licenses = ["ISC"]
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
if defined? JRUBY_VERSION
|
22
|
+
spec.platform = "java"
|
23
|
+
else
|
24
|
+
spec.extensions = ["ext/sysrandom/extconf.rb"]
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sysrandom
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: java
|
6
|
+
authors:
|
7
|
+
- Tony Arcieri
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-05-29 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Sysrandom generates secure random numbers using /dev/urandom, getrandom(), etc
|
14
|
+
email:
|
15
|
+
- bascule@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".gitignore"
|
21
|
+
- ".rspec"
|
22
|
+
- ".rubocop.yml"
|
23
|
+
- ".travis.yml"
|
24
|
+
- CHANGES.md
|
25
|
+
- Gemfile
|
26
|
+
- LICENSE.txt
|
27
|
+
- README.md
|
28
|
+
- Rakefile
|
29
|
+
- bin/console
|
30
|
+
- bin/setup
|
31
|
+
- ext/sysrandom/extconf.rb
|
32
|
+
- ext/sysrandom/randombytes_sysrandom.c
|
33
|
+
- ext/sysrandom/sysrandom_ext.c
|
34
|
+
- lib/sysrandom.rb
|
35
|
+
- lib/sysrandom/securerandom.rb
|
36
|
+
- lib/sysrandom/version.rb
|
37
|
+
- sysrandom.gemspec
|
38
|
+
homepage: https://github.com/cryptosphere/sysrandom
|
39
|
+
licenses:
|
40
|
+
- ISC
|
41
|
+
metadata: {}
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
requirements: []
|
57
|
+
rubyforge_project:
|
58
|
+
rubygems_version: 2.4.8
|
59
|
+
signing_key:
|
60
|
+
specification_version: 4
|
61
|
+
summary: Secure random number generation using system RNG facilities
|
62
|
+
test_files: []
|