Skip to content
This repository was archived by the owner on Jul 3, 2020. It is now read-only.

Commit 0302835

Browse files
author
Face Kapow
committed
Some bindings, fix history
1 parent 7075732 commit 0302835

File tree

6 files changed

+1151
-2
lines changed

6 files changed

+1151
-2
lines changed

js/core/libsodium.js

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
// Copyright 2014-present runtime.js project authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
var lib = require('./resources').libsodium;
18+
var constants = lib.crypto_constants();
19+
20+
// Helper function to convert hex results into Uint8Arrays.
21+
function hexToU8(hexStr) {
22+
var u8 = new Uint8Array(hexStr.length/2);
23+
for (var i = 0; i < (hexStr.length/2); i++) {
24+
u8[i] = parseInt(hexStr.substr(i*2, 2), 16);
25+
}
26+
return u8;
27+
}
28+
29+
function throwErr(funcName, argName, i, msg) {
30+
throw new Error(funcName + ': ' + argName + ' (argument ' + i + ') ' + msg + '.');
31+
}
32+
33+
function stringOrU8(arg, funcName, argName, i, msg) {
34+
var ret = arg;
35+
if (!(arg instanceof Uint8Array)) {
36+
if (typeof arg === 'string' || (arg instanceof String)) {
37+
ret = new Uint8Array(arg.length);
38+
for (var i = 0; i < arg.length; i++) {
39+
ret[i] = arg.charCodeAt(i);
40+
}
41+
} else {
42+
throwErr(funcName, argName, i, (msg ? msg : 'must be a string or Uint8Array'));
43+
}
44+
}
45+
return ret;
46+
}
47+
48+
function isNumber(arg, funcName, argName, i, msg) {
49+
if (typeof arg !== 'number' && !(arg instanceof Number)) {
50+
throwErr(funcName, argName, i, (msg ? msg : 'must be a number'));
51+
}
52+
return arg;
53+
}
54+
55+
module.exports = {
56+
crypto_secretbox_easy: function(data, key) {
57+
var dataArr = stringOrU8(data, 'crypto_secretbox_easy', 'data', 0);
58+
var keyArr = stringOrU8(key, 'crypto_secretbox_easy', 'key', 1);
59+
60+
var nonceArr = runtime.random.getRandomValues(constants.crypto_secretbox_NONCEBYTES);
61+
62+
var cipher = lib.crypto_secretbox_easy(dataArr, keyArr, nonceArr);
63+
if (!cipher) {
64+
throw new Error('crypto_secretbox_easy: error creating box.');
65+
}
66+
return {
67+
ciphertext: hexToU8(cipher),
68+
nonce: nonceArr
69+
};
70+
},
71+
crypto_secretbox_open_easy: function(cipher, key, nonce) {
72+
var cipherArr = stringOrU8(cipher, 'crypto_secretbox_open_easy', 'cipher', 0);
73+
var keyArr = stringOrU8(key, 'crypto_secretbox_open_easy', 'key', 1);
74+
var nonceArr = stringOrU8(nonce, 'crypto_secretbox_open_easy', 'nonce', 2);
75+
76+
var decipher = lib.crypto_secretbox_open_easy(cipherArr, keyArr, nonceArr);
77+
if (!decipher) {
78+
throw new Error('crypto_secretbox_open_easy: error decrypting box.');
79+
}
80+
return hexToU8(decipher);
81+
},
82+
crypto_auth: function(data, key) {
83+
var dataArr = stringOrU8(data, 'crypto_auth', 'data', 0);
84+
var keyArr;
85+
if (key === null || key === undefined) {
86+
keyArr = runtime.random.getRandomValues(constants.crypto_auth_KEYBYTES);
87+
} else {
88+
keyArr = stringOrU8(key, 'crypto_auth', 'key', 1, 'must be unspecified, a string, or Uint8Array');
89+
}
90+
91+
var mac = lib.crypto_auth(dataArr, keyArr);
92+
if (!mac) {
93+
throw new Error('crypto_auth: error creating tag.');
94+
}
95+
return {
96+
mac: hexToU8(mac),
97+
key: keyArr
98+
};
99+
},
100+
crypto_auth_verify: function(mac, key, data) {
101+
var macArr = stringOrU8(mac, 'crypto_auth_verify', 'MAC', 0);
102+
var keyArr = stringOrU8(key, 'crypto_auth_verify', 'key', 1);
103+
var dataArr = stringOrU8(data, 'crypto_auth_verify', 'data', 2);
104+
105+
return lib.crypto_auth_verify(macArr, keyArr, dataArr);
106+
},
107+
crypto_aead_chacha20poly1305_encrypt: function(data, key, addData) {
108+
var dataArr = stringOrU8(data, 'crypto_aead_chacha20poly1305_encrypt', 'data', 0);
109+
var keyArr = stringOrU8(key, 'crypto_aead_chacha20poly1305_encrypt', 'key', 1);
110+
var addDataArr = stringOrU8(key, 'crypto_aead_chacha20poly1305_encrypt', 'additional data', 2);
111+
112+
var nonceArr = runtime.random.getRandomValues(constants.crypto_aead_chacha20poly1305_NPUBBYTES);
113+
114+
var cipher = lib.crypto_aead_chacha20poly1305_encrypt(dataArr, keyArr, nonceArr, addDataArr);
115+
if (!cipher) {
116+
throw new Error('crypto_aead_chacha20poly1305_encrypt: error creating box.');
117+
}
118+
return {
119+
ciphertext: hexToU8(cipher.ciphertext),
120+
nonce: nonceArr,
121+
length: cipher.ciphertext_len
122+
};
123+
},
124+
crypto_aead_chacha20poly1305_decrypt: function(cipher, cipherLength, key, nonce, addData) {
125+
var cipherArr = stringOrU8(cipher, 'crypto_aead_chacha20poly1305_decrypt', 'cipher', 0);
126+
var cipherLen = isNumber(cipherLength, 'crypto_aead_chacha20poly1305_decrypt', 'cipher length', 1);
127+
var keyArr = stringOrU8(key, 'crypto_aead_chacha20poly1305_decrypt', 'key', 2);
128+
var nonceArr = stringOrU8(nonce, 'crypto_aead_chacha20poly1305_decrypt', 'nonce', 3);
129+
var addDataArr = stringOrU8(key, 'crypto_aead_chacha20poly1305_decrypt', 'additional data', 4);
130+
131+
var decipher = lib.crypto_aead_chacha20poly1305_decrypt(cipherArr, keyArr, nonceArr, addDataArr, cipherLen);
132+
if (!decipher) {
133+
throw new Error('crypto_aead_chacha20poly1305_decrypt: error decrypting box.');
134+
}
135+
return hexToU8(decipher.deciphertext);
136+
},
137+
crypto_aead_aes256gcm_is_available: function() {
138+
// AES-256 GCM isn't supported on QEMU's system-x86_64
139+
return false;
140+
},
141+
crypto_aead_aes256gcm_encrypt: function(data, key, addData) {
142+
// AES-256 GCM isn't supported on QEMU's system-x86_64
143+
throw new Error('CPU not supported');
144+
/*var dataArr = stringOrU8(data, 'crypto_aead_aes256gcm_encrypt', 'data', 0);
145+
var keyArr = stringOrU8(key, 'crypto_aead_aes256gcm_encrypt', 'key', 1);
146+
var addDataArr = stringOrU8(key, 'crypto_aead_aes256gcm_encrypt', 'additional data', 2);
147+
var nonceArr = runtime.random.getRandomValues(constants.crypto_aead_aes256gcm_NPUBBYTES);
148+
var cipher = lib.crypto_aead_aes256gcm_encrypt(dataArr, keyArr, nonceArr, addDataArr);
149+
if (!cipher) {
150+
throw new Error('crypto_aead_aes256gcm_encrypt: error creating box.');
151+
}
152+
if (cipher instanceof Error) throw cipher;
153+
return {
154+
ciphertext: hexToU8(cipher.ciphertext),
155+
nonce: nonceArr,
156+
length: cipher.ciphertext_len
157+
};*/
158+
},
159+
crypto_aead_aes256gcm_decrypt: function(cipher, cipherLength, key, nonce, addData) {
160+
// AES-256 GCM isn't supported on QEMU's system-x86_64
161+
throw new Error('CPU not supported');
162+
/*var cipherArr = stringOrU8(cipher, 'crypto_aead_aes256gcm_decrypt', 'cipher', 0);
163+
var cipherLen = isNumber(cipherLength, 'crypto_aead_aes256gcm_decrypt', 'cipher length', 1);
164+
var keyArr = stringOrU8(key, 'crypto_aead_aes256gcm_decrypt', 'key', 2);
165+
var nonceArr = stringOrU8(nonce, 'crypto_aead_aes256gcm_decrypt', 'nonce', 3);
166+
var addDataArr = stringOrU8(key, 'crypto_aead_aes256gcm_decrypt', 'additional data', 4);
167+
var decipher = lib.crypto_aead_aes256gcm_decrypt(cipherArr, keyArr, nonceArr, addDataArr, cipherLen);
168+
if (!decipher) {
169+
throw new Error('crypto_aead_aes256gcm_decrypt: error decrypting box.');
170+
}
171+
if (decipher instanceof Error) throw decipher;
172+
return hexToU8(decipher.deciphertext);*/
173+
},
174+
crypto_box_easy: function(data, pk, sk) {
175+
var dataArr = stringOrU8(data, 'crypto_box_easy', 'data', 0);
176+
var pkArr = stringOrU8(pk, 'crypto_box_easy', 'public key', 1);
177+
var skArr = stringOrU8(sk, 'crypto_box_easy', 'secret key', 2);
178+
179+
var nonceArr = runtime.random.getRandomValues(constants.crypto_box_NONCEBYTES);
180+
181+
var cipher = lib.crypto_box_easy(dataArr, pkArr, skArr, nonceArr);
182+
if (!cipher) {
183+
throw new Error('crypto_box_easy: error creating box.');
184+
}
185+
return {
186+
ciphertext: hexToU8(cipher),
187+
nonce: nonceArr
188+
};
189+
},
190+
crypto_box_open_easy: function(cipher, pk, sk, nonce) {
191+
var cipherArr = stringOrU8(cipher, 'crypto_box_open_easy', 'cipher', 0);
192+
var pkArr = stringOrU8(pk, 'crypto_box_open_easy', 'public key', 1);
193+
var skArr = stringOrU8(sk, 'crypto_box_open_easy', 'secret key', 1);
194+
var nonceArr = stringOrU8(nonce, 'crypto_box_open_easy', 'nonce', 2);
195+
196+
var decipher = lib.crypto_box_open_easy(cipherArr, pkArr, skArr, nonceArr);
197+
if (!decipher) {
198+
throw new Error('crypto_box_open_easy: error decrypting box.');
199+
}
200+
return hexToU8(decipher);
201+
},
202+
crypto_box_keypair: function() {
203+
var keypair = lib.crypto_box_keypair();
204+
if (typeof keypair === 'string') throw new Error(keypair);
205+
return keypair;
206+
},
207+
crypto_box_seed_keypair: function(seed) {
208+
var seedArr = stringOrU8(seed, 'crypto_box_seed_keypair', 'seed', 0);
209+
210+
var keypair = lib.crypto_box_seed_keypair(seedArr);
211+
if (typeof keypair === 'string') throw new Error(keypair);
212+
return keypair;
213+
}
214+
};
215+
216+
var justConvertHex = [
217+
{
218+
funcName: 'randombytes_buf',
219+
errorInfo: 'error generating randomness.',
220+
dataVerifier: isNumber,
221+
argName: 'buffer length'
222+
},
223+
{
224+
funcName: 'crypto_generichash',
225+
errorInfo: 'error calculating hash.'
226+
},
227+
{
228+
funcName: 'crypto_hash_sha256',
229+
errorInfo: 'error calculating hash.'
230+
},
231+
{
232+
funcName: 'crypto_hash_sha512',
233+
errorInfo: 'error calculating hash.'
234+
}
235+
];
236+
237+
for (var i = 0; i < justConvertHex.length; i++) {
238+
(function(i) {
239+
var f = justConvertHex[i];
240+
module.exports[f.funcName] = function(data) {
241+
var result = lib[f.funcName]((f.dataVerifier ? f.dataVerifier : stringOrU8)(data, f.funcName, (f.argName ? f.argName : 'data'), 0));
242+
if (!result) {
243+
throw new Error(f.funcName + ': ' + (f.errorInfo ? f.errorInfo : 'unknown error.'));
244+
}
245+
return hexToU8(result);
246+
}
247+
})(i);
248+
}

js/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ runtime.shell.setCommand('reboot', function(args, env, cb) {
5959
cb(0);
6060
});
6161

62+
runtime.libsodium = require('./core/libsodium');
63+
6264

6365
// Start device drivers
6466
require('./driver/ps2');

src/kernel/kernel-main.cc

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,14 +145,56 @@ const char* runtime_rng_name() {
145145
}
146146

147147
uint32_t runtime_rng_random() {
148+
// prevent abort()
149+
if (GLOBAL_engines()) {
150+
v8::Isolate* iv8 = GLOBAL_engines()->cpu_engine()->thread_manager()->current_thread()->IsolateV8();
151+
v8::Local<v8::Context> context = iv8->GetCurrentContext();
152+
153+
v8::Local<v8::Object> global = context->Global();
154+
v8::Local<v8::Object> runtimeObj = global->Get(context, v8::String::NewFromUtf8(iv8, "runtime", v8::NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()->ToObject();
155+
v8::Local<v8::Object> runtimeRandomObj = runtimeObj->Get(context, v8::String::NewFromUtf8(iv8, "random", v8::NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()->ToObject();
156+
v8::Local<v8::Function> runtimeRandomGetRandomValuesFunc = v8::Local<v8::Function>::Cast(runtimeRandomObj->Get(context, v8::String::NewFromUtf8(iv8, "getRandomValues", v8::NewStringType::kNormal).ToLocalChecked()).ToLocalChecked());
157+
158+
v8::Local<v8::Value> args[1] = { v8::Number::New(iv8, 1) };
159+
160+
// js equivalent: runtime.random.getRandomValues.apply(undefined, [1])
161+
v8::Local<v8::Object> u8Array = runtimeRandomGetRandomValuesFunc->Call(context, v8::Undefined(iv8), 1, args).ToLocalChecked()->ToObject(context).ToLocalChecked();
162+
return (uint8_t)(u8Array->Get(0)->ToNumber()->Value());
163+
} else {
164+
// mainly when libsodium is intialized, which is before V8 is available
165+
printf("[randombytes] fallback used\n");
148166
return 42;
167+
}
149168
}
150169

151170
void runtime_rng_buf(void* const buf, const size_t size) {
152-
uint8_t* b = reinterpret_cast<uint8_t*>(buf);
171+
uint8_t* b = reinterpret_cast<uint8_t*>(buf);
172+
173+
// prevent abort()
174+
if (GLOBAL_engines()) {
175+
v8::Isolate* iv8 = GLOBAL_engines()->cpu_engine()->thread_manager()->current_thread()->IsolateV8();
176+
v8::Local<v8::Context> context = iv8->GetCurrentContext();
177+
178+
v8::Local<v8::Object> global = context->Global();
179+
v8::Local<v8::Object> runtimeObj = global->Get(context, v8::String::NewFromUtf8(iv8, "runtime", v8::NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()->ToObject();
180+
v8::Local<v8::Object> runtimeRandomObj = runtimeObj->Get(context, v8::String::NewFromUtf8(iv8, "random", v8::NewStringType::kNormal).ToLocalChecked()).ToLocalChecked()->ToObject();
181+
v8::Local<v8::Function> runtimeRandomGetRandomValuesFunc = v8::Local<v8::Function>::Cast(runtimeRandomObj->Get(context, v8::String::NewFromUtf8(iv8, "getRandomValues", v8::NewStringType::kNormal).ToLocalChecked()).ToLocalChecked());
182+
183+
v8::Local<v8::Value> args[1] = { v8::Number::New(iv8, size) };
184+
185+
// js equivalent: runtime.random.getRandomValues.apply(undefined, [size])
186+
v8::Local<v8::Object> u8Array = runtimeRandomGetRandomValuesFunc->Call(context, v8::Undefined(iv8), 1, args).ToLocalChecked()->ToObject(context).ToLocalChecked();
187+
153188
for (size_t i = 0; i < size; ++i) {
154-
b[i] = 42;
189+
b[i] = (uint8_t)u8Array->Get(i)->ToNumber()->Value();
155190
}
191+
} else {
192+
// mainly when libsodium is intialized, which is before V8 is available
193+
printf("[randombytes] fallback used\n");
194+
for (size_t i = 0; i < size; ++i) {
195+
b[i] = 42;
196+
}
197+
}
156198
}
157199

158200
void KernelMain::InitSystemBSP(void* mbt) {

0 commit comments

Comments
 (0)