Git Product home page Git Product logo

js-nacl's Introduction

js-nacl: Pure-Javascript High-level API to Emscripten-compiled libsodium routines

A high-level Javascript API wrapping an Emscripten-compiled libsodium, a cryptographic library based on NaCl. Includes both in-browser and node.js support.

The paper "The security impact of a new cryptographic library" is an excellent summary of the motivation behind the NaCl API and library design.

Using this library in the browser requires support for the newish window.crypto.getRandomValues API.

WARNING: This code will not run in Safari version 5.1.x; or, at least, will not run when Safari's Javascript debug mode is disabled. Symptoms include corruption during hash calculation, failures when unboxing, and failures when producing and verifying signatures. Safari 7.0 seems to be just fine, however. I don't know exactly at which version Safari started working: I don't have access to enough of a range of systems. The code has run fine on Chrome and Firefox across all the versions I've tried.

Changes

Version 1.4.0: Updated from libsodium stable-2018-11-19 to 1.0.18-stable.

Version 1.3.2: The Emscripten-compiled code is now configured so that it no longer adds a listener to the uncaughtException when running in node.js. See issue #46.

Version 1.3.1: Correct a minor packaging error.

Version 1.3.0: Updated from libsodium 1.0.11 to stable-2018-11-19. Added crypto_box_seal and crypto_box_seal_open. Switched from using the Emscripten SDK to using a Dockerized Emscripten to produce the built version of the library. Because this enables WASM by default, the approach to handling of requested_total_memory is now different; see below.

Version 1.2.2: Updated from libsodium 1.0.10 to 1.0.11.

Version 1.2.1: Repaired a mistake where I had failed to export the new names crypto_sign_seed_keypair and crypto_box_seed_keypair.

Version 1.2.0: js-nacl is now based around libsodium rather than the plain NaCl tarball. Functions crypto_sign_keypair_from_seed and crypto_box_keypair_from_seed have been renamed to their libsodium names, crypto_sign_seed_keypair and crypto_box_seed_keypair respectively; the old names are still available as aliases, though deprecated, to be removed in a future version.

Version 1.1.0: API change. The nacl_factory.instantiate function now expects a callback as its first argument. It calls the callback with the nacl instance containing the API functions, and returns no useful value.

Version 0.5.0: API change. Instead of being provided with a module nacl, with API functions available directly, library importers are given nacl_factory with a single function instantiate, which returns a nacl instance containing the API functions.

NPM Package

This library is registered on npmjs.org. To install it:

npm install js-nacl

Building the library

The git checkout includes a pre-compiled version of the library, so you won't need Emscripten unless you want to change something about the underlying C-language library itself.

Essentially, the source checkout contains everything you will need to use the library in both the browser and in node.js.

If you do find yourself wanting to build the library, see the instructions in BUILDING.md.

Using the library

In the browser, include the lib/nacl_factory.js script:

<script src="lib/nacl_factory.js"></script>
...
<script>
  nacl_factory.instantiate(function (nacl) {
    alert(nacl.to_hex(nacl.random_bytes(16)));
  });
</script>

In node.js, require the lib/nacl_factory.js module:

var nacl_factory = require("./lib/nacl_factory.js");
nacl_factory.instantiate(function (nacl) {
  ...
  console.log(nacl.to_hex(nacl.random_bytes(16)));
});

Or if you have installed the library via npm,

var nacl_factory = require("js-nacl");
nacl_factory.instantiate(function (nacl) {
  ...
  console.log(nacl.to_hex(nacl.random_bytes(16)));
});

In addition, since version 1.3.0, the instantiate function returns a Promise that yields the nacl object.

Instantiating the NaCl module

Pass nacl_factory.instantiate a callback function expecting a single argument, the nacl module instance.

The nacl_factory.instantiate function expects also a second optional argument, a dictionary of optional configuration values.

Each call to nacl_factory.instantiate() creates an entirely fresh module instance, complete with its own private heap area. Since v1.3.0: The heap should automatically grow as required, and should no longer require manual ahead-of-time configuration.

It's fine to instantiate the module more than once in a single program, though beware of the large amount of memory potentially taken up by each instance. The memory assigned to each module instance will not be released until the instance is garbage collected.

If you notice memory leaks across multiple uses of a single module instance, please report them, with a test case if at all possible.

Strings vs. Binary Data

The library enforces a strict distinction between strings and binary data. Binary data is represented using instances of Uint8Array.

nacl.to_hex(Uint8Array) → String

Returns a lower-case hexadecimal representation of the given binary data.

nacl.from_hex(String) → Uint8Array

Converts a lower- or upper-case hexadecimal representation of binary data into the equivalent Uint8Array.

nacl.encode_utf8(String) → Uint8Array

Returns the binary equivalent of the argument, encoded using UTF-8.

nacl.encode_latin1(String) → Uint8Array

Returns the binary equivalent of the argument, encoded using Latin1 (an 8-bit clean encoding). If any of the character codes in the argument string are greater than 255, an exception is thrown.

nacl.decode_utf8(Uint8Array) → String

Decodes the binary data in the argument using the UTF-8 encoding, producing the corresponding string.

nacl.decode_latin1(Uint8Array) → String

Decodes the binary data in the argument using the Latin1 8-bit clean encoding, producing the corresponding string.

Hashing: crypto_hash

Follows the NaCl crypto_hash API.

nacl.crypto_hash(Uint8Array) → Uint8Array

Computes the SHA-512 hash of its argument.

While SHA-512 is recommended, the SHA-256 function is also available, as nacl.crypto\_hash\_sha256.

nacl.crypto_hash_string(String) → Uint8Array

Encodes its argument using nacl.encode_utf8, and then calls crypto_hash.

Public-key authenticated encryption: crypto_box

Follows the NaCl crypto_box API.

You do not need to perform any padding of any arguments to these functions; the API given here is most similar to the "C++" API in the NaCl documentation.

Make sure to follow the instructions regarding nonce selection given in the "Security model" section of the NaCl API documentation!

senderKeypair = nacl.crypto_box_keypair();
recipientKeypair = nacl.crypto_box_keypair();
message = nacl.encode_utf8("Hello!");

nonce = nacl.crypto_box_random_nonce();
packet = nacl.crypto_box(message, nonce, recipientKeypair.boxPk, senderKeypair.boxSk);

decoded = nacl.crypto_box_open(packet, nonce, senderKeypair.boxPk, recipientKeypair.boxSk);

"Hello!" === nacl.decode_utf8(decoded); // always true

nacl.crypto_box_keypair() → {"boxPk": Uint8Array, "boxSk": Uint8Array}

Creates a fresh random keypair. boxPk is the public key and boxSk is the secret key.

nacl.crypto_box_random_nonce() → Uint8Array

Returns a fresh randomly-chosen nonce suitable for use with crypto_box.

nacl.crypto_box(msgBin, nonceBin, recipientPublicKeyBin, senderSecretKeyBin) → Uint8Array

Places msg in an authenticated, encrypted box that can only be verified and decrypted by the secret key corresponding to recipientPublicKey.

nacl.crypto_box_open(ciphertextBin, nonceBin, senderPublicKeyBin, recipientSecretKeyBin) → Uint8Array

Verifies and decrypts a box from crypto_box. Throws an exception if the verification fails or any of the inputs are invalid.

nacl.crypto_box_precompute(publicKeyBin, secretKeyBin) → {"boxK": Uint8Array}

Precomputes a shared secret between two parties. See the documentation for crypto_box_beforenm at the NaCl website.

nacl.crypto_box_precomputed(msgBin, nonceBin, {"boxK": Uint8Array}) → Uint8Array
nacl.crypto_box_open_precomputed(ciphertextBin, nonceBin, {"boxK": Uint8Array}) → Uint8Array

Precomputed-secret variants of crypto_box and crypto_box_open.

Secret-key authenticated encryption: crypto_secretbox

Follows the NaCl crypto_secretbox API.

You do not need to perform any padding of any arguments to these functions; the API given here is most similar to the "C++" API in the NaCl documentation.

Make sure to follow the instructions regarding nonce selection given in the "Security model" section of the NaCl API documentation!

k = ...;
m = nacl.encode_utf8("message");
n = nacl.crypto_secretbox_random_nonce();
c = nacl.crypto_secretbox(m, n, k);
m1 = nacl.crypto_secretbox_open(c, n, k);
"message" === nacl.decode_utf8(m1); // always true

nacl.crypto_secretbox_random_nonce() → Uint8Array

Returns a fresh randomly-chosen nonce suitable for use with crypto_secretbox.

nacl.crypto_secretbox(msgBin, nonceBin, keyBin) → Uint8Array

Places msg in an authenticated, encrypted box that can only be verified and decrypted by someone who knows keyBin. The keyBin Uint8Array must be nacl.crypto_secretbox_KEYBYTES bytes long.

nacl.crypto_secretbox_open(ciphertextBin, nonceBin, keyBin) → Uint8Array

Verifies and decrypts a packet from crypto_secretbox. Throws an exception if the verification fails or any of the inputs are invalid.

Anonymous authenticated encryption: crypto_box_seal

Uses a freshly-created ephemeral box keypair to send an "anonymous" message to a specific recipient, who is identified by their public box key, and who may decrypt the message using the matching box keypair.

nacl.crypto_box_seal(msgBin, recipientPublicKeyBin) → Uint8Array

Places msgBin in an authenticated, encrypted box that can only be verified and decrypted by the secret key corresponding to recipientPublicKeyBin.

nacl.crypto_box_seal_open(ciphertextBin, recipientPublicKeyBin, recipientSecretKeyBin) → Uint8Array

Verifies and decrypts a box from crypto_box_seal. Throws an exception if the verification fails or any of the inputs are invalid. Unlike crypto_box_open, no nonce is required, and the recipient's public key is supplied instead of the sender's. The sender remains anonymous.

Secret-key encryption: crypto_stream

Follows the NaCl crypto_stream API.

Make sure to follow the instructions regarding nonce selection given in the "Security model" section of the NaCl API documentation!

Since this style of secret-key encryption is symmetric, nacl.crypto_stream_xor is suitable for decryption as well as encryption:

k = ...;
m = nacl.encode_utf8("message");
n = nacl.crypto_stream_random_nonce();
c = nacl.crypto_stream_xor(m, n, k);
m1 = nacl.crypto_stream_xor(c, n, k);
"message" === nacl.decode_utf8(m1); // always true

nacl.crypto_stream_random_nonce() → Uint8Array

Returns a fresh randomly-chosen nonce suitable for use with crypto_stream.

nacl.crypto_stream(lenInt, nonceBin, keyBin) → Uint8Array

Returns a lenInt-byte length keystream based on the given nonce and key. The key must be nacl.crypto_stream_KEYBYTES bytes long.

nacl.crypto_stream_xor(msgBin, nonceBin, keyBin) → Uint8Array

Returns msgBin.length bytes of ciphertext (or plaintext, depending on the contents of msgBin) produced by XORing msgBin with the result of nacl.crypto_stream(msgBin.length, nonceBin, keyBin).

Secret-key single-message authentication: crypto_onetimeauth

Follows the NaCl crypto_onetimeauth API.

Secret-key message authentication: crypto_auth

Follows the NaCl crypto_auth API.

Signatures: crypto_sign

Follows the NaCl crypto_sign API.

Note that this uses the version of Ed25519 from SUPERCOP, and not the old prototype implementation from the nacl 20110221 release.

The SUPERCOP Ed25519 signature scheme used is compatible with libsodium and most other bindings and wrappers of libsodium and nacl.

nacl.crypto_sign_keypair() → {"signPk": Uint8Array, "signSk": Uint8Array}

Creates a fresh random keypair. signPk is the public key and signSk is the secret key.

k = nacl.crypto_sign_keypair();
m = nacl.encode_utf8("message");
signed_m = nacl.crypto_sign(m, k.signSk);
m1 = nacl.crypto_sign_open(signed_m, k.signPk);
"message" === nacl.decode_utf8(m1); // always true

nacl.crypto_sign(msgBin, signerSecretKey) → Uint8Array

Produces a signature-wrapped version of msgBin.

nacl.crypto_sign_open(packetBin, signerPublicKey) → (Uint8Array || null)

Verifies the signature on the given packetBin, and if it is valid, extracts the carried message and returns it. If the signature could not be verified, returns null.

nacl.crypto_sign_detached(msgBin, signerSecretKey) → Uint8Array

WARNING: Experimental. Produces a "detached" signature that, unlike crypto_sign, excludes the actual message body. The result can be used with crypto_sign_verify_detached.

The returned detached signature will be nacl.crypto_sign_BYTES in length.

nacl.crypto_sign_verify_detached(detachedSignatureBin, msgBin, signerPublicKey) → (true || false)

WARNING: Experimental. Given a "detached" signature from crypto_sign_detached, along with the original message and the signer's public signing key, returns true if the signature is valid, and false otherwise.

Derived Keys

WARNING: Experimental

If you see yourself wanting to use these, you will need to know why PBKDF2 and scrypt are of crucial importance.

You might like to explore the use of these functions in tandem with scrypt.crypto_scrypt from js-scrypt.

It is not generally safe to supply (for example) a user's passphrase directly to these procedures without using PBKDF2, scrypt or something similar beforehand.

nacl.crypto_sign_seed_keypair(Uint8Array) → {"signPk": Uint8Array, "signSk": Uint8Array}

Produces a signing keypair from its argument. A given binary input will always produce the same keypair as output.

The input must be 32 bytes long. As Brian Warner puts it, "Ed25519 keys start life as a 32-byte (256-bit) uniformly random binary seed" such as might be produced by sha256, or better yet, PBKDF2 or scrypt.

Make sure to read and understand the warnings relating to passphrases, PBKDF2 and scrypt at the beginning of this section.

Compatible with PyNaCl's crypto_sign_keypair_fromseed and racl's bytes->crypto-sign-keypair.

(Prior to v1.2.0, known as nacl.crypto_sign_keypair_from_seed.)

nacl.crypto_box_seed_keypair(Uint8Array) → {"boxPk": Uint8Array, "boxSk": Uint8Array}

Produces an encrypted authenticated box keypair from its argument. A given binary input will always produce the same keypair as output.

The input may be of any length. The input is hashed once with sha512, and the first 32 bytes of the result are taken as the 32-byte secret key, which is then passed to nacl.crypto_box_keypair_from_raw_sk.

Make sure to read and understand the warnings relating to passphrases, PBKDF2 and scrypt at the beginning of this section.

Compatible with racl's bytes->crypto-box-keypair.

(Prior to v1.2.0, known as nacl.crypto_box_keypair_from_seed.)

nacl.crypto_box_keypair_from_raw_sk(Uint8Array) → {"boxPk": Uint8Array, "boxSk": Uint8Array}

Produces an encrypted authenticated box keypair from its argument. A given binary input will always produce the same keypair as output.

The input must be 32 bytes long, and could be a random 32-byte value, or the output of sha256, or better yet, the output of PBKDF2 or scrypt.

Make sure to read and understand the warnings relating to passphrases, PBKDF2 and scrypt at the beginning of this section.

Compatible with racl's crypto-box-sk->pk.

Low-level tools

nacl.crypto_scalarmult(Uint8Array, Uint8Array) → Uint8Array

Expects two binaries, the first of length nacl.crypto_scalarmult_SCALARBYTES (representing an integer), and the second of length nacl.crypto_scalarmult_BYTES (representing a group element). The two are multiplied using the underlying NaCl crypto_scalarmult primitive, and the resulting nacl.crypto_scalarmult_BYTES-length group element binary is returned.

nacl.crypto_scalarmult_base(Uint8Array) → Uint8Array

As nacl.crypto_scalarmult, but multiplies the nacl.crypto_scalarmult_SCALARBYTES-length argument by a standard group element, returning the result.

License

js-nacl is written by Tony Garnock-Jones [email protected] and is licensed under the MIT license:

Copyright © 2013-2018 Tony Garnock-Jones.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

js-nacl relies on libsodium, which is released under the ISC license:

Copyright (c) 2013-2018 Frank Denis

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

libsodium in turn relies on NaCl itself, which is public domain code by Daniel J. Bernstein and others.

js-nacl's People

Contributors

graydon avatar nl5887 avatar pgorsira avatar tanx avatar tonyg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

js-nacl's Issues

decode_utf8 throwing errors

I have the following code to encrypt and decrypt messages, storing the nonce and encrypted message in localStorage between. (note: the generateSalt() and generateHashKey(..) use PBKDF2 to take a user's password and create a hash suitable as the encryption/decryption key)

function encrypt(user,pw,data) {
    var nonce, salt, key;

    salt = generateSalt();
    key = generateHashKey(salt, pw);

    nonce = nacl.crypto_secretbox_random_nonce();
    data = nacl.encode_utf8(data);
    key = nacl.encode_utf8(key);
    data = nacl.crypto_secretbox(data,nonce,key);

    data = JSON.stringify({
        salt: salt,
        nonce: Array.apply([],nonce),
        data: Array.apply([],data)
    });

    localStorage.setItem(user,data);
}

function decrypt(user,pw) {
    var data = JSON.parse(localStorage.getItem(user)), nonce, salt, key;

    salt = data.salt;
    key = generateHashKey(salt, key);

    nonce = new Uint8Array(data.nonce);
    data = new Uint8Array(data.data);
    key = nacl.encode_utf8(key);
    data = nacl.crypto_secretbox_open(data,nonce,key);
    data = nacl.decode_utf8(data);

    return data;
}

encrypt("foo", "bar", "hello world");
decrypt("foo", "bar"); // "hello world"

So, first... sanity check... am I doing this correctly? I feel like I am, but I have had to piece a few things together from the documentation, so a confirmation would be appreciated. :)


Next, to the topic of my bug report... you'l notice that in this code, I'm storing both the nonce and the encrypted message as basic arrays (from their Uint8Array wrappers), which is a terribly inefficient way to do so (since it's being converted to a string via JSON.stringify(..)).

However, the docs make it seem like I should have been able to do this, on the encrypt side:

data = JSON.stringify({
    salt: salt,
    nonce: nacl.decode_utf8(nonce),
    data: nacl.decode_utf8(data)
});

... so that what's being stored is a utf8-encoded string, rather than an array of numbers. Then, on the decrypt side, it seems like I should have been able to:

nonce = nacl.encode_utf8(data.nonce);
data = nacl.encode_utf8(data.data);

However, the nacl.decode_utf8(nonce) call fails immediately, with an error about "URIError: URI malformed" from its usage of decodeURIComponent(..).

What am I missing? The docs seem to indicate those decode/encode functions should go safely from Uint8Array -> String and String -> Uint8Array, respectively.

eval used in library?

I have a CSP on my site which does not allow eval(), and trying to use nacl, I get errors thrown indicating the nacl library is trying to use it. What's the reason behind that? Is there anyway around it without just basically opening up a big hole in my CSP?

sealed box fail

First of all, congratulations of the work. Perfect compatibility between JS / PHP5.6 for crypto_box/crypto_secretbox/crypto_scalarmult.

About crypto_box_seal I checked that do not have the function implementation, but _crypto_box_seal exists mapped.

Unfortunately the implementation I made always returns the error in the _crypto_box_seal_open call.

"nacl_raw._crypto_box_seal_open signalled an error"

Sometimes it still displays error when calling _crypto_box_seal.

"Uncaught abort () at Error"

Below the implementation made:

nacl_factory.js

      return m.extractBytes(nacl_raw._crypto_box_zerobytes());//32
    }
    
    function crypto_box_seal(msg, pk) {
      var m = injectBytes(msg, nacl_raw._crypto_box_zerobytes());
      var pka = check_injectBytes("crypto_box_seal", "pk", pk, nacl_raw._crypto_box_publickeybytes());
      var c = new Target(msg.length + nacl_raw._crypto_box_sealbytes());
      check("_crypto_box_seal", nacl_raw._crypto_box_seal(c.address, m, c.length, 0, pka));
      free_all([c, m, pka]);
      return c.extractBytes(nacl_raw._crypto_box_boxzerobytes());
    }

    function crypto_box_seal_open(ciphertext, pk, sk) {
      var c = injectBytes(ciphertext, nacl_raw._crypto_box_boxzerobytes());
      var pka = check_injectBytes("crypto_box_seal_open",
                                  "pk", pk, nacl_raw._crypto_box_publickeybytes());
      var ska = check_injectBytes("crypto_box_seal_open",
                                  "sk", sk, nacl_raw._crypto_box_secretkeybytes());
      var m = new Target(ciphertext.length + nacl_raw._crypto_box_boxzerobytes());
      check("_crypto_box_seal_open", nacl_raw._crypto_box_seal_open(m.address, c, m.length, 0, pka, ska));
      free_all([c, pka, ska, m]);
      return m.extractBytes(nacl_raw._crypto_box_zerobytes());
    }

    function crypto_box_precompute(pk, sk) {
      var pka = check_injectBytes("crypto_box_precompute",

nacl_factory.js

    exports.crypto_box_open = crypto_box_open;
    exports.crypto_box_seal = crypto_box_seal;
    exports.crypto_box_seal_open = crypto_box_seal_open;
    exports.crypto_box_precompute = crypto_box_precompute;

index.html

            nacl_factory.instantiate(function (nacl) {

                var alice_sk = nacl.crypto_box_keypair();
                
                //crypto_box_seal
                var message = 'test 123';
                var d1 = new Date();
                var encryptedBoxSeal = nacl.crypto_box_seal(nacl.encode_utf8(message), alice_sk.boxPk);
                var d2 = new Date();
                var time = d2 - d1;
                console.log(time + "ms\t encryptedBoxSeal \t=> " + nacl.to_hex(encryptedBoxSeal));
                
                //crypto_box_seal_open
                d1 = new Date();
                var dencryptedBoxSeal = nacl.crypto_box_seal_open(encryptedBoxSeal, alice_sk.boxPk, alice_sk.boxSk);
                d2 = new Date();
                time = d2 - d1;
                console.log(time + "ms\t dencryptedBoxSeal \t=> " + nacl.to_hex(dencryptedBoxSeal));
            });

Is it possible to implement _crypto_box_seal and _crypto_box_seal_open in nacl_factory.js?
Where his my error in the codes?

Are the sizes in bytes for m/pka/c/extractBytes(_crypto_box_seal) and for c/pka/ska/m/extractBytes(_crypto_box_seal_open) applied correctly?

Doesn't build with the latest emscripten

I would like to build js-nacl with the latest emscripten to make use of the asm.js output.

Using the HEAD of master branch of emscripten first gave this error:

Assertion failed: Cannot grow asm.js heap

I turned off ALLOW_MEMORY_GROWTH in the Makefile, and then got this error:

python `which emcc` \
    -s LINKABLE=1 \
    -s EXPORTED_FUNCTIONS="$(cat subnacl/naclexports.sh)" \
    -s ALLOW_MEMORY_GROWTH=0 \
    --js-library nacl_randombytes_emscripten.js \
    --post-js subnacl/naclapi.js \
    -O1 --closure 1 -o nacl_raw.js \
    -I subnacl/include \
    keys.c \
    $(find subnacl -name '*.c')

undefined:374
        throw 'Invalid token, cannot triage: ' + dump(item);
                                               ^
Invalid token, cannot triage: // {
//   "tokens": [
//     {
//       "text": "attributes"
//     },
//     {
//       "text": "#0"
//     },
//     {
//       "text": "="
//     },
//     {
//       "text": "{ nounwind\"less-precise-fpmad\"=\"false\"\"no-frame-pointer-elim\"=\"true\"\"no-frame-pointer-elim-non-leaf\"=\"true\"\"no-infs-fp-math\"=\"false\"\"no-nans-fp-math\"=\"false\"\"unsafe-fp-math\"=\"false\"\"use-soft-float\"=\"false\" }",
//       "tokens": [
//         {
//           "text": "nounwind"
//         },
//         {
//           "text": "\"less-precise-fpmad\""
//         },
//         {
//           "text": "="
//         },
//         {
//           "text": "\"false\""
//         },
//         {
//           "text": "\"no-frame-pointer-elim\""
//         },
//         {
//           "text": "="
//         },
//         {
//           "text": "\"true\""
//         },
//         {
//           "text": "\"no-frame-pointer-elim-non-leaf\""
//         },
//         {
//           "text": "="
//         },
//         {
//           "text": "\"true\""
//         },
//         {
//           "text": "\"no-infs-fp-math\""
//         },
//         {
//           "text": "="
//         },
//         {
//           "text": "\"false\""
//         },
//         {
//           "text": "\"no-nans-fp-math\""
//         },
//         {
//           "text": "="
//         },
//         {
//           "text": "\"false\""
//         },
//         {
//           "text": "\"unsafe-fp-math\""
//         },
//         {
//           "text": "="
//         },
//         {
//           "text": "\"false\""
//         },
//         {
//           "text": "\"use-soft-float\""
//         },
//         {
//           "text": "="
//         },
//         {
//           "text": "\"false\""
//         }
//       ],
//       "type": "{"
//     }
//   ],
//   "indent": 0,
//   "lineNum": 641,
//   "__uid__": 17
// }
Traceback (most recent call last):
  File "/home/nlacasse/opal/emscripten/emscripten.py", line 853, in <module>
    _main(environ=os.environ)
  File "/home/nlacasse/opal/emscripten/emscripten.py", line 841, in _main
    temp_files.run_and_clean(lambda: main(
  File "/home/nlacasse/opal/emscripten/tools/tempfiles.py", line 38, in run_and_clean
    return func()
  File "/home/nlacasse/opal/emscripten/emscripten.py", line 849, in <lambda>
    DEBUG_CACHE=DEBUG_CACHE,
  File "/home/nlacasse/opal/emscripten/emscripten.py", line 735, in main
    jcache=jcache, temp_files=temp_files, DEBUG=DEBUG, DEBUG_CACHE=DEBUG_CACHE)
  File "/home/nlacasse/opal/emscripten/emscripten.py", line 184, in emscript
    assert '//FORWARDED_DATA:' in out, 'Did not receive forwarded data in pre output - process failed?'
AssertionError: Did not receive forwarded data in pre output - process failed?
Traceback (most recent call last):
  File "/home/nlacasse/bin/emcc", line 1505, in <module>
    final = shared.Building.emscripten(final, append_ext=False, extra_args=extra_args)
  File "/home/nlacasse/opal/emscripten/tools/shared.py", line 1096, in emscripten
    assert os.path.exists(filename + '.o.js') and len(open(filename + '.o.js', 'r').read()) > 0, 'Emscripten failed to generate .js: ' + str(compiler_output)
AssertionError: Emscripten failed to generate .js: 
make: *** [nacl_raw.js] Error 1

Newbie question on using the factory

I would like to use js-nacl in a Quasar/Vue project but struggle a bit with the factory callback instantiation. What I would like to do is:

createHashHex: function (myString) {
  var naclFactory = require('js-nacl')
  var nacl
  naclFactory.instantiate(function (naclInstance) {
    nacl = naclInstance
  })
  let pwHashArray = nacl.crypto_hash_string(myString)
  let pwHashHex = nacl.to_hex(pwHashArray)
  return pwHashHex
}

But that does not work. How do I correctly instantiate the stuff without using the inline notation in the docs?

Cheers,
Michael

Change sk and pk suffixes

I appreciate that the sk and pk suffixes are used for consistency with the nacl documentation however I think there might be a risk that new developers will think 'sk' equates to 'shared key' and 'pk' equates to 'private key' (contrary to the documentation). This feels relevant given that one of the goals of nacl (as I understand it) is to reduce the impact of inexperienced developers using crypto.

key size configurable?

It doesn't appear obvious from the docs or the code that there's a way to configure the key-size expected for nacl.crypto_secretbox(..). Is that correct, or did I miss something?

It appears the default is 32-characters. Does this correspond to 256-bits or 512-bits? Can we configure the key length, to say 1024-bits or 2048-bits?

TypeError in Firefox 40.0.3

Hi,
Im implementing your lib right now for another project but in my Firefox 40.0.3 I get the following error:

TypeError: invalid arguments
nacl_raw.HEAPU8.set(bs, address + p);
nacl_factory.js (Line 26009)

I tested the the same in Chrome and everything seems to work there. I added below a small test script to help to reproduce the error.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>TEST</title>

    <!-- NaCl, SCrypt and sha512 are mandatory -->
    <script src="libs/js-nacl/lib/nacl_factory.js" type="text/javascript"></script>

    <script>
        var nacl = nacl_factory.instantiate();
    </script>
</head>
<body>

    <script>
        function test (secret, password) {

            var k = nacl.crypto_hash_sha256(password);
            var m = nacl.encode_utf8(secret);
            var n = nacl.crypto_secretbox_random_nonce();
            var c = nacl.crypto_secretbox(m, n, k);

            return {
                nonce: nacl.to_hex(n),
                ciphertext: nacl.to_hex(c)
            }
        }

        console.log(test("mySecret", "myPassword"));
    </script>

</body>
</html>

Thanks in advance and thanks for that nice lib.

reduce the size?

The current size of the produced nacl.js is > !Mb. It would be interesting to reduce its size so it can be easily used on the web. Maybe the --compression arg of emscripten could help here?

Publish node.js module in npm registry

To get more traction, it may be interesting to publish the module in the npm registry. This allows people to simply type "npm install js-nacl" to install your module for their project.

The code is then discoverable here, which should increase usage/testing/contributions:
https://npmjs.org

I would gladly take care of it, but only you can add your own github repo. A good tutorial can be found here:
http://www.hacksparrow.com/create-npm-package-node-js-module.html

Which files need to be hosted?

Hello @tonyg ,
I am the member of cdnjs project.
We want to host this library.

I saw many files about nacl like nacl_raw.js, nacl_cooked.js, lib/nacl_factory.js, etc on npm package.
Which files do you want to host or all of above or the others I didn't mention?
Thanks for your help!

cdnjs/cdnjs#7995

Documentation unclear on which interface is provided

The documentation is not clear which interface is provided, the C or C++. This is a concern as some functions, like crypto_secretbox, differ between C and C++. The C api requiring user padding but not the C++ api.

Looking at nacl_cooked.js it looks like the C++ api conventions are expected but I have not check all functions.

Which NaCl implementation is implemented in js-nacl?

Tony,

Can't say how much I appreciate your work! It's incredibly fast and easy to use!

I'm trying to determine how the library is intended to act based upon which implementation NaCl implemented.

Have you implemented Ref10, amd64-64-24k, or amd64-51-30k?

Thank you so very much in advance!

Uncaught TypeError: Cannot read property 'length' of undefined nacl_factory.js:26036

Tony!

I can't thank you enough for adding this feature!

I wanted to simply append this to our last thread, but it wouldn't let me reopen.

I downloaded it and tried, but it gives the error in the title.

It only occurs with nacl.crypto_sign_verify_detached, so nacl.crypto_sign_detached seems to be working as expected as I get 256 bits returned, quickly verified with my Base64 encoder.

Again, I can't thank you enough for this, and I bet your quick feature addition probably sets a record for implementation time!

make TOTAL_MEMORY configurable.

Make TOTAL_MEMORY configurable. As a side-effect, this will permit complete garbage-collection and rebooting of the module as a page runs.

"Typed arrays 2 must be run on a little-endian system"

Hello, I'm getting a strange error with minimal code:

nacl_factory.instantiate(function(nacl) {
  // literally do nothing
});

Which gives me this error:

This is on firefox 46.0.1 on linux kernel 4.4.0-22, ubuntu 16.04. Am I doing something wrong here? I'm running this on a traditional x86_64 machine, it isn't likely something unweildy. But, now that I recognize it, this is a version installed from bower; maybe it installed an old version somehow?

import fails with error about inability to resolve 'fs'

[Solution: The problem is apparently a bug in Webpack, and a suggested workaround (from here via this comment from @balinskia) is to 'add the following to your Webpack config: node: { fs: "empty" }'. Original bug report text follows.]


All I did was:

import NaCl from 'js-nacl';

which resulted in:

web_1         | ERROR in ./~/js-nacl/lib/nacl_factory.js
web_1         | Module not found: Error: Can't resolve 'fs' in '/src/app/node_modules/js-nacl/lib'
web_1         |  @ ./~/js-nacl/lib/nacl_factory.js 27:1242-1255
web_1         |  @ ./js/actions/identity/config.js
web_1         |  @ ./js/reducers/identity/config.js
web_1         |  @ ./js/reducers/identity/index.js
web_1         |  @ ./js/reducers/index.js
web_1         |  @ ./js/redux-store.js
web_1         |  @ ./js/main.js
web_1         |  @ multi (webpack)-dev-server/client?http://0.0.0.0:4000 webpack/hot/dev-server ./js/main.js
web_1         | webpack: Failed to compile.

this is a react app. :-\

here is a link to the file:

https://github.com/NullVoxPopuli/tanqueReact/blob/c95a968c6e2ec84c5c17c3eddd134d2b553acdc2/js/actions/identity/config.js#L4

Expose Argon2 password derivation

The README (very correctly) notes that you should not derive a key without running it through a strengthening function like PBKDF2, but libsodium itself already ships with one—Argon2. From brief inspection, it seems that the nacl_raw property (the WASM code?) contains this functionality, e.g. nacl_raw._crypto_pwhash_argon2id_alg_argon2id13 et al.

I’d love to create a PR, but having no experience with WASM-compiled code, I worry that a half-baked PR is more likely to either be a nuisance or a security hole; looking at nacl_cooked.js, I am guessing it isn’t a very big task…for someone who knows what they’re doing, which (alas) I here do not.

Any chance of exposing the Argon2 API?

No updates in 3 years?

Would you still recommend to use this project, or has it been made obsolete?

(Sorry for the very dumb question, as a total outsider looking in, I really don't know!)

Many thanks,
Dan.

Multithreading support

Sorry for all the github issues, but I've got some time today. I've been checking out the generated emscripten code and I noticed the following functions:

Module.onFullScreen
checks
document.webkitFullScreenElement

and

Module.requestAnimationFrame
checks
window.requestAnimationFrame

I would guess, that those Module functions are hooks for potential GUI use-cases for an emscripten module, but I don't think they are relevant for a crypto library. The problem is that in order for multithreading to work inside the browser (via WebWorker), a script can't reference either 'window' or 'document' as they aren't thread-safe. The details can be read here:
http://www.html5rocks.com/en/tutorials/workers/basics/

Question: is there any way to remove the Module functions by changing emscripten arguments? I could just remove those manually by hand before closure minifies the scripts, but that would not be very automation friendly. Thanks

Emscripten Buildsteps

I really like how you're using Typed Arrays for all binary data. None of the JS-crypto libraries I've used does this (crypto-js, sjcl, OpenPGP.js).

I looked through the Makefile and README.md and there seems to be no documented steps on how to build js-nacl from the NaCl src with emscripten. It's probably trivial, but would be very helpful to get started. Thanks.

Tankred

newbie question: password -> key

I'm trying to encrypt a user's nacl private key with a passphrase using nacl.crypto_secretbox, I'm unsure how I'm supposed to turn a password/passphrase into a valid key for secretbox.

thanks!

Type inconsistency with latest version

I tried installing the package via NPM, but I could see that while the package is at version 1.3.2, the types are at version 1.3.0.

I don't know if that is related or not, but the types do not expose the sealed box functions for anonymous encryption.

Types in documentation don't match actual types

Hello,
it seems to me, that some of the (not all) functions do not actually return Uint8Arrays but Buffers, resulting in checks like nacl.random_bytes(16) instanceof Uint8Array failing (nacl.crypto_hash(nacl.random_bytes(16)) instanceof Uint8Array passes fine).
There are some parts of my application, where I rely on the objects actually being of type Uint8Array. It would be nice, if the documentation would more clearly reflect, where Uint8Array is to be expected, and where Buffers are.

Thanks in advance!
r

Reevaluate libsodium

Hi,

Do you plan on reevaluting using libsodium instead of NaCL. The community is gathering around it. There is much more activity. Another thing I really like is that they improve on some issues with the original API. I hate the thing about adding / removing zerobytes manually. They added crypto_box_easy crypto_secretbox_easy which simply wraps that operation so you don't forget / make mistakes.

https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_box/crypto_box_easy.c

Thanks,

Library throws error in Google Chrome

Running this library in google chrome, the following error gets thrown:

failed to asynchronously prepare wasm: CompileError: WebAssembly Instantiation: Wasm code generation disallowed by embedder

This seems related to our content security policy (which is strict):
https://stackoverflow.com/questions/48523118/wasm-module-compile-error-in-chrome-extension

We cannot put 'unsafe-eval' on our script-src for obvious reasons.

Any insights as to what is going wrong and how it can be fixed?

pk from sk

tonyg!

Your lib is so awesome! I was working away immediately after you gave those two new functions. Thank you so much!

For my implementation, a signing key needs to be known, and the public key needs to be created from that.

Is that what nacl.crypto_box_keypair_from_raw_sk does? If not, could I trouble you for another feature request, that the pk can be returned from the sk?

Thank you so much in advance and for this amazing library!

uncaughtException event being handled in nacl_factory.js

The uncaughtException event is being handled here: https://github.com/tonyg/js-nacl/blob/master/lib/nacl_factory.js#L27 - It checks if the error is of a specific type and if not, it re-throws the error which then crashes the process.

This causes problems if a project has its own uncaughtException handler which tries to handle the uncaughtException in a different way (e.g. in node.js, we may want to exit after some delay instead of immediately).

How to only output signature with nacl.crypto_sign and take only signature as message argument with nacl.crypto_sign_open?

tonyg, I love your lib!

For my implementation, I need just a slight change.

I am transmitting raw data along with the signature, and the signature is produced from sha512ing the raw data; therefore, I don't need the signature to include the hash.

Is there any way to have nacl.crypto_sign output only the signature without the message?

If so, is there a way to have nacl.crypto_sign_open only take the signature and not signature & hash as the message argument?

If the answer to both is "no", where is the message in the nacl.crypto_sign output, so I can manually remove it and add it?

Thank you so very much in advance and for such a great lib!

Crosspost: http://stackoverflow.com/questions/21941957/how-to-split-a-uint8array
and http://crypto.stackexchange.com/questions/14633/how-does-js-nacl-combine-the-message-and-signature-for-nacl-crypto-sign

new function crypto_sign_seed_keypair is not exported

Hi,

In lib/nacl_factory.js, only old deprecated function crypto_sign_keypair_from_seed is exported, so we must call this deprecated function :-(
Could you add :

    exports.crypto_sign_seed_keypair = crypto_sign_seed_keypair;
    exports.crypto_box_seed_keypair = crypto_box_seed_keypair;

Thanks for your great job 👍

Browser benchmarks

This is not an issue really but wanted to let you know I copied over your benchmarks to http://jsperf.com/js-nacl

On a project I am working on we have seen some issues in safari using nacl.crypto_secretbox() on larger chunks of data (greater than 4mb) so I will be adding that to the tests on jsperf. If there is any other functions that should have a test let me know, I am happy to add them.

Is this library still maintained?

Hi @tonyg, I'm currently trying to tidy up the bindings linked on the libsodium website. If this library is still maintained, then please let me know; otherwise, the link to this library will likely be removed from the bindings page to help users find up to date and maintained bindings.

Does not work in browser

I was happy to read this line in the README

"Essentially, the source checkout contains everything you will need to use the library in both the browser and in node.js."

So I uploaded the entire checkout into a webserver and loaded runner.html from the test folder

Sadly, it gives these errors. I am a newbie at cryptography

runner.html:1 Refused to apply style from 'https://abcxyz.com/nacl/node_modules/mocha/mocha.css' because its MIME type ('text/plain') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
runner.html:11 GET https://abcxyz.com/nacl/node_modules/mocha/mocha.js net::ERR_ABORTED 404
runner.html:1 Refused to execute script from 'https://abcxyz.com/nacl/node_modules/mocha/mocha.js' because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.
runner.html:12 Uncaught TypeError: mocha.setup is not a function
    at runner.html:12
(anonymous) @ runner.html:12
runner.html:39 Uncaught TypeError: Cannot read property 'emit' of undefined
    at nacl_factory.instantiate.memoryInitializerPrefixURL (runner.html:39)
    at nacl_factory.js:577
    at Object.instantiate (nacl_factory.js:581)
    at runner.html:37

Please support

Please help js-nacl be widely available trough jsdelivr CDN and many others :)


    Vote for at https://jsdelivr.uservoice.com/forums/164147-plugins-submission/suggestions/5061662-js-nacl-https-github-com-tonyg-js-nacl

    Please someone send a pull request to cdnjs CDN https://github.com/cdnjs/cdnjs

lets spread the word ! :)

newbie question

Hi TonyG
In my php I'm using sodium_bin2hex(sodium_crypto_box_publickey(sodium_crypto_box_keypair())) which I pass to the javascript:
bpkeypair='';
nacl_factory.instantiate(function(nacl){
akeypair=nacl.crypto_box_keypair();
message=nacl.encode_utf8(msg);
nonce=nacl.crypto_box_random_nonce();
});
nacl_factory.instantiate(function(acl){
ctext=acl.crypto_box(message,nonce,bpkeypair,akeypair.boxSk);
n2h=acl.to_hex(nonce);
});

when I pass "cipher text" and the "nonce to hex" back to php through ajax and try to decrypt the message using:
$jsnonce=sodium_hex2bin($n2h);
$keydc=$keysk.$pk;
$text=sodium_crypto_box_open($ctext,$jsnonce,$keydc);

I get this error:
Uncaught SodiumException: keypair size should be SODIUM_CRYPTO_BOX_KEYPAIRBYTES.

I'll attach the two files Im using to play around. Please help?
Thanks very much

test.docx
testrespoonse.docx

Key pair generation fails on IPhones

This problem was reported by all IPhone users of a certain website.
One specific user used IPhone XS Max and Safari browser.

I don't have an IPhone, so I can't test this.

Code (approximate) used in the website

function bufferToHex(buffer) {
    var s = '', h = '0123456789ABCDEF';
    (new Uint8Array(buffer)).forEach((v) => { s += h[v >> 4] + h[v & 15]; });
    return s;
}

function generateKeyPair() {
    var pass = 'some string';
    var salt = bufferToHex(nacl.random_bytes(32));
    var keyPair = null;

    try {
        keyPair = nacl.crypto_box_seed_keypair(pass + salt);
    } catch(err) {}

    if (keyPair){
        return {publicKey: keyPair.boxPk, privateKey: keyPair.boxSk};
    }

    return keyPair;
}

console.log(generateKeyPair()) // should not be null

generateKeyPair() returns null if it couldn't generate the key pair.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.