dualcone 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +116 -0
- data/ext/dualcone/dualcone.c +288 -0
- data/ext/dualcone/dualcone.h +49 -0
- data/ext/dualcone/extconf.rb +36 -0
- data/lib/dualcone.rb +4 -0
- data/lib/dualcone/version.rb +5 -0
- data/vendor/libhydrogen/LICENSE +18 -0
- data/vendor/libhydrogen/Makefile +61 -0
- data/vendor/libhydrogen/README.md +36 -0
- data/vendor/libhydrogen/hydrogen.c +18 -0
- data/vendor/libhydrogen/hydrogen.h +331 -0
- data/vendor/libhydrogen/impl/common.h +321 -0
- data/vendor/libhydrogen/impl/core.h +223 -0
- data/vendor/libhydrogen/impl/gimli-core.h +25 -0
- data/vendor/libhydrogen/impl/gimli-core/portable.h +39 -0
- data/vendor/libhydrogen/impl/gimli-core/sse2.h +100 -0
- data/vendor/libhydrogen/impl/hash.h +140 -0
- data/vendor/libhydrogen/impl/hydrogen_p.h +83 -0
- data/vendor/libhydrogen/impl/kdf.h +20 -0
- data/vendor/libhydrogen/impl/kx.h +535 -0
- data/vendor/libhydrogen/impl/pwhash.h +281 -0
- data/vendor/libhydrogen/impl/random.h +465 -0
- data/vendor/libhydrogen/impl/secretbox.h +236 -0
- data/vendor/libhydrogen/impl/sign.h +207 -0
- data/vendor/libhydrogen/impl/x25519.h +384 -0
- metadata +186 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b2cefd1451fcbb7e091ab48f74b5cbca1eb8a585e3cc28edb34ff5a6f04beaac
|
4
|
+
data.tar.gz: 5ba6021faa19db6e737f669459f86c464fc6878bfad7250bead60004f0f60c60
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5b1a2bc0687e734ec4b7a103825a2b698f15ae01a3d8efca9a0fd27b6b8d41e42b66b103c93770b7fc2df46ce5deccdce81723eb0cb406578ae8a52b6ebf5c3e
|
7
|
+
data.tar.gz: 98f13c8cc8c35459f34698d84f119fb7e5550128c76af207151ba3438b6ac056f5c199b17a54c8f95848e427ec3dcd71e05c5c58ba84e5f1ef4b486e95f8ad68
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Tom Richards
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
# Dualcone
|
2
|
+
|
3
|
+
[![CircleCI](https://circleci.com/gh/t-richards/dualcone.svg?style=svg)](https://circleci.com/gh/t-richards/dualcone)
|
4
|
+
|
5
|
+
Dualcone is a Ruby source code protection system. Dualcone uses symmetric encryption to protect your source code.
|
6
|
+
|
7
|
+
Dualcone is a self-contained gem. It brings along its own copy of the lightweight cryptographic library, [libhydrogen][libhydrogen].
|
8
|
+
|
9
|
+
Dualcone supports GNU + Linux and other Unix-like operating systems. Windows is not supported.
|
10
|
+
|
11
|
+
## Roadmap
|
12
|
+
|
13
|
+
### Part 1
|
14
|
+
- [x] Key generation: `Dualcone.generate_key`
|
15
|
+
- [x] Encrypted code running: `Dualcone.run(code)`
|
16
|
+
- [x] Encrypted code generation: `Dualcone.encrypt(path)`
|
17
|
+
- [x] Specs passing
|
18
|
+
|
19
|
+
### Part 2
|
20
|
+
- [x] Runnable trivial ruby script
|
21
|
+
- [ ] Runnable non-trivial ruby script
|
22
|
+
- [ ] Runnable sinatra app
|
23
|
+
- [ ] Runnable rails app
|
24
|
+
|
25
|
+
## Installation
|
26
|
+
|
27
|
+
Add this gem to your application's Gemfile:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
gem 'dualcone'
|
31
|
+
```
|
32
|
+
|
33
|
+
And then execute:
|
34
|
+
|
35
|
+
```bash
|
36
|
+
$ bundle install
|
37
|
+
```
|
38
|
+
|
39
|
+
Or install it yourself as:
|
40
|
+
|
41
|
+
```bash
|
42
|
+
$ gem install dualcone
|
43
|
+
```
|
44
|
+
|
45
|
+
You need to have a C compiler and `make` installed on your system to be able to build this gem's native code and the included version of `libhydrogen`.
|
46
|
+
|
47
|
+
## Usage
|
48
|
+
|
49
|
+
1. Generate a secret encryption key.
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
require 'dualcone'
|
53
|
+
Dualcone.generate_key
|
54
|
+
=> "764888c92f3059c88524225b622cd178856877cf3537230a9d7f5b5b6d8850c5"
|
55
|
+
```
|
56
|
+
|
57
|
+
2. Place your encryption key in the `DUALCONE_HEX_KEY` environment variable:
|
58
|
+
|
59
|
+
```bash
|
60
|
+
$ export DUALCONE_HEX_KEY="8c8f91f84d8e554dc03277ce2f038af95cd932e2b65011969e77d3ac18d7bdd9"
|
61
|
+
```
|
62
|
+
|
63
|
+
This environment variable is required for both encrypting files as well as running already-encrypted files.
|
64
|
+
|
65
|
+
3. Encrypt your Ruby source code file(s).
|
66
|
+
|
67
|
+
:warning: Your source code file will be modified in-place. This is a one-way operation! :warning:
|
68
|
+
|
69
|
+
For example, let's say we have a file named `hello.rb` with the following contents:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
puts 'Hello, world!'
|
73
|
+
```
|
74
|
+
|
75
|
+
You can encrypt this file using `Dualcone.encrypt(path)`
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
Dualcone.encrypt('hello.rb')
|
79
|
+
```
|
80
|
+
|
81
|
+
The entire contents of the file `hello.rb` will be replaced with a call to `Dualcone.run(code)`:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
require 'dualcone'
|
85
|
+
Dualcone.run('7f1a1b6a047aee2403e415044b72f2ac2997cef689960df46afdfe6d7c657e18dbae1bea3bbe33ae9157cb2f7b22f34db69b2eb41e05aa512151')
|
86
|
+
```
|
87
|
+
|
88
|
+
4. Finally, test your encrypted code by running it.
|
89
|
+
|
90
|
+
```bash
|
91
|
+
$ ruby hello.rb
|
92
|
+
```
|
93
|
+
|
94
|
+
## Development
|
95
|
+
|
96
|
+
1. `git clone git@github.com:t-richards/dualcone.git` to clone the repo.
|
97
|
+
2. `bin/setup` to install dependencies and fetch git submodules.
|
98
|
+
3. `bin/rake compile` to build the gem's native extensions.
|
99
|
+
4. `bin/rspec` to run the tests.
|
100
|
+
5. `bin/rubocop` to check code style.
|
101
|
+
|
102
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
103
|
+
|
104
|
+
To install this gem onto your local machine, run `bin/rake install`. To release a new version, update the version number in `version.rb`, and then run `bin/rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org][rubygems].
|
105
|
+
|
106
|
+
## Contributing
|
107
|
+
|
108
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/t-richards/dualcone.
|
109
|
+
|
110
|
+
## License
|
111
|
+
|
112
|
+
The gem is available as open source under the terms of the [MIT License][mit-license].
|
113
|
+
|
114
|
+
[libhydrogen]: https://github.com/jedisct1/libhydrogen
|
115
|
+
[mit-license]: https://opensource.org/licenses/MIT
|
116
|
+
[rubygems]: https://rubygems.org
|
@@ -0,0 +1,288 @@
|
|
1
|
+
#include "dualcone.h"
|
2
|
+
|
3
|
+
VALUE rb_mDualcone;
|
4
|
+
|
5
|
+
void rb_dualcone_cleanup(DualconeContext *ctx) {
|
6
|
+
if (ctx->input_path != NULL) {
|
7
|
+
free(ctx->input_path);
|
8
|
+
}
|
9
|
+
|
10
|
+
if (ctx->output_path != NULL) {
|
11
|
+
unlink(ctx->output_path); /* temporary file */
|
12
|
+
hydro_memzero(ctx->output_path, PATH_MAX);
|
13
|
+
free(ctx->output_path);
|
14
|
+
}
|
15
|
+
|
16
|
+
if (ctx->plaintext != NULL) {
|
17
|
+
hydro_memzero(ctx->plaintext, ctx->plaintext_len);
|
18
|
+
free(ctx->plaintext);
|
19
|
+
}
|
20
|
+
|
21
|
+
if (ctx->ciphertext_hex != NULL) {
|
22
|
+
hydro_memzero(ctx->ciphertext_hex, ctx->ciphertext_hex_len);
|
23
|
+
free(ctx->ciphertext_hex);
|
24
|
+
}
|
25
|
+
|
26
|
+
if (ctx->ciphertext != NULL) {
|
27
|
+
hydro_memzero(ctx->ciphertext, ctx->ciphertext_len);
|
28
|
+
free(ctx->ciphertext);
|
29
|
+
}
|
30
|
+
|
31
|
+
hydro_memzero(ctx, sizeof(DualconeContext));
|
32
|
+
}
|
33
|
+
|
34
|
+
void rb_dualcone_get_key(DualconeContext *ctx) {
|
35
|
+
int result = 0;
|
36
|
+
int errno_sv = 0;
|
37
|
+
|
38
|
+
/* Hex-encoded encryption key from environment */
|
39
|
+
char *hex_key = getenv(DUALCONE_HEX_KEY);
|
40
|
+
if (hex_key == NULL) {
|
41
|
+
rb_dualcone_cleanup(ctx);
|
42
|
+
rb_raise(rb_eKeyError, "environment variable not found: " DUALCONE_HEX_KEY);
|
43
|
+
}
|
44
|
+
|
45
|
+
/* Convert encryption key (hex encoded) to binary */
|
46
|
+
result = hydro_hex2bin(ctx->binary_key, hydro_secretbox_KEYBYTES, hex_key, strlen(hex_key), NULL, NULL);
|
47
|
+
if (result == -1) {
|
48
|
+
errno_sv = errno;
|
49
|
+
rb_dualcone_cleanup(ctx);
|
50
|
+
rb_raise(rb_eFatal, "unable to hex-decode encryption key: %s", strerror(errno_sv));
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
VALUE rb_dualcone_run(VALUE _self, VALUE code) {
|
55
|
+
int result = 0;
|
56
|
+
int errno_sv = 0;
|
57
|
+
|
58
|
+
/* Check args */
|
59
|
+
rb_check_type(code, T_STRING);
|
60
|
+
|
61
|
+
/* Dualcone private memory allocations */
|
62
|
+
DualconeContext ctx = {0};
|
63
|
+
rb_dualcone_get_key(&ctx);
|
64
|
+
|
65
|
+
/* Encrypted ruby code (hex-encoded) */
|
66
|
+
char *hex_code = StringValuePtr(code);
|
67
|
+
long hex_code_len = RSTRING_LEN(code);
|
68
|
+
|
69
|
+
/* Check message length */
|
70
|
+
if (hex_code_len < DUALCONE_MIN_HEX_LEN) {
|
71
|
+
rb_dualcone_cleanup(&ctx);
|
72
|
+
rb_raise(rb_eFatal, "unable to run code: too short (got %ld chars, expected at least %d chars)", hex_code_len, DUALCONE_MIN_HEX_LEN);
|
73
|
+
}
|
74
|
+
|
75
|
+
/* Allocate memory for ciphertext */
|
76
|
+
ctx.ciphertext_len = hex_code_len / 2;
|
77
|
+
ctx.ciphertext = calloc(1, ctx.ciphertext_len);
|
78
|
+
if (RB_UNLIKELY(ctx.ciphertext == NULL)) {
|
79
|
+
errno_sv = errno;
|
80
|
+
rb_dualcone_cleanup(&ctx);
|
81
|
+
rb_raise(rb_eFatal, "unable to allocate memory for ciphertext: %s", strerror(errno_sv));
|
82
|
+
}
|
83
|
+
|
84
|
+
/* Convert code (hex encoded) to binary */
|
85
|
+
result = hydro_hex2bin(ctx.ciphertext, ctx.ciphertext_len, hex_code, hex_code_len, NULL, NULL);
|
86
|
+
if (result == -1) {
|
87
|
+
errno_sv = errno;
|
88
|
+
rb_dualcone_cleanup(&ctx);
|
89
|
+
rb_raise(rb_eFatal, "unable to hex-decode ruby code: %s", strerror(errno_sv));
|
90
|
+
}
|
91
|
+
|
92
|
+
/* Allocate memory for plaintext */
|
93
|
+
ctx.plaintext_len = ctx.ciphertext_len - hydro_secretbox_HEADERBYTES + 1; // Null byte
|
94
|
+
ctx.plaintext = calloc(1, ctx.plaintext_len);
|
95
|
+
if (RB_UNLIKELY(ctx.plaintext == NULL)) {
|
96
|
+
errno_sv = errno;
|
97
|
+
rb_dualcone_cleanup(&ctx);
|
98
|
+
rb_raise(rb_eFatal, "unable to allocate memory for plaintext: %s", strerror(errno_sv));
|
99
|
+
}
|
100
|
+
|
101
|
+
/* Decrypt binary code to plaintext code */
|
102
|
+
result = hydro_secretbox_decrypt(ctx.plaintext, ctx.ciphertext, ctx.ciphertext_len, 0, DUALCONE_CONTEXT, ctx.binary_key);
|
103
|
+
if (result == -1) {
|
104
|
+
rb_dualcone_cleanup(&ctx);
|
105
|
+
rb_raise(rb_eFatal, "unable to decrypt ruby code");
|
106
|
+
}
|
107
|
+
|
108
|
+
/* Evaluate the plaintext code */
|
109
|
+
rb_eval_string_protect(ctx.plaintext, &result);
|
110
|
+
if (result != 0) {
|
111
|
+
rb_dualcone_cleanup(&ctx);
|
112
|
+
rb_raise(rb_eFatal, "unable to evaluate ruby code");
|
113
|
+
}
|
114
|
+
|
115
|
+
/* Done */
|
116
|
+
rb_dualcone_cleanup(&ctx);
|
117
|
+
return Qnil;
|
118
|
+
}
|
119
|
+
|
120
|
+
VALUE rb_dualcone_generate_key(VALUE _self) {
|
121
|
+
uint8_t key[hydro_secretbox_KEYBYTES];
|
122
|
+
char hex[hydro_secretbox_KEYBYTES * 2 + 1];
|
123
|
+
|
124
|
+
/* Generate key */
|
125
|
+
hydro_secretbox_keygen(key);
|
126
|
+
char *retval = hydro_bin2hex(hex, hydro_secretbox_KEYBYTES * 2 + 1, key, hydro_secretbox_KEYBYTES);
|
127
|
+
if (retval == NULL) {
|
128
|
+
rb_raise(rb_eFatal, "unable to generate key");
|
129
|
+
}
|
130
|
+
|
131
|
+
return rb_str_new_cstr(hex);
|
132
|
+
}
|
133
|
+
|
134
|
+
VALUE rb_dualcone_encrypt(VALUE _self, VALUE path) {
|
135
|
+
int result = 0;
|
136
|
+
int errno_sv = 0;
|
137
|
+
|
138
|
+
/* Check args */
|
139
|
+
rb_check_type(path, T_STRING);
|
140
|
+
|
141
|
+
/* Dualcone private memory allocations */
|
142
|
+
DualconeContext ctx = {0};
|
143
|
+
rb_dualcone_get_key(&ctx);
|
144
|
+
|
145
|
+
/* The path of the input file (ruby code, plaintext) */
|
146
|
+
/* This value is modified by dirname(), so strdup() is necessary */
|
147
|
+
ctx.input_path = strdup(StringValuePtr(path));
|
148
|
+
if (RB_UNLIKELY(ctx.input_path == NULL)) {
|
149
|
+
errno_sv = errno;
|
150
|
+
rb_dualcone_cleanup(&ctx);
|
151
|
+
rb_raise(rb_eFatal, "unable to allocate memory for input path: %s", strerror(errno_sv));
|
152
|
+
}
|
153
|
+
|
154
|
+
/* Check if input file is readable */
|
155
|
+
int plaintext_fd = open(ctx.input_path, O_RDONLY);
|
156
|
+
if (plaintext_fd == -1) {
|
157
|
+
errno_sv = errno;
|
158
|
+
rb_dualcone_cleanup(&ctx);
|
159
|
+
rb_raise(rb_eFatal, "unable to read input file '%s': %s", ctx.input_path, strerror(errno_sv));
|
160
|
+
}
|
161
|
+
|
162
|
+
/* Allocate memory for temporary path template */
|
163
|
+
ctx.output_path = calloc(1, PATH_MAX);
|
164
|
+
if (RB_UNLIKELY(ctx.output_path == NULL)) {
|
165
|
+
errno_sv = errno;
|
166
|
+
rb_dualcone_cleanup(&ctx);
|
167
|
+
rb_raise(rb_eFatal, "unable to allocate memory for output path: %s", strerror(errno_sv));
|
168
|
+
}
|
169
|
+
|
170
|
+
/* Construct path template for temporary file */
|
171
|
+
char *output_dir = dirname(ctx.input_path);
|
172
|
+
strncat(ctx.output_path, output_dir, PATH_MAX - strlen(ctx.output_path) - 1);
|
173
|
+
strncat(ctx.output_path, "/.dualcone.XXXXXX", PATH_MAX - strlen(ctx.output_path) - 1);
|
174
|
+
|
175
|
+
/* Create temporary file */
|
176
|
+
int output_fd = mkstemp(ctx.output_path);
|
177
|
+
if (RB_UNLIKELY(output_fd == -1)) {
|
178
|
+
errno_sv = errno;
|
179
|
+
rb_dualcone_cleanup(&ctx);
|
180
|
+
rb_raise(rb_eFatal, "unable to create temporary file: %s", strerror(errno_sv));
|
181
|
+
}
|
182
|
+
|
183
|
+
/* Get input file length */
|
184
|
+
struct stat plaintext_stat = {0};
|
185
|
+
result = fstat(plaintext_fd, &plaintext_stat);
|
186
|
+
if (result == -1) {
|
187
|
+
errno_sv = errno;
|
188
|
+
rb_dualcone_cleanup(&ctx);
|
189
|
+
rb_raise(rb_eFatal, "unable to determine length of input file: %s", strerror(errno_sv));
|
190
|
+
}
|
191
|
+
|
192
|
+
/* Allocate buffer for input file */
|
193
|
+
ctx.plaintext_len = plaintext_stat.st_size;
|
194
|
+
ctx.plaintext = calloc(1, ctx.plaintext_len);
|
195
|
+
if (RB_UNLIKELY(ctx.plaintext == NULL)) {
|
196
|
+
errno_sv = errno;
|
197
|
+
rb_dualcone_cleanup(&ctx);
|
198
|
+
rb_raise(rb_eFatal, "unable to allocate memory for input data: %s", strerror(errno_sv));
|
199
|
+
}
|
200
|
+
|
201
|
+
/* Read entire input file */
|
202
|
+
ssize_t read_result = read(plaintext_fd, ctx.plaintext, ctx.plaintext_len);
|
203
|
+
if (read_result == -1) {
|
204
|
+
errno_sv = errno;
|
205
|
+
rb_dualcone_cleanup(&ctx);
|
206
|
+
rb_raise(rb_eFatal, "unable to read ruby code: %s", strerror(errno_sv));
|
207
|
+
}
|
208
|
+
close(plaintext_fd);
|
209
|
+
|
210
|
+
/* Allocate memory for encryption result */
|
211
|
+
ctx.ciphertext_len = hydro_secretbox_HEADERBYTES + ctx.plaintext_len;
|
212
|
+
ctx.ciphertext = calloc(1, ctx.ciphertext_len);
|
213
|
+
if (RB_UNLIKELY(ctx.ciphertext == NULL)) {
|
214
|
+
errno_sv = errno;
|
215
|
+
rb_dualcone_cleanup(&ctx);
|
216
|
+
rb_raise(rb_eFatal, "unable to allocate memory for encryption: %s", strerror(errno_sv));
|
217
|
+
}
|
218
|
+
|
219
|
+
/* Encrypt data! */
|
220
|
+
result = hydro_secretbox_encrypt(ctx.ciphertext, ctx.plaintext, ctx.plaintext_len, 0, DUALCONE_CONTEXT, ctx.binary_key);
|
221
|
+
if (result != 0) {
|
222
|
+
rb_dualcone_cleanup(&ctx);
|
223
|
+
rb_raise(rb_eFatal, "unable to encrypt ruby code");
|
224
|
+
}
|
225
|
+
|
226
|
+
/* Allocate memory for hex-encoded encrypted data */
|
227
|
+
ctx.ciphertext_hex_len = ctx.ciphertext_len * 2 + 1;
|
228
|
+
ctx.ciphertext_hex = calloc(1, ctx.ciphertext_hex_len);
|
229
|
+
if (RB_UNLIKELY(ctx.ciphertext_hex == NULL)) {
|
230
|
+
errno_sv = errno;
|
231
|
+
rb_dualcone_cleanup(&ctx);
|
232
|
+
rb_raise(rb_eFatal, "unable to allocate memory for hex-encoding: %s", strerror(errno_sv));
|
233
|
+
}
|
234
|
+
|
235
|
+
/* Hex encode encrypted data */
|
236
|
+
hydro_bin2hex(ctx.ciphertext_hex, ctx.ciphertext_hex_len, ctx.ciphertext, ctx.ciphertext_len);
|
237
|
+
|
238
|
+
/* Write preamble */
|
239
|
+
ssize_t write_result = 0;
|
240
|
+
write_result = write(output_fd, DUALCONE_PREAMBLE, sizeof(DUALCONE_PREAMBLE) - 1);
|
241
|
+
if (write_result == -1) {
|
242
|
+
errno_sv = errno;
|
243
|
+
rb_dualcone_cleanup(&ctx);
|
244
|
+
rb_raise(rb_eFatal, "unable to write to temporary file: %s", strerror(errno_sv));
|
245
|
+
}
|
246
|
+
|
247
|
+
/* Write hex-encoded data */
|
248
|
+
write_result = write(output_fd, ctx.ciphertext_hex, ctx.ciphertext_hex_len - 1);
|
249
|
+
if (write_result == -1) {
|
250
|
+
errno_sv = errno;
|
251
|
+
rb_dualcone_cleanup(&ctx);
|
252
|
+
rb_raise(rb_eFatal, "unable to write to temporary file: %s", strerror(errno_sv));
|
253
|
+
}
|
254
|
+
|
255
|
+
/* Write postamble */
|
256
|
+
write_result = write(output_fd, DUALCONE_POSTAMBLE, sizeof(DUALCONE_POSTAMBLE) - 1);
|
257
|
+
if (write_result == -1) {
|
258
|
+
errno_sv = errno;
|
259
|
+
rb_dualcone_cleanup(&ctx);
|
260
|
+
rb_raise(rb_eFatal, "unable to write to temporary file: %s", strerror(errno_sv));
|
261
|
+
}
|
262
|
+
|
263
|
+
/* Rename tempfile over original */
|
264
|
+
close(output_fd);
|
265
|
+
char *plaintext_path = StringValuePtr(path);
|
266
|
+
result = rename(ctx.output_path, plaintext_path);
|
267
|
+
if (result == -1) {
|
268
|
+
errno_sv = errno;
|
269
|
+
rb_dualcone_cleanup(&ctx);
|
270
|
+
rb_raise(rb_eFatal, "unable to rename temporary file: %s", strerror(errno_sv));
|
271
|
+
}
|
272
|
+
|
273
|
+
/* Done */
|
274
|
+
rb_dualcone_cleanup(&ctx);
|
275
|
+
return Qnil;
|
276
|
+
}
|
277
|
+
|
278
|
+
void Init_dualcone(void) {
|
279
|
+
if (RB_UNLIKELY(hydro_init() != 0)) {
|
280
|
+
rb_raise(rb_eFatal, "unable to initialize libhydrogen");
|
281
|
+
return;
|
282
|
+
}
|
283
|
+
|
284
|
+
rb_mDualcone = rb_define_module("Dualcone");
|
285
|
+
rb_define_module_function(rb_mDualcone, "encrypt", rb_dualcone_encrypt, 1);
|
286
|
+
rb_define_module_function(rb_mDualcone, "generate_key", rb_dualcone_generate_key, 0);
|
287
|
+
rb_define_module_function(rb_mDualcone, "run", rb_dualcone_run, 1);
|
288
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#ifndef __DUALCONE_H
|
2
|
+
#define __DUALCONE_H
|
3
|
+
|
4
|
+
#include <stdio.h>
|
5
|
+
#include <errno.h>
|
6
|
+
#include <limits.h>
|
7
|
+
#include <libgen.h>
|
8
|
+
#include <sys/types.h>
|
9
|
+
#include <sys/stat.h>
|
10
|
+
#include <fcntl.h>
|
11
|
+
#include <unistd.h>
|
12
|
+
|
13
|
+
#include <ruby.h>
|
14
|
+
#include <hydrogen.h>
|
15
|
+
|
16
|
+
#define DUALCONE_CONTEXT "DUALCONE"
|
17
|
+
#define DUALCONE_HEX_KEY "DUALCONE_HEX_KEY"
|
18
|
+
#define DUALCONE_MIN_HEX_LEN hydro_secretbox_HEADERBYTES * 2
|
19
|
+
#define DUALCONE_PREAMBLE "require 'dualcone'\nDualcone.run('"
|
20
|
+
#define DUALCONE_POSTAMBLE "')\n"
|
21
|
+
|
22
|
+
#ifndef PATH_MAX
|
23
|
+
#define PATH_MAX 4096
|
24
|
+
#endif
|
25
|
+
|
26
|
+
typedef struct {
|
27
|
+
/* Symmetric key */
|
28
|
+
uint8_t binary_key[hydro_secretbox_KEYBYTES];
|
29
|
+
|
30
|
+
/* Input file path */
|
31
|
+
char *input_path;
|
32
|
+
|
33
|
+
/* Temporary output file path */
|
34
|
+
char *output_path;
|
35
|
+
|
36
|
+
/* Encrypted code (hex-encoded) */
|
37
|
+
char *ciphertext_hex;
|
38
|
+
size_t ciphertext_hex_len;
|
39
|
+
|
40
|
+
/* Encrypted code (binary) */
|
41
|
+
uint8_t *ciphertext;
|
42
|
+
size_t ciphertext_len;
|
43
|
+
|
44
|
+
/* Plaintext ruby code */
|
45
|
+
char *plaintext;
|
46
|
+
size_t plaintext_len;
|
47
|
+
} DualconeContext;
|
48
|
+
|
49
|
+
#endif /* __DUALCONE_H */
|