2

I am using a Javascript to generate wireguard keypairs but it's browser faced so i removed the window objects and have one more issue that prevents creation of private key.

the issue is this line of code that i cannot run in nodejs:

    function generatePresharedKey() {

var privateKey = new Uint8Array(32);
var crypto = require('crypto');
crypto.getRandomValues(privateKey);

                return privateKey;
        }

this is the error i get

crypto.getRandomValues(privateKey);
       ^

TypeError: crypto.getRandomValues is not a function

if i try to call getRandomValues using require it says that it cannot find module. var getRandomValues = require('get-random-values');

How to do i import it ? npm install get-random-values doesn't help.

any advice ?

fiddle here :

/*! SPDX-License-Identifier: GPL-2.0
 *
 * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
 */
function gf(init) {
                var r = new Float64Array(16);
                if (init) {
                        for (var i = 0; i < init.length; ++i)
                                r[i] = init[i];
                }
                return r;
        }

function pack(o, n) {
                var b, m = gf(), t = gf();
                for (var i = 0; i < 16; ++i)
                        t[i] = n[i];
                carry(t);
                carry(t);
                carry(t);
                for (var j = 0; j < 2; ++j) {
                        m[0] = t[0] - 0xffed;
                        for (var i = 1; i < 15; ++i) {
                                m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
                                m[i - 1] &= 0xffff;
                        }
                        m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
                        b = (m[15] >> 16) & 1;
                        m[14] &= 0xffff;
                        cswap(t, m, 1 - b);
                }
                for (var i = 0; i < 16; ++i) {
                        o[2 * i] = t[i] & 0xff;
                        o[2 * i + 1] = t[i] >> 8;
                }
        }


function carry(o) {
                var c;
                for (var i = 0; i < 16; ++i) {
                        o[(i + 1) % 16] += (i < 15 ? 1 : 38) * Math.floor(o[i] / 65536);
                        o[i] &= 0xffff;
                }
        }

function cswap(p, q, b) {
                var t, c = ~(b - 1);
                for (var i = 0; i < 16; ++i) {
                        t = c & (p[i] ^ q[i]);
                        p[i] ^= t;
                        q[i] ^= t;
                }
        }

function add(o, a, b) {
                for (var i = 0; i < 16; ++i)
                        o[i] = (a[i] + b[i]) | 0;
        }
function subtract(o, a, b) {
                for (var i = 0; i < 16; ++i)
                        o[i] = (a[i] - b[i]) | 0;
        }
function multmod(o, a, b) {
                var t = new Float64Array(31);
                for (var i = 0; i < 16; ++i) {
                        for (var j = 0; j < 16; ++j)
                                t[i + j] += a[i] * b[j];
                }
                for (var i = 0; i < 15; ++i)
                        t[i] += 38 * t[i + 16];
                for (var i = 0; i < 16; ++i)
                        o[i] = t[i];
                carry(o);
                carry(o);
        }
function invert(o, i) {
                var c = gf();
                for (var a = 0; a < 16; ++a)
                        c[a] = i[a];
                for (var a = 253; a >= 0; --a) {
                        multmod(c, c, c);
                        if (a !== 2 && a !== 4)
                                multmod(c, c, i);
                }
                for (var a = 0; a < 16; ++a)
                        o[a] = c[a];
        }
function clamp(z) {
                z[31] = (z[31] & 127) | 64;
                z[0] &= 248;
        }

function generatePublicKey(privateKey) {
                var r, z = new Uint8Array(32);
                var a = gf([1]),
                        b = gf([9]),
                        c = gf(),
                        d = gf([1]),
                        e = gf(),
                        f = gf(),
                        _121665 = gf([0xdb41, 1]),
                        _9 = gf([9]);
                for (var i = 0; i < 32; ++i)
                        z[i] = privateKey[i];
                clamp(z);
                for (var i = 254; i >= 0; --i) {
                        r = (z[i >>> 3] >>> (i & 7)) & 1;
                        cswap(a, b, r);
                        cswap(c, d, r);
                        add(e, a, c);
                        subtract(a, a, c);
                        add(c, b, d);
                        subtract(b, b, d);
                        multmod(d, e, e);
                        multmod(f, a, a);
                        multmod(a, c, a);
                        multmod(c, b, e);
                        add(e, a, c);
                        subtract(a, a, c);
                        multmod(b, a, a);
                        subtract(c, d, f);
                        multmod(a, c, _121665);
                        add(a, a, d);
                        multmod(c, c, a);
                        multmod(a, d, f);
                        multmod(d, b, _9);
                        multmod(b, e, e);
                        cswap(a, b, r);
                        cswap(c, d, r);
                }
                invert(c, c);
                multmod(a, a, c);
                pack(z, a);
                return z;
        }


function generatePresharedKey() {
                var privateKey = new Uint8Array(32);
//var crypto = require('crypto').randomBytes;
//var getRandomValues = require('get-random-values');
//crypto.getRandomValues(privateKey);
const webcrypto = require('crypto').webcrypto;
webcrypto.getRandomValues(privateKey);
                return privateKey;
        }

function generatePrivateKey() {
                var privateKey = generatePresharedKey();
                clamp(privateKey);
                return privateKey;
        }
 
function encodeBase64(dest, src) {
                var input = Uint8Array.from([(src[0] >> 2) & 63, ((src[0] << 4) | (src[1] >> 4)) & 63, ((src[1] << 2) | (src[2] >> 6)) & 63, src[2] & 63]);
                for (var i = 0; i < 4; ++i)
                        dest[i] = input[i] + 65 +
                        (((25 - input[i]) >> 8) & 6) -
                        (((51 - input[i]) >> 8) & 75) -
                        (((61 - input[i]) >> 8) & 15) +
                        (((62 - input[i]) >> 8) & 3);
        }

function keyToBase64(key) {
                var i, base64 = new Uint8Array(44);
                for (i = 0; i < 32 / 3; ++i)
                        encodeBase64(base64.subarray(i * 4), key.subarray(i * 3));
                encodeBase64(base64.subarray(i * 4), Uint8Array.from([key[i * 3 + 0], key[i * 3 + 1], 0]));
                base64[43] = 61;
                return String.fromCharCode.apply(null, base64);
        }


function generateKeypair() {
  var privateKey = generatePrivateKey();
  var publicKey = generatePublicKey(privateKey);
  return {
    publicKey: keyToBase64(publicKey),
    privateKey: keyToBase64(privateKey)
  };
}

function doSomething() {
        const   keypair = generateKeypair()
  var m = JSON.stringify(keypair)
 var op = JSON.parse(m)
  console.log(keypair)
 //console.log(op.publicKey)
  document.getElementById("demo").innerHTML =  op.publicKey + "</br>" +  op.privateKey;
   
}


doSomething();

3 Answers3

5

Class: Crypto

  • Added in: v15.0.0

Calling require('crypto').webcrypto returns an instance of the Crypto class. Crypto is a singleton that provides access to the remainder of the crypto API.

Example:

const privateKey = new Uint8Array(32);
const webcrypto = require('crypto').webcrypto;
webcrypto.getRandomValues(privateKey);

Result:

÷ÆVY{ñÕÓ»ÃVíA0²†xò¥x´ü^18

Lawrence Cherone
  • 46,049
  • 7
  • 62
  • 106
  • that was my though too at first, but i get : `TypeError: Cannot call method 'getRandomValues' of undefined` is there a solution for earlier versions ? – Alberto Valejo Sep 07 '21 at 13:57
  • How would one achieve this using the `import from` syntax? I would expect `import { webcrypto } from 'crypto';`, however I then get a TS compile error `Property 'getRandomValues' does not exist on type 'typeof webcrypto'` – devklick Jun 06 '22 at 08:06
3

You need to understand getRandomValues is on window.crypto that means it works on browser. To make it work on Node.js you need to install get-random-values

npm i get-random-values

In your module add this:

const getRandomValues = require('get-random-values'), 
      array = new Uint8Array(10);
getRandomValues(array);
console.log(getRandomValues(array));
Apoorva Chikara
  • 8,277
  • 3
  • 20
  • 35
  • tried that but i get `TypeError: Cannot call method 'getRandomValues' of undefined` but the variable for getrnadomvalues is proper as it would work with `crypto.randomBytes(privatekey.length)` – Alberto Valejo Sep 07 '21 at 14:15
  • Try running above code, I am getting the values. Check if this helps. – Apoorva Chikara Sep 07 '21 at 15:26
  • 1
    you were right , i am just newbie here, did not load the library properly . big thx !!! my second issue that needed to be solved, as it turned out, is removing from method from code as im forced to use an older node where this method is not available , and used `new` instead – Alberto Valejo Sep 08 '21 at 06:28
  • 2
    While this works, it doesnt seem right. `crypto.getRandomValues` works in a node-js terminal, so why would you have to install a third party library to access it in a node-js application? – devklick Jun 06 '22 at 07:59
  • The answers here are confusing to say the least if not plainly wrong! Using node-v16.13.1-x64 this works: const crypto = require('crypto'); salt = crypto.getRandomValues(new Uint8Array(16)); see: https://nodejs.org/api/webcrypto.html#cryptogetrandomvaluestypedarray – user2677034 Feb 01 '23 at 01:59
0

You do not need npm i get-random-values in order to use webcrypto.getRandomValues

If you are trying to use webcrypto with import from syntax in node.js, you need to import it (and can then use it) like so:

import { webcrypto } from "node:crypto";

/** scuffed example function */
function getRandomValue() {
    return webcrypto.getRandomValues(new Uint32Array(1))[0];
}

If you're using require() syntax, you instead need to require it (and can then use it) like so:

const { webcrypto } = require("crypto");

/** still scuffed example function */
function getRandomValue() {
  return webcrypto.getRandomValues(new Uint32Array(1))[0];
}
11belowstudio
  • 137
  • 11