[6a3a178] | 1 | TweetNaCl.js
|
---|
| 2 | ============
|
---|
| 3 |
|
---|
| 4 | Port of [TweetNaCl](http://tweetnacl.cr.yp.to) / [NaCl](http://nacl.cr.yp.to/)
|
---|
| 5 | to JavaScript for modern browsers and Node.js. Public domain.
|
---|
| 6 |
|
---|
| 7 | [![Build Status](https://travis-ci.org/dchest/tweetnacl-js.svg?branch=master)
|
---|
| 8 | ](https://travis-ci.org/dchest/tweetnacl-js)
|
---|
| 9 |
|
---|
| 10 | Demo: <https://tweetnacl.js.org>
|
---|
| 11 |
|
---|
| 12 | **:warning: The library is stable and API is frozen, however it has not been
|
---|
| 13 | independently reviewed. If you can help reviewing it, please [contact
|
---|
| 14 | me](mailto:dmitry@codingrobots.com).**
|
---|
| 15 |
|
---|
| 16 | Documentation
|
---|
| 17 | =============
|
---|
| 18 |
|
---|
| 19 | * [Overview](#overview)
|
---|
| 20 | * [Installation](#installation)
|
---|
| 21 | * [Usage](#usage)
|
---|
| 22 | * [Public-key authenticated encryption (box)](#public-key-authenticated-encryption-box)
|
---|
| 23 | * [Secret-key authenticated encryption (secretbox)](#secret-key-authenticated-encryption-secretbox)
|
---|
| 24 | * [Scalar multiplication](#scalar-multiplication)
|
---|
| 25 | * [Signatures](#signatures)
|
---|
| 26 | * [Hashing](#hashing)
|
---|
| 27 | * [Random bytes generation](#random-bytes-generation)
|
---|
| 28 | * [Constant-time comparison](#constant-time-comparison)
|
---|
| 29 | * [System requirements](#system-requirements)
|
---|
| 30 | * [Development and testing](#development-and-testing)
|
---|
| 31 | * [Benchmarks](#benchmarks)
|
---|
| 32 | * [Contributors](#contributors)
|
---|
| 33 | * [Who uses it](#who-uses-it)
|
---|
| 34 |
|
---|
| 35 |
|
---|
| 36 | Overview
|
---|
| 37 | --------
|
---|
| 38 |
|
---|
| 39 | The primary goal of this project is to produce a translation of TweetNaCl to
|
---|
| 40 | JavaScript which is as close as possible to the original C implementation, plus
|
---|
| 41 | a thin layer of idiomatic high-level API on top of it.
|
---|
| 42 |
|
---|
| 43 | There are two versions, you can use either of them:
|
---|
| 44 |
|
---|
| 45 | * `nacl.js` is the port of TweetNaCl with minimum differences from the
|
---|
| 46 | original + high-level API.
|
---|
| 47 |
|
---|
| 48 | * `nacl-fast.js` is like `nacl.js`, but with some functions replaced with
|
---|
| 49 | faster versions.
|
---|
| 50 |
|
---|
| 51 |
|
---|
| 52 | Installation
|
---|
| 53 | ------------
|
---|
| 54 |
|
---|
| 55 | You can install TweetNaCl.js via a package manager:
|
---|
| 56 |
|
---|
| 57 | [Bower](http://bower.io):
|
---|
| 58 |
|
---|
| 59 | $ bower install tweetnacl
|
---|
| 60 |
|
---|
| 61 | [NPM](https://www.npmjs.org/):
|
---|
| 62 |
|
---|
| 63 | $ npm install tweetnacl
|
---|
| 64 |
|
---|
| 65 | or [download source code](https://github.com/dchest/tweetnacl-js/releases).
|
---|
| 66 |
|
---|
| 67 |
|
---|
| 68 | Usage
|
---|
| 69 | -----
|
---|
| 70 |
|
---|
| 71 | All API functions accept and return bytes as `Uint8Array`s. If you need to
|
---|
| 72 | encode or decode strings, use functions from
|
---|
| 73 | <https://github.com/dchest/tweetnacl-util-js> or one of the more robust codec
|
---|
| 74 | packages.
|
---|
| 75 |
|
---|
| 76 | In Node.js v4 and later `Buffer` objects are backed by `Uint8Array`s, so you
|
---|
| 77 | can freely pass them to TweetNaCl.js functions as arguments. The returned
|
---|
| 78 | objects are still `Uint8Array`s, so if you need `Buffer`s, you'll have to
|
---|
| 79 | convert them manually; make sure to convert using copying: `new Buffer(array)`,
|
---|
| 80 | instead of sharing: `new Buffer(array.buffer)`, because some functions return
|
---|
| 81 | subarrays of their buffers.
|
---|
| 82 |
|
---|
| 83 |
|
---|
| 84 | ### Public-key authenticated encryption (box)
|
---|
| 85 |
|
---|
| 86 | Implements *curve25519-xsalsa20-poly1305*.
|
---|
| 87 |
|
---|
| 88 | #### nacl.box.keyPair()
|
---|
| 89 |
|
---|
| 90 | Generates a new random key pair for box and returns it as an object with
|
---|
| 91 | `publicKey` and `secretKey` members:
|
---|
| 92 |
|
---|
| 93 | {
|
---|
| 94 | publicKey: ..., // Uint8Array with 32-byte public key
|
---|
| 95 | secretKey: ... // Uint8Array with 32-byte secret key
|
---|
| 96 | }
|
---|
| 97 |
|
---|
| 98 |
|
---|
| 99 | #### nacl.box.keyPair.fromSecretKey(secretKey)
|
---|
| 100 |
|
---|
| 101 | Returns a key pair for box with public key corresponding to the given secret
|
---|
| 102 | key.
|
---|
| 103 |
|
---|
| 104 | #### nacl.box(message, nonce, theirPublicKey, mySecretKey)
|
---|
| 105 |
|
---|
| 106 | Encrypt and authenticates message using peer's public key, our secret key, and
|
---|
| 107 | the given nonce, which must be unique for each distinct message for a key pair.
|
---|
| 108 |
|
---|
| 109 | Returns an encrypted and authenticated message, which is
|
---|
| 110 | `nacl.box.overheadLength` longer than the original message.
|
---|
| 111 |
|
---|
| 112 | #### nacl.box.open(box, nonce, theirPublicKey, mySecretKey)
|
---|
| 113 |
|
---|
| 114 | Authenticates and decrypts the given box with peer's public key, our secret
|
---|
| 115 | key, and the given nonce.
|
---|
| 116 |
|
---|
| 117 | Returns the original message, or `false` if authentication fails.
|
---|
| 118 |
|
---|
| 119 | #### nacl.box.before(theirPublicKey, mySecretKey)
|
---|
| 120 |
|
---|
| 121 | Returns a precomputed shared key which can be used in `nacl.box.after` and
|
---|
| 122 | `nacl.box.open.after`.
|
---|
| 123 |
|
---|
| 124 | #### nacl.box.after(message, nonce, sharedKey)
|
---|
| 125 |
|
---|
| 126 | Same as `nacl.box`, but uses a shared key precomputed with `nacl.box.before`.
|
---|
| 127 |
|
---|
| 128 | #### nacl.box.open.after(box, nonce, sharedKey)
|
---|
| 129 |
|
---|
| 130 | Same as `nacl.box.open`, but uses a shared key precomputed with `nacl.box.before`.
|
---|
| 131 |
|
---|
| 132 | #### nacl.box.publicKeyLength = 32
|
---|
| 133 |
|
---|
| 134 | Length of public key in bytes.
|
---|
| 135 |
|
---|
| 136 | #### nacl.box.secretKeyLength = 32
|
---|
| 137 |
|
---|
| 138 | Length of secret key in bytes.
|
---|
| 139 |
|
---|
| 140 | #### nacl.box.sharedKeyLength = 32
|
---|
| 141 |
|
---|
| 142 | Length of precomputed shared key in bytes.
|
---|
| 143 |
|
---|
| 144 | #### nacl.box.nonceLength = 24
|
---|
| 145 |
|
---|
| 146 | Length of nonce in bytes.
|
---|
| 147 |
|
---|
| 148 | #### nacl.box.overheadLength = 16
|
---|
| 149 |
|
---|
| 150 | Length of overhead added to box compared to original message.
|
---|
| 151 |
|
---|
| 152 |
|
---|
| 153 | ### Secret-key authenticated encryption (secretbox)
|
---|
| 154 |
|
---|
| 155 | Implements *xsalsa20-poly1305*.
|
---|
| 156 |
|
---|
| 157 | #### nacl.secretbox(message, nonce, key)
|
---|
| 158 |
|
---|
| 159 | Encrypt and authenticates message using the key and the nonce. The nonce must
|
---|
| 160 | be unique for each distinct message for this key.
|
---|
| 161 |
|
---|
| 162 | Returns an encrypted and authenticated message, which is
|
---|
| 163 | `nacl.secretbox.overheadLength` longer than the original message.
|
---|
| 164 |
|
---|
| 165 | #### nacl.secretbox.open(box, nonce, key)
|
---|
| 166 |
|
---|
| 167 | Authenticates and decrypts the given secret box using the key and the nonce.
|
---|
| 168 |
|
---|
| 169 | Returns the original message, or `false` if authentication fails.
|
---|
| 170 |
|
---|
| 171 | #### nacl.secretbox.keyLength = 32
|
---|
| 172 |
|
---|
| 173 | Length of key in bytes.
|
---|
| 174 |
|
---|
| 175 | #### nacl.secretbox.nonceLength = 24
|
---|
| 176 |
|
---|
| 177 | Length of nonce in bytes.
|
---|
| 178 |
|
---|
| 179 | #### nacl.secretbox.overheadLength = 16
|
---|
| 180 |
|
---|
| 181 | Length of overhead added to secret box compared to original message.
|
---|
| 182 |
|
---|
| 183 |
|
---|
| 184 | ### Scalar multiplication
|
---|
| 185 |
|
---|
| 186 | Implements *curve25519*.
|
---|
| 187 |
|
---|
| 188 | #### nacl.scalarMult(n, p)
|
---|
| 189 |
|
---|
| 190 | Multiplies an integer `n` by a group element `p` and returns the resulting
|
---|
| 191 | group element.
|
---|
| 192 |
|
---|
| 193 | #### nacl.scalarMult.base(n)
|
---|
| 194 |
|
---|
| 195 | Multiplies an integer `n` by a standard group element and returns the resulting
|
---|
| 196 | group element.
|
---|
| 197 |
|
---|
| 198 | #### nacl.scalarMult.scalarLength = 32
|
---|
| 199 |
|
---|
| 200 | Length of scalar in bytes.
|
---|
| 201 |
|
---|
| 202 | #### nacl.scalarMult.groupElementLength = 32
|
---|
| 203 |
|
---|
| 204 | Length of group element in bytes.
|
---|
| 205 |
|
---|
| 206 |
|
---|
| 207 | ### Signatures
|
---|
| 208 |
|
---|
| 209 | Implements [ed25519](http://ed25519.cr.yp.to).
|
---|
| 210 |
|
---|
| 211 | #### nacl.sign.keyPair()
|
---|
| 212 |
|
---|
| 213 | Generates new random key pair for signing and returns it as an object with
|
---|
| 214 | `publicKey` and `secretKey` members:
|
---|
| 215 |
|
---|
| 216 | {
|
---|
| 217 | publicKey: ..., // Uint8Array with 32-byte public key
|
---|
| 218 | secretKey: ... // Uint8Array with 64-byte secret key
|
---|
| 219 | }
|
---|
| 220 |
|
---|
| 221 | #### nacl.sign.keyPair.fromSecretKey(secretKey)
|
---|
| 222 |
|
---|
| 223 | Returns a signing key pair with public key corresponding to the given
|
---|
| 224 | 64-byte secret key. The secret key must have been generated by
|
---|
| 225 | `nacl.sign.keyPair` or `nacl.sign.keyPair.fromSeed`.
|
---|
| 226 |
|
---|
| 227 | #### nacl.sign.keyPair.fromSeed(seed)
|
---|
| 228 |
|
---|
| 229 | Returns a new signing key pair generated deterministically from a 32-byte seed.
|
---|
| 230 | The seed must contain enough entropy to be secure. This method is not
|
---|
| 231 | recommended for general use: instead, use `nacl.sign.keyPair` to generate a new
|
---|
| 232 | key pair from a random seed.
|
---|
| 233 |
|
---|
| 234 | #### nacl.sign(message, secretKey)
|
---|
| 235 |
|
---|
| 236 | Signs the message using the secret key and returns a signed message.
|
---|
| 237 |
|
---|
| 238 | #### nacl.sign.open(signedMessage, publicKey)
|
---|
| 239 |
|
---|
| 240 | Verifies the signed message and returns the message without signature.
|
---|
| 241 |
|
---|
| 242 | Returns `null` if verification failed.
|
---|
| 243 |
|
---|
| 244 | #### nacl.sign.detached(message, secretKey)
|
---|
| 245 |
|
---|
| 246 | Signs the message using the secret key and returns a signature.
|
---|
| 247 |
|
---|
| 248 | #### nacl.sign.detached.verify(message, signature, publicKey)
|
---|
| 249 |
|
---|
| 250 | Verifies the signature for the message and returns `true` if verification
|
---|
| 251 | succeeded or `false` if it failed.
|
---|
| 252 |
|
---|
| 253 | #### nacl.sign.publicKeyLength = 32
|
---|
| 254 |
|
---|
| 255 | Length of signing public key in bytes.
|
---|
| 256 |
|
---|
| 257 | #### nacl.sign.secretKeyLength = 64
|
---|
| 258 |
|
---|
| 259 | Length of signing secret key in bytes.
|
---|
| 260 |
|
---|
| 261 | #### nacl.sign.seedLength = 32
|
---|
| 262 |
|
---|
| 263 | Length of seed for `nacl.sign.keyPair.fromSeed` in bytes.
|
---|
| 264 |
|
---|
| 265 | #### nacl.sign.signatureLength = 64
|
---|
| 266 |
|
---|
| 267 | Length of signature in bytes.
|
---|
| 268 |
|
---|
| 269 |
|
---|
| 270 | ### Hashing
|
---|
| 271 |
|
---|
| 272 | Implements *SHA-512*.
|
---|
| 273 |
|
---|
| 274 | #### nacl.hash(message)
|
---|
| 275 |
|
---|
| 276 | Returns SHA-512 hash of the message.
|
---|
| 277 |
|
---|
| 278 | #### nacl.hash.hashLength = 64
|
---|
| 279 |
|
---|
| 280 | Length of hash in bytes.
|
---|
| 281 |
|
---|
| 282 |
|
---|
| 283 | ### Random bytes generation
|
---|
| 284 |
|
---|
| 285 | #### nacl.randomBytes(length)
|
---|
| 286 |
|
---|
| 287 | Returns a `Uint8Array` of the given length containing random bytes of
|
---|
| 288 | cryptographic quality.
|
---|
| 289 |
|
---|
| 290 | **Implementation note**
|
---|
| 291 |
|
---|
| 292 | TweetNaCl.js uses the following methods to generate random bytes,
|
---|
| 293 | depending on the platform it runs on:
|
---|
| 294 |
|
---|
| 295 | * `window.crypto.getRandomValues` (WebCrypto standard)
|
---|
| 296 | * `window.msCrypto.getRandomValues` (Internet Explorer 11)
|
---|
| 297 | * `crypto.randomBytes` (Node.js)
|
---|
| 298 |
|
---|
| 299 | If the platform doesn't provide a suitable PRNG, the following functions,
|
---|
| 300 | which require random numbers, will throw exception:
|
---|
| 301 |
|
---|
| 302 | * `nacl.randomBytes`
|
---|
| 303 | * `nacl.box.keyPair`
|
---|
| 304 | * `nacl.sign.keyPair`
|
---|
| 305 |
|
---|
| 306 | Other functions are deterministic and will continue working.
|
---|
| 307 |
|
---|
| 308 | If a platform you are targeting doesn't implement secure random number
|
---|
| 309 | generator, but you somehow have a cryptographically-strong source of entropy
|
---|
| 310 | (not `Math.random`!), and you know what you are doing, you can plug it into
|
---|
| 311 | TweetNaCl.js like this:
|
---|
| 312 |
|
---|
| 313 | nacl.setPRNG(function(x, n) {
|
---|
| 314 | // ... copy n random bytes into x ...
|
---|
| 315 | });
|
---|
| 316 |
|
---|
| 317 | Note that `nacl.setPRNG` *completely replaces* internal random byte generator
|
---|
| 318 | with the one provided.
|
---|
| 319 |
|
---|
| 320 |
|
---|
| 321 | ### Constant-time comparison
|
---|
| 322 |
|
---|
| 323 | #### nacl.verify(x, y)
|
---|
| 324 |
|
---|
| 325 | Compares `x` and `y` in constant time and returns `true` if their lengths are
|
---|
| 326 | non-zero and equal, and their contents are equal.
|
---|
| 327 |
|
---|
| 328 | Returns `false` if either of the arguments has zero length, or arguments have
|
---|
| 329 | different lengths, or their contents differ.
|
---|
| 330 |
|
---|
| 331 |
|
---|
| 332 | System requirements
|
---|
| 333 | -------------------
|
---|
| 334 |
|
---|
| 335 | TweetNaCl.js supports modern browsers that have a cryptographically secure
|
---|
| 336 | pseudorandom number generator and typed arrays, including the latest versions
|
---|
| 337 | of:
|
---|
| 338 |
|
---|
| 339 | * Chrome
|
---|
| 340 | * Firefox
|
---|
| 341 | * Safari (Mac, iOS)
|
---|
| 342 | * Internet Explorer 11
|
---|
| 343 |
|
---|
| 344 | Other systems:
|
---|
| 345 |
|
---|
| 346 | * Node.js
|
---|
| 347 |
|
---|
| 348 |
|
---|
| 349 | Development and testing
|
---|
| 350 | ------------------------
|
---|
| 351 |
|
---|
| 352 | Install NPM modules needed for development:
|
---|
| 353 |
|
---|
| 354 | $ npm install
|
---|
| 355 |
|
---|
| 356 | To build minified versions:
|
---|
| 357 |
|
---|
| 358 | $ npm run build
|
---|
| 359 |
|
---|
| 360 | Tests use minified version, so make sure to rebuild it every time you change
|
---|
| 361 | `nacl.js` or `nacl-fast.js`.
|
---|
| 362 |
|
---|
| 363 | ### Testing
|
---|
| 364 |
|
---|
| 365 | To run tests in Node.js:
|
---|
| 366 |
|
---|
| 367 | $ npm run test-node
|
---|
| 368 |
|
---|
| 369 | By default all tests described here work on `nacl.min.js`. To test other
|
---|
| 370 | versions, set environment variable `NACL_SRC` to the file name you want to test.
|
---|
| 371 | For example, the following command will test fast minified version:
|
---|
| 372 |
|
---|
| 373 | $ NACL_SRC=nacl-fast.min.js npm run test-node
|
---|
| 374 |
|
---|
| 375 | To run full suite of tests in Node.js, including comparing outputs of
|
---|
| 376 | JavaScript port to outputs of the original C version:
|
---|
| 377 |
|
---|
| 378 | $ npm run test-node-all
|
---|
| 379 |
|
---|
| 380 | To prepare tests for browsers:
|
---|
| 381 |
|
---|
| 382 | $ npm run build-test-browser
|
---|
| 383 |
|
---|
| 384 | and then open `test/browser/test.html` (or `test/browser/test-fast.html`) to
|
---|
| 385 | run them.
|
---|
| 386 |
|
---|
| 387 | To run headless browser tests with `tape-run` (powered by Electron):
|
---|
| 388 |
|
---|
| 389 | $ npm run test-browser
|
---|
| 390 |
|
---|
| 391 | (If you get `Error: spawn ENOENT`, install *xvfb*: `sudo apt-get install xvfb`.)
|
---|
| 392 |
|
---|
| 393 | To run tests in both Node and Electron:
|
---|
| 394 |
|
---|
| 395 | $ npm test
|
---|
| 396 |
|
---|
| 397 | ### Benchmarking
|
---|
| 398 |
|
---|
| 399 | To run benchmarks in Node.js:
|
---|
| 400 |
|
---|
| 401 | $ npm run bench
|
---|
| 402 | $ NACL_SRC=nacl-fast.min.js npm run bench
|
---|
| 403 |
|
---|
| 404 | To run benchmarks in a browser, open `test/benchmark/bench.html` (or
|
---|
| 405 | `test/benchmark/bench-fast.html`).
|
---|
| 406 |
|
---|
| 407 |
|
---|
| 408 | Benchmarks
|
---|
| 409 | ----------
|
---|
| 410 |
|
---|
| 411 | For reference, here are benchmarks from MacBook Pro (Retina, 13-inch, Mid 2014)
|
---|
| 412 | laptop with 2.6 GHz Intel Core i5 CPU (Intel) in Chrome 53/OS X and Xiaomi Redmi
|
---|
| 413 | Note 3 smartphone with 1.8 GHz Qualcomm Snapdragon 650 64-bit CPU (ARM) in
|
---|
| 414 | Chrome 52/Android:
|
---|
| 415 |
|
---|
| 416 | | | nacl.js Intel | nacl-fast.js Intel | nacl.js ARM | nacl-fast.js ARM |
|
---|
| 417 | | ------------- |:-------------:|:-------------------:|:-------------:|:-----------------:|
|
---|
| 418 | | salsa20 | 1.3 MB/s | 128 MB/s | 0.4 MB/s | 43 MB/s |
|
---|
| 419 | | poly1305 | 13 MB/s | 171 MB/s | 4 MB/s | 52 MB/s |
|
---|
| 420 | | hash | 4 MB/s | 34 MB/s | 0.9 MB/s | 12 MB/s |
|
---|
| 421 | | secretbox 1K | 1113 op/s | 57583 op/s | 334 op/s | 14227 op/s |
|
---|
| 422 | | box 1K | 145 op/s | 718 op/s | 37 op/s | 368 op/s |
|
---|
| 423 | | scalarMult | 171 op/s | 733 op/s | 56 op/s | 380 op/s |
|
---|
| 424 | | sign | 77 op/s | 200 op/s | 20 op/s | 61 op/s |
|
---|
| 425 | | sign.open | 39 op/s | 102 op/s | 11 op/s | 31 op/s |
|
---|
| 426 |
|
---|
| 427 | (You can run benchmarks on your devices by clicking on the links at the bottom
|
---|
| 428 | of the [home page](https://tweetnacl.js.org)).
|
---|
| 429 |
|
---|
| 430 | In short, with *nacl-fast.js* and 1024-byte messages you can expect to encrypt and
|
---|
| 431 | authenticate more than 57000 messages per second on a typical laptop or more than
|
---|
| 432 | 14000 messages per second on a $170 smartphone, sign about 200 and verify 100
|
---|
| 433 | messages per second on a laptop or 60 and 30 messages per second on a smartphone,
|
---|
| 434 | per CPU core (with Web Workers you can do these operations in parallel),
|
---|
| 435 | which is good enough for most applications.
|
---|
| 436 |
|
---|
| 437 |
|
---|
| 438 | Contributors
|
---|
| 439 | ------------
|
---|
| 440 |
|
---|
| 441 | See AUTHORS.md file.
|
---|
| 442 |
|
---|
| 443 |
|
---|
| 444 | Third-party libraries based on TweetNaCl.js
|
---|
| 445 | -------------------------------------------
|
---|
| 446 |
|
---|
| 447 | * [forward-secrecy](https://github.com/alax/forward-secrecy) — Axolotl ratchet implementation
|
---|
| 448 | * [nacl-stream](https://github.com/dchest/nacl-stream-js) - streaming encryption
|
---|
| 449 | * [tweetnacl-auth-js](https://github.com/dchest/tweetnacl-auth-js) — implementation of [`crypto_auth`](http://nacl.cr.yp.to/auth.html)
|
---|
| 450 | * [chloride](https://github.com/dominictarr/chloride) - unified API for various NaCl modules
|
---|
| 451 |
|
---|
| 452 |
|
---|
| 453 | Who uses it
|
---|
| 454 | -----------
|
---|
| 455 |
|
---|
| 456 | Some notable users of TweetNaCl.js:
|
---|
| 457 |
|
---|
| 458 | * [miniLock](http://minilock.io/)
|
---|
| 459 | * [Stellar](https://www.stellar.org/)
|
---|