Skip to content

Commit

Permalink
Add crypto.getRandomValues() (#2327)
Browse files Browse the repository at this point in the history
  • Loading branch information
chiefbiiko authored and ry committed May 17, 2019
1 parent 7f65495 commit 00f6fa4
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 1 deletion.
1 change: 1 addition & 0 deletions cli/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ ts_sources = [
"../js/files.ts",
"../js/flatbuffers.ts",
"../js/form_data.ts",
"../js/get_random_values.ts",
"../js/globals.ts",
"../js/headers.ts",
"../js/io.ts",
Expand Down
1 change: 1 addition & 0 deletions cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ extern crate clap;
extern crate deno;
#[cfg(unix)]
extern crate nix;
extern crate rand;

mod ansi;
pub mod compiler;
Expand Down
3 changes: 3 additions & 0 deletions cli/msg.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ union Any {
FetchRes,
FormatError,
FormatErrorRes,
GetRandomValues,
GlobalTimer,
GlobalTimerRes,
GlobalTimerStop,
Expand Down Expand Up @@ -578,4 +579,6 @@ table Seek {
whence: uint;
}

table GetRandomValues {}

root_type Base;
12 changes: 12 additions & 0 deletions cli/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::js_errors::apply_source_map;
use crate::js_errors::JSErrorColor;
use crate::msg;
use crate::msg_util;
use crate::rand;
use crate::repl;
use crate::resolve_addr::resolve_addr;
use crate::resources;
Expand All @@ -39,6 +40,7 @@ use futures::Sink;
use futures::Stream;
use hyper;
use hyper::rt::Future;
use rand::{thread_rng, Rng};
use remove_dir_all::remove_dir_all;
use std;
use std::convert::From;
Expand Down Expand Up @@ -195,6 +197,7 @@ pub fn op_selector_std(inner_type: msg::Any) -> Option<OpCreator> {
msg::Any::Exit => Some(op_exit),
msg::Any::Fetch => Some(op_fetch),
msg::Any::FormatError => Some(op_format_error),
msg::Any::GetRandomValues => Some(op_get_random_values),
msg::Any::GlobalTimer => Some(op_global_timer),
msg::Any::GlobalTimerStop => Some(op_global_timer_stop),
msg::Any::IsTTY => Some(op_is_tty),
Expand Down Expand Up @@ -2168,3 +2171,12 @@ fn op_host_post_message(
});
Box::new(op)
}

fn op_get_random_values(
_state: &ThreadSafeState,
_base: &msg::Base<'_>,
data: Option<PinnedBuf>,
) -> Box<OpWithError> {
thread_rng().fill(&mut data.unwrap()[..]);
Box::new(ok_future(empty_buf()))
}
35 changes: 35 additions & 0 deletions js/get_random_values.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import * as msg from "gen/cli/msg_generated";
import * as flatbuffers from "./flatbuffers";
import * as dispatch from "./dispatch";
import { assert } from "./util";

function req(
typedArray: ArrayBufferView
): [flatbuffers.Builder, msg.Any, flatbuffers.Offset, ArrayBufferView] {
const builder = flatbuffers.createBuilder();
const inner = msg.GetRandomValues.createGetRandomValues(builder);
return [builder, msg.Any.GetRandomValues, inner, typedArray];
}

/** Synchronously collects cryptographically secure random values. The
* underlying CSPRNG in use is Rust's `rand::rngs::ThreadRng`.
*
* const arr = new Uint8Array(32);
* crypto.getRandomValues(arr);
*/
export function getRandomValues<
T extends
| Int8Array
| Uint8Array
| Uint8ClampedArray
| Int16Array
| Uint16Array
| Int32Array
| Uint32Array
>(typedArray: T): T {
assert(typedArray !== null, "Input must not be null");
assert(typedArray.length <= 65536, "Input must not be longer than 65536");
dispatch.sendSync(...req(typedArray as ArrayBufferView));
return typedArray;
}
51 changes: 51 additions & 0 deletions js/get_random_values_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { test, assertNotEquals, assertStrictEq } from "./test_util.ts";

test(function getRandomValuesInt8Array(): void {
const arr = new Int8Array(32);
crypto.getRandomValues(arr);
assertNotEquals(arr, new Int8Array(32));
});

test(function getRandomValuesUint8Array(): void {
const arr = new Uint8Array(32);
crypto.getRandomValues(arr);
assertNotEquals(arr, new Uint8Array(32));
});

test(function getRandomValuesUint8ClampedArray(): void {
const arr = new Uint8ClampedArray(32);
crypto.getRandomValues(arr);
assertNotEquals(arr, new Uint8ClampedArray(32));
});

test(function getRandomValuesInt16Array(): void {
const arr = new Int16Array(4);
crypto.getRandomValues(arr);
assertNotEquals(arr, new Int16Array(4));
});

test(function getRandomValuesUint16Array(): void {
const arr = new Uint16Array(4);
crypto.getRandomValues(arr);
assertNotEquals(arr, new Uint16Array(4));
});

test(function getRandomValuesInt32Array(): void {
const arr = new Int32Array(8);
crypto.getRandomValues(arr);
assertNotEquals(arr, new Int32Array(8));
});

test(function getRandomValuesUint32Array(): void {
const arr = new Uint32Array(8);
crypto.getRandomValues(arr);
assertNotEquals(arr, new Uint32Array(8));
});

test(function getRandomValuesReturnValue(): void {
const arr = new Uint32Array(8);
const rtn = crypto.getRandomValues(arr);
assertNotEquals(arr, new Uint32Array(8));
assertStrictEq(rtn, arr);
});
21 changes: 21 additions & 0 deletions js/globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import { window } from "./window";
import * as blob from "./blob";
import * as consoleTypes from "./console";
import * as csprng from "./get_random_values";
import * as customEvent from "./custom_event";
import * as deno from "./deno";
import * as domTypes from "./dom_types";
Expand Down Expand Up @@ -69,6 +70,10 @@ window.console = console;
window.setTimeout = timers.setTimeout;
window.setInterval = timers.setInterval;
window.location = (undefined as unknown) as domTypes.Location;
// The following Crypto interface implementation is not up to par with the
// standard https://www.w3.org/TR/WebCryptoAPI/#crypto-interface as it does not
// yet incorporate the SubtleCrypto interface as its "subtle" property.
window.crypto = (csprng as unknown) as Crypto;

// When creating the runtime type library, we use modifications to `window` to
// determine what is in the global namespace. When we put a class in the
Expand Down Expand Up @@ -135,3 +140,19 @@ export interface ImportMeta {
url: string;
main: boolean;
}

export interface Crypto {
readonly subtle: null;
getRandomValues: <
T extends
| Int8Array
| Uint8Array
| Uint8ClampedArray
| Int16Array
| Uint16Array
| Int32Array
| Uint32Array
>(
typedArray: T
) => T;
}
4 changes: 3 additions & 1 deletion js/test_util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import {
} from "./deps/https/deno.land/std/testing/asserts.ts";
export {
assert,
assertEquals
assertEquals,
assertNotEquals,
assertStrictEq
} from "./deps/https/deno.land/std/testing/asserts.ts";

interface TestPermissions {
Expand Down
1 change: 1 addition & 0 deletions js/unit_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import "./fetch_test.ts";
import "./file_test.ts";
import "./files_test.ts";
import "./form_data_test.ts";
import "./get_random_values_test.ts";
import "./globals_test.ts";
import "./headers_test.ts";
import "./link_test.ts";
Expand Down

0 comments on commit 00f6fa4

Please sign in to comment.