Files
bun.sh/src/bun.js/node/node_crypto_binding.zig

778 lines
28 KiB
Zig

const std = @import("std");
const bun = @import("bun");
const JSC = bun.JSC;
const string = bun.string;
const Crypto = JSC.API.Bun.Crypto;
const BoringSSL = bun.BoringSSL.c;
const EVP = Crypto.EVP;
const PBKDF2 = EVP.PBKDF2;
const JSValue = JSC.JSValue;
const validators = @import("./util/validators.zig");
const JSGlobalObject = JSC.JSGlobalObject;
const JSError = bun.JSError;
const String = bun.String;
const UUID = bun.UUID;
const Async = bun.Async;
const Node = JSC.Node;
fn ExternCryptoJob(comptime name: []const u8) type {
return struct {
vm: *JSC.VirtualMachine,
task: JSC.WorkPoolTask,
any_task: JSC.AnyTask,
poll: Async.KeepAlive = .{},
callback: JSC.Strong.Optional,
ctx: *Ctx,
const Ctx = opaque {
const ctx_name = name ++ "Ctx";
pub const runTask = @extern(*const fn (*Ctx, *JSGlobalObject) callconv(.c) void, .{ .name = "Bun__" ++ ctx_name ++ "__runTask" }).*;
pub const runFromJS = @extern(*const fn (*Ctx, *JSGlobalObject, JSValue) callconv(.c) void, .{ .name = "Bun__" ++ ctx_name ++ "__runFromJS" }).*;
pub const deinit = @extern(*const fn (*Ctx) callconv(.c) void, .{ .name = "Bun__" ++ ctx_name ++ "__deinit" }).*;
};
pub fn create(global: *JSGlobalObject, ctx: *Ctx, callback: JSValue) callconv(.c) *@This() {
const vm = global.bunVM();
const job = bun.new(@This(), .{
.vm = vm,
.task = .{
.callback = &runTask,
},
.any_task = undefined,
.ctx = ctx,
.callback = .create(callback, global),
});
job.any_task = JSC.AnyTask.New(@This(), &runFromJS).init(job);
return job;
}
pub fn createAndSchedule(global: *JSGlobalObject, ctx: *Ctx, callback: JSValue) callconv(.c) void {
var job = create(global, ctx, callback.withAsyncContextIfNeeded(global));
job.schedule();
}
pub fn runTask(task: *JSC.WorkPoolTask) void {
const job: *@This() = @fieldParentPtr("task", task);
var vm = job.vm;
defer vm.enqueueTaskConcurrent(JSC.ConcurrentTask.create(job.any_task.task()));
job.ctx.runTask(vm.global);
}
pub fn runFromJS(this: *@This()) void {
defer this.deinit();
const vm = this.vm;
if (vm.isShuttingDown()) {
return;
}
const callback = this.callback.trySwap() orelse {
return;
};
this.ctx.runFromJS(vm.global, callback);
}
fn deinit(this: *@This()) void {
this.ctx.deinit();
this.poll.unref(this.vm);
this.callback.deinit();
bun.destroy(this);
}
pub fn schedule(this: *@This()) callconv(.c) void {
this.poll.ref(this.vm);
JSC.WorkPool.schedule(&this.task);
}
comptime {
@export(&create, .{ .name = "Bun__" ++ name ++ "__create" });
@export(&schedule, .{ .name = "Bun__" ++ name ++ "__schedule" });
@export(&createAndSchedule, .{ .name = "Bun__" ++ name ++ "__createAndSchedule" });
}
};
}
// Definitions for job structs created from c++
pub const CheckPrimeJob = ExternCryptoJob("CheckPrimeJob");
pub const GeneratePrimeJob = ExternCryptoJob("GeneratePrimeJob");
pub const HkdfJob = ExternCryptoJob("HkdfJob");
pub const SecretKeyJob = ExternCryptoJob("SecretKeyJob");
pub const RsaKeyPairJob = ExternCryptoJob("RsaKeyPairJob");
pub const DsaKeyPairJob = ExternCryptoJob("DsaKeyPairJob");
pub const EcKeyPairJob = ExternCryptoJob("EcKeyPairJob");
pub const NidKeyPairJob = ExternCryptoJob("NidKeyPairJob");
pub const DhKeyPairJob = ExternCryptoJob("DhKeyPairJob");
pub const DhJob = ExternCryptoJob("DhJob");
pub const SignJob = ExternCryptoJob("SignJob");
comptime {
_ = CheckPrimeJob;
_ = GeneratePrimeJob;
_ = HkdfJob;
_ = SecretKeyJob;
_ = RsaKeyPairJob;
_ = DsaKeyPairJob;
_ = EcKeyPairJob;
_ = NidKeyPairJob;
_ = DhKeyPairJob;
_ = DhJob;
_ = SignJob;
}
fn CryptoJob(comptime Ctx: type) type {
return struct {
vm: *JSC.VirtualMachine,
task: JSC.WorkPoolTask,
any_task: JSC.AnyTask,
poll: Async.KeepAlive = .{},
callback: JSC.Strong.Optional,
ctx: Ctx,
pub fn init(global: *JSGlobalObject, callback: JSValue, ctx: *const Ctx) JSError!*@This() {
const vm = global.bunVM();
const job = bun.new(@This(), .{
.vm = vm,
.task = .{
.callback = &runTask,
},
.any_task = undefined,
.ctx = ctx.*,
.callback = .create(callback.withAsyncContextIfNeeded(global), global),
});
errdefer bun.destroy(job);
try job.ctx.init(global);
job.any_task = JSC.AnyTask.New(@This(), &runFromJS).init(job);
return job;
}
pub fn initAndSchedule(global: *JSGlobalObject, callback: JSValue, ctx: *const Ctx) JSError!void {
var job = try init(global, callback, ctx);
job.schedule();
}
pub fn runTask(task: *JSC.WorkPoolTask) void {
const job: *@This() = @fieldParentPtr("task", task);
var vm = job.vm;
defer vm.enqueueTaskConcurrent(JSC.ConcurrentTask.create(job.any_task.task()));
job.ctx.runTask(job.ctx.result);
}
pub fn runFromJS(this: *@This()) void {
defer this.deinit();
const vm = this.vm;
if (vm.isShuttingDown()) {
return;
}
const callback = this.callback.trySwap() orelse {
return;
};
this.ctx.runFromJS(vm.global, callback);
}
fn deinit(this: *@This()) void {
this.ctx.deinit();
this.poll.unref(this.vm);
this.callback.deinit();
bun.destroy(this);
}
pub fn schedule(this: *@This()) callconv(.c) void {
this.poll.ref(this.vm);
JSC.WorkPool.schedule(&this.task);
}
};
}
const random = struct {
const JobCtx = struct {
value: JSValue,
bytes: [*]u8,
offset: u32,
length: usize,
result: void = {},
fn init(this: *JobCtx, _: *JSGlobalObject) JSError!void {
this.value.protect();
}
fn runTask(this: *JobCtx, _: void) void {
bun.csprng(this.bytes[this.offset..][0..this.length]);
}
fn runFromJS(this: *JobCtx, global: *JSGlobalObject, callback: JSValue) void {
const vm = global.bunVM();
vm.eventLoop().runCallback(callback, global, .js_undefined, &.{ .null, this.value });
}
fn deinit(this: *JobCtx) void {
this.value.unprotect();
}
};
const Job = CryptoJob(JobCtx);
const max_possible_length = @min(JSC.ArrayBuffer.max_size, std.math.maxInt(i32));
const max_range = 0xffff_ffff_ffff;
fn randomInt(global: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) bun.JSError!JSC.JSValue {
var min_value, var max_value, var callback = callFrame.argumentsAsArray(3);
var min_specified = true;
if (max_value.isUndefined() or max_value.isCallable()) {
callback = max_value;
max_value = min_value;
min_value = JSValue.jsNumber(0);
min_specified = false;
}
if (!callback.isUndefined()) {
_ = try validators.validateFunction(global, "callback", callback);
}
if (!min_value.isSafeInteger()) {
return global.throwInvalidArgumentTypeValue2("min", "a safe integer", min_value);
}
if (!max_value.isSafeInteger()) {
return global.throwInvalidArgumentTypeValue2("max", "a safe integer", max_value);
}
const min: i64 = @intFromFloat(@trunc(min_value.asNumber()));
const max: i64 = @intFromFloat(@trunc(max_value.asNumber()));
if (max <= min) {
return global.ERR(.OUT_OF_RANGE, "The value of \"max\" is out of range. It must be greater than the value of \"min\" ({d}). Received {d}", .{
min,
max,
}).throw();
}
if (max - min > max_range) {
if (min_specified) {
return global.ERR(.OUT_OF_RANGE, "The value of \"max - min\" is out of range. It must be <= {d}. Received {d}", .{ max_range, max - min }).throw();
}
return global.ERR(.OUT_OF_RANGE, "The value of \"max\" is out of range. It must be <= {d}. Received {d}", .{ max_range, max - min }).throw();
}
const res = std.crypto.random.intRangeLessThan(i64, min, max);
if (!callback.isUndefined()) {
callback = callback.withAsyncContextIfNeeded(global);
callback.callNextTick(global, [2]JSValue{ .js_undefined, JSValue.jsNumber(res) });
return .js_undefined;
}
return JSValue.jsNumber(res);
}
fn randomUUID(global: *JSGlobalObject, callFrame: *JSC.CallFrame) JSError!JSValue {
const args = callFrame.arguments();
var disable_entropy_cache = false;
if (args.len > 0) {
const options = args[0];
if (!options.isUndefined()) {
try validators.validateObject(global, options, "options", .{}, .{});
if (try options.get(global, "disableEntropyCache")) |disable_entropy_cache_value| {
disable_entropy_cache = try validators.validateBoolean(global, disable_entropy_cache_value, "options.disableEntropyCache", .{});
}
}
}
var str, var bytes = String.createUninitialized(.latin1, 36);
const uuid = if (disable_entropy_cache)
UUID.init()
else
global.bunVM().rareData().nextUUID();
uuid.print(bytes[0..36]);
return str.transferToJS(global);
}
fn assertOffset(global: *JSGlobalObject, offset_value: JSValue, element_size: u8, length: usize) JSError!u32 {
if (!offset_value.isNumber()) {
return global.throwInvalidArgumentTypeValue("offset", "number", offset_value);
}
const offset = offset_value.asNumber() * @as(f32, @floatFromInt(element_size));
const max_length = @min(length, max_possible_length);
if (std.math.isNan(offset) or offset > @as(f64, @floatFromInt(max_length)) or offset < 0) {
return global.throwRangeError(offset, .{ .field_name = "offset", .min = 0, .max = max_length });
}
return @intFromFloat(offset);
}
fn assertSize(global: *JSGlobalObject, size_value: JSValue, element_size: u8, offset: u32, length: usize) JSError!u32 {
var size = try validators.validateNumber(global, size_value, "size", null, null);
size *= @as(f32, @floatFromInt(element_size));
if (std.math.isNan(size) or size > max_possible_length or size < 0) {
return global.throwRangeError(size, .{ .field_name = "size", .min = 0, .max = max_possible_length });
}
if (size + @as(f32, @floatFromInt(offset)) > @as(f64, @floatFromInt(length))) {
return global.throwRangeError(size + @as(f32, @floatFromInt(offset)), .{ .field_name = "size + offset", .max = @intCast(length) });
}
return @intFromFloat(size);
}
fn randomBytes(global: *JSGlobalObject, callFrame: *JSC.CallFrame) JSError!JSValue {
const size_value, const callback = callFrame.argumentsAsArray(2);
const size = try assertSize(global, size_value, 1, 0, max_possible_length + 1);
if (!callback.isUndefined()) {
_ = try validators.validateFunction(global, "callback", callback);
}
const result, const bytes = try JSC.ArrayBuffer.alloc(global, .ArrayBuffer, size);
if (callback.isUndefined()) {
// sync
bun.csprng(bytes);
return result;
}
const ctx: JobCtx = .{
.value = result,
.bytes = bytes.ptr,
.offset = 0,
.length = size,
};
try Job.initAndSchedule(global, callback, &ctx);
return .js_undefined;
}
fn randomFillSync(global: *JSGlobalObject, callFrame: *JSC.CallFrame) JSError!JSValue {
const buf_value, const offset_value, const size_value = callFrame.argumentsAsArray(3);
const buf = buf_value.asArrayBuffer(global) orelse {
return global.throwInvalidArgumentTypeValue("buf", "ArrayBuffer or ArrayBufferView", buf_value);
};
const element_size = buf.bytesPerElement() orelse 1;
const offset = try assertOffset(
global,
if (offset_value.isUndefined()) JSC.jsNumber(0) else offset_value,
element_size,
buf.byte_len,
);
const size = if (size_value.isUndefined())
buf.byte_len - offset
else
try assertSize(global, size_value, element_size, offset, buf.byte_len);
if (size == 0) {
return buf_value;
}
bun.csprng(buf.slice()[offset..][0..size]);
return buf_value;
}
fn randomFill(global: *JSGlobalObject, callFrame: *JSC.CallFrame) JSError!JSValue {
const buf_value, var offset_value, var size_value, var callback =
callFrame.argumentsAsArray(4);
const buf = buf_value.asArrayBuffer(global) orelse {
return global.throwInvalidArgumentTypeValue("buf", "ArrayBuffer or ArrayBufferView", buf_value);
};
const element_size = buf.bytesPerElement() orelse 1;
var offset: u32 = 0;
if (offset_value.isCallable()) {
callback = offset_value;
offset = try assertOffset(global, JSValue.jsNumber(0), element_size, buf.byte_len);
size_value = JSValue.jsNumber(buf.len);
} else if (size_value.isCallable()) {
callback = size_value;
offset = try assertOffset(global, offset_value, element_size, buf.byte_len);
size_value = JSValue.jsNumber(buf.len - offset);
} else {
_ = try validators.validateFunction(global, "callback", callback);
offset = try assertOffset(global, offset_value, element_size, buf.byte_len);
}
const size = if (size_value.isUndefined())
buf.byte_len - offset
else
try assertSize(global, size_value, element_size, offset, buf.byte_len);
if (size == 0) {
_ = try callback.call(global, .js_undefined, &.{ .null, JSValue.jsNumber(0) });
return .js_undefined;
}
const ctx: JobCtx = .{
.value = buf_value,
.bytes = buf.slice().ptr,
.offset = offset,
.length = size,
};
try Job.initAndSchedule(global, callback, &ctx);
return .js_undefined;
}
};
fn pbkdf2(globalThis: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) bun.JSError!JSC.JSValue {
const data = try PBKDF2.fromJS(globalThis, callFrame, true);
const job = PBKDF2.Job.create(JSC.VirtualMachine.get(), globalThis, &data);
return job.promise.value();
}
fn pbkdf2Sync(globalThis: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) bun.JSError!JSC.JSValue {
var data = try PBKDF2.fromJS(globalThis, callFrame, false);
defer data.deinit();
var out_arraybuffer = JSC.JSValue.createBufferFromLength(globalThis, @intCast(data.length));
if (out_arraybuffer == .zero or globalThis.hasException()) {
data.deinit();
return .zero;
}
const output = out_arraybuffer.asArrayBuffer(globalThis) orelse {
data.deinit();
return globalThis.throwOutOfMemory();
};
if (!data.run(output.slice())) {
const err = Crypto.createCryptoError(globalThis, BoringSSL.ERR_get_error());
BoringSSL.ERR_clear_error();
return globalThis.throwValue(err);
}
return out_arraybuffer;
}
pub fn timingSafeEqual(global: *JSGlobalObject, callFrame: *JSC.CallFrame) JSError!JSValue {
const l_value, const r_value = callFrame.argumentsAsArray(2);
const l_buf = l_value.asArrayBuffer(global) orelse {
return global.ERR(.INVALID_ARG_TYPE, "The \"buf1\" argument must be an instance of ArrayBuffer, Buffer, TypedArray, or DataView.", .{}).throw();
};
const l = l_buf.byteSlice();
const r_buf = r_value.asArrayBuffer(global) orelse {
return global.ERR(.INVALID_ARG_TYPE, "The \"buf2\" argument must be an instance of ArrayBuffer, Buffer, TypedArray, or DataView.", .{}).throw();
};
const r = r_buf.byteSlice();
if (l.len != r.len) {
return global.ERR(.CRYPTO_TIMING_SAFE_EQUAL_LENGTH, "Input buffers must have the same byte length", .{}).throw();
}
return JSC.jsBoolean(BoringSSL.CRYPTO_memcmp(l.ptr, r.ptr, l.len) == 0);
}
pub fn secureHeapUsed(_: *JSGlobalObject, _: *JSC.CallFrame) JSError!JSValue {
return .js_undefined;
}
pub fn getFips(_: *JSGlobalObject, _: *JSC.CallFrame) JSError!JSValue {
return JSValue.jsNumber(0);
}
pub fn setFips(_: *JSGlobalObject, _: *JSC.CallFrame) JSError!JSValue {
return .js_undefined;
}
pub fn setEngine(global: *JSGlobalObject, _: *JSC.CallFrame) JSError!JSValue {
return global.ERR(.CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED, "Custom engines not supported by BoringSSL", .{}).throw();
}
fn forEachHash(_: *const BoringSSL.EVP_MD, maybe_from: ?[*:0]const u8, _: ?[*:0]const u8, ctx: *anyopaque) callconv(.c) void {
const from = maybe_from orelse return;
const hashes: *bun.CaseInsensitiveASCIIStringArrayHashMap(void) = @alignCast(@ptrCast(ctx));
hashes.put(bun.span(from), {}) catch bun.outOfMemory();
}
fn getHashes(global: *JSGlobalObject, _: *JSC.CallFrame) JSError!JSValue {
var hashes: bun.CaseInsensitiveASCIIStringArrayHashMap(void) = .init(bun.default_allocator);
defer hashes.deinit();
// TODO(dylan-conway): cache the names
BoringSSL.EVP_MD_do_all_sorted(&forEachHash, @alignCast(@ptrCast(&hashes)));
const array = try JSValue.createEmptyArray(global, hashes.count());
for (hashes.keys(), 0..) |hash, i| {
const str = String.createUTF8ForJS(global, hash);
try array.putIndex(global, @intCast(i), str);
}
return array;
}
const Scrypt = struct {
password: Node.StringOrBuffer,
salt: Node.StringOrBuffer,
N: u32,
r: u32,
p: u32,
maxmem: u64,
keylen: u32,
// used in async mode
buf: JSC.Strong.Optional = .empty,
result: []u8 = &.{},
err: ?u32 = null,
const Job = CryptoJob(Scrypt);
pub fn fromJS(global: *JSGlobalObject, callFrame: *JSC.CallFrame, comptime is_async: bool) JSError!if (is_async) struct { @This(), JSValue } else @This() {
const password_value, const salt_value, const keylen_value, var maybe_options_value: ?JSValue, var callback =
callFrame.argumentsAsArray(5);
if (is_async) {
if (callback.isUndefined()) {
callback = maybe_options_value.?;
maybe_options_value = null;
}
}
const password = try Node.StringOrBuffer.fromJSMaybeAsync(global, bun.default_allocator, password_value, is_async, true) orelse {
return global.throwInvalidArgumentTypeValue("password", "string, ArrayBuffer, Buffer, TypedArray, or DataView", password_value);
};
errdefer password.deinit();
const salt = try Node.StringOrBuffer.fromJSMaybeAsync(global, bun.default_allocator, salt_value, is_async, true) orelse {
return global.throwInvalidArgumentTypeValue("salt", "string, ArrayBuffer, Buffer, TypedArray, or DataView", salt_value);
};
errdefer salt.deinit();
const keylen = try validators.validateInt32(global, keylen_value, "keylen", .{}, 0, null);
var N: ?u32 = null;
var r: ?u32 = null;
var p: ?u32 = null;
var maxmem: ?i64 = null;
if (maybe_options_value) |options_value| {
if (options_value.getObject()) |options| {
if (try options.get(global, "N")) |N_value| {
N = try validators.validateUint32(global, N_value, "N", .{}, false);
}
if (try options.get(global, "cost")) |cost_value| {
if (N != null) {
return global.throwIncompatibleOptionPair("N", "cost");
}
N = try validators.validateUint32(global, cost_value, "cost", .{}, false);
}
if (try options.get(global, "r")) |r_value| {
r = try validators.validateUint32(global, r_value, "r", .{}, false);
}
if (try options.get(global, "blockSize")) |blocksize_value| {
if (r != null) {
return global.throwIncompatibleOptionPair("r", "blockSize");
}
r = try validators.validateUint32(global, blocksize_value, "blockSize", .{}, false);
}
if (try options.get(global, "p")) |p_value| {
p = try validators.validateUint32(global, p_value, "p", .{}, false);
}
if (try options.get(global, "parallelization")) |parallelization_value| {
if (p != null) {
return global.throwIncompatibleOptionPair("p", "parallelization");
}
p = try validators.validateUint32(global, parallelization_value, "parallelization", .{}, false);
}
if (try options.get(global, "maxmem")) |maxmem_value| {
maxmem = try validators.validateInteger(global, maxmem_value, "maxmem", 0, null);
}
}
}
const N_default: u32 = 16384;
const r_default: u32 = 8;
const p_default: u32 = 1;
const maxmem_default: i64 = 33554432;
if (N == null or N.? == 0) {
N = N_default;
}
if (r == null or r.? == 0) {
r = r_default;
}
if (p == null or p.? == 0) {
p = p_default;
}
if (maxmem == null or maxmem.? == 0) {
maxmem = maxmem_default;
}
const ctx: Scrypt = .{
.password = password,
.salt = salt,
.N = N.?,
.r = r.?,
.p = p.?,
.maxmem = @intCast(maxmem.?),
.keylen = @intCast(keylen),
};
if (is_async) {
_ = try validators.validateFunction(global, "callback", callback);
}
try ctx.checkScryptParams(global);
if (is_async) {
return .{ ctx, callback };
}
return ctx;
}
fn checkScryptParams(this: *const Scrypt, global: *JSGlobalObject) JSError!void {
const N = this.N;
const r = this.r;
const p = this.p;
const maxmem = this.maxmem;
if (BoringSSL.EVP_PBE_validate_scrypt_params(
null,
0,
null,
0,
N,
r,
p,
maxmem,
null,
0,
) == 0) {
return global.throwInvalidScryptParams();
}
}
fn init(this: *Scrypt, global: *JSGlobalObject) JSError!void {
const buf, const bytes = try JSC.ArrayBuffer.alloc(global, .ArrayBuffer, this.keylen);
// to be filled in later
this.result = bytes;
this.buf = .create(buf, global);
}
fn runTask(this: *Scrypt, key: []u8) void {
const password = this.password.slice();
const salt = this.salt.slice();
if (key.len == 0) {
// result will be an empty buffer
return;
}
if (password.len > std.math.maxInt(i32) or salt.len > std.math.maxInt(i32)) {
this.err = 0;
return;
}
const res = BoringSSL.EVP_PBE_scrypt(
password.ptr,
password.len,
salt.ptr,
salt.len,
this.N,
this.r,
this.p,
this.maxmem,
key.ptr,
key.len,
);
if (res == 0) {
this.err = BoringSSL.ERR_peek_last_error();
return;
}
}
fn runFromJS(this: *Scrypt, global: *JSGlobalObject, callback: JSValue) void {
const vm = global.bunVM();
if (this.err) |err| {
if (err != 0) {
var buf: [256]u8 = undefined;
const msg = BoringSSL.ERR_error_string_n(err, &buf, buf.len);
const exception = global.ERR(.CRYPTO_OPERATION_FAILED, "Scrypt failed: {s}", .{msg}).toJS();
vm.eventLoop().runCallback(callback, global, .js_undefined, &.{exception});
return;
}
const exception = global.ERR(.CRYPTO_OPERATION_FAILED, "Scrypt failed", .{}).toJS();
vm.eventLoop().runCallback(callback, global, .js_undefined, &.{exception});
return;
}
const buf = this.buf.swap();
vm.eventLoop().runCallback(callback, global, .js_undefined, &.{ .js_undefined, buf });
}
fn deinit(this: *Scrypt) void {
this.buf.deinit();
}
};
fn scrypt(global: *JSGlobalObject, callFrame: *JSC.CallFrame) JSError!JSValue {
const ctx, const callback = try Scrypt.fromJS(global, callFrame, true);
try Scrypt.Job.initAndSchedule(global, callback, &ctx);
return .js_undefined;
}
fn scryptSync(global: *JSGlobalObject, callFrame: *JSC.CallFrame) JSError!JSValue {
var ctx = try Scrypt.fromJS(global, callFrame, false);
const buf, const bytes = try JSC.ArrayBuffer.alloc(global, .ArrayBuffer, ctx.keylen);
ctx.runTask(bytes);
return buf;
}
pub fn createNodeCryptoBindingZig(global: *JSC.JSGlobalObject) JSC.JSValue {
const crypto = JSC.JSValue.createEmptyObject(global, 15);
crypto.put(global, String.init("pbkdf2"), JSC.JSFunction.create(global, "pbkdf2", pbkdf2, 5, .{}));
crypto.put(global, String.init("pbkdf2Sync"), JSC.JSFunction.create(global, "pbkdf2Sync", pbkdf2Sync, 5, .{}));
crypto.put(global, String.init("randomInt"), JSC.JSFunction.create(global, "randomInt", random.randomInt, 2, .{}));
crypto.put(global, String.init("randomFill"), JSC.JSFunction.create(global, "randomFill", random.randomFill, 4, .{}));
crypto.put(global, String.init("randomFillSync"), JSC.JSFunction.create(global, "randomFillSync", random.randomFillSync, 3, .{}));
crypto.put(global, String.init("randomUUID"), JSC.JSFunction.create(global, "randomUUID", random.randomUUID, 1, .{}));
crypto.put(global, String.init("randomBytes"), JSC.JSFunction.create(global, "randomBytes", random.randomBytes, 2, .{}));
crypto.put(global, String.init("timingSafeEqual"), JSC.JSFunction.create(global, "timingSafeEqual", timingSafeEqual, 2, .{}));
crypto.put(global, String.init("secureHeapUsed"), JSC.JSFunction.create(global, "secureHeapUsed", secureHeapUsed, 0, .{}));
crypto.put(global, String.init("getFips"), JSC.JSFunction.create(global, "getFips", getFips, 0, .{}));
crypto.put(global, String.init("setFips"), JSC.JSFunction.create(global, "setFips", setFips, 1, .{}));
crypto.put(global, String.init("setEngine"), JSC.JSFunction.create(global, "setEngine", setEngine, 2, .{}));
crypto.put(global, String.init("getHashes"), JSC.JSFunction.create(global, "getHashes", getHashes, 0, .{}));
crypto.put(global, String.init("scrypt"), JSC.JSFunction.create(global, "scrypt", scrypt, 5, .{}));
crypto.put(global, String.init("scryptSync"), JSC.JSFunction.create(global, "scryptSync", scryptSync, 4, .{}));
return crypto;
}