Compare commits

...

64 Commits
kx ... master

Author SHA1 Message Date
Christophe Diederichs
f19e6c8172
Deprecate sodium-test (#68)
* deprecate sodium-test ahrness

* prune dependencies
2023-05-23 17:16:13 +02:00
Christophe Diederichs
ae2df3305e 0.8.0 2022-01-14 17:43:21 +00:00
Theron Spiegl
6c584231e6
Add crypto_secretstream methods (#57) 2022-01-14 16:42:28 +00:00
Christophe Diederichs
426ca77d47 0.7.4 2021-11-05 09:32:51 +00:00
Kasper Isager Dalsgarð
25c97802f4
crypto_sign: replace Buffer.alloc() with new Uint8Array() (#62) 2021-11-04 17:17:13 +00:00
Kasper Isager Dalsgarð
87ff2a56bd
Use globalThis instead of global (#61)
* Use `globalThis` instead of `global`

* Update `standard`
2021-11-02 16:36:15 +01:00
RangerMauve
7ef6e52870 Remove "react-native" field
This field isn't adding anything at the moment, and it actually breaks things by pointing at an unresolvable module.
2020-12-01 11:29:33 +01:00
Mathias Buus
0227f45c6b 0.7.3 2020-11-13 16:46:11 +01:00
Mathias Buus
ca32540960 load the sink just in time 2020-11-13 16:46:06 +01:00
Mathias Buus
51093efbc5 0.7.2 2020-11-12 14:46:28 +01:00
Christophe Diederichs
f79aed4eee
turn off worker_threads in browser (#52) 2020-11-12 14:04:40 +01:00
Kyle Mathews
3eb1d64460
Small copy change to README (#54) 2020-11-12 08:39:33 +01:00
RangerMauve
7febc97986
Detect window.close is defined (#49) 2020-10-09 13:35:11 +02:00
Christophe Diederichs
66494ec3b5 0.7.1 2020-09-22 15:56:40 +02:00
Christophe Diederichs
35f38a6c10 missing export: crypto_sign_ed25519_sk_to_pk 2020-09-22 15:50:00 +02:00
Christophe Diederichs
125384f26a remove lockfile 2020-09-22 15:34:54 +02:00
Christophe Diederichs
d432fe295d crypto_aead: correctly hadle ad passed as null 2020-09-22 15:30:31 +02:00
Christophe Diederichs
97200f90da 0.7.0 2020-09-22 14:56:20 +02:00
Christian Bundy
656d6d251e
Add crypto_auth (#32)
* add crypto_auth_hmac methods
2020-09-22 14:49:40 +02:00
Christian Bundy
61b6e6916a
Add crypto_box_easy (#29)
* Fix backward crypto_secretbox_detached bug

* Add crypto_box_easy
2020-09-22 14:47:36 +02:00
Christophe Diederichs
ab004d8022
Add ed25519 conversion operations (#46)
* add ed25519 methods and constants
2020-09-22 14:46:45 +02:00
Christophe Diederichs
ce5ac41ecd 0.6.3 2020-09-15 17:39:54 +02:00
Christophe Diederichs
a82160d51b
crypto_verify return booleans & add crypto_verify_64 (#33)
* crypto_verify return booleans

* can now return crypto_verify result directly

* remove redundant return values

* unpackneg check returns boolean
2020-09-15 17:27:39 +02:00
Mathias Buus
a546f3e51d 0.6.2 2020-08-12 15:40:16 +02:00
Emil Bay
a338ae9f9d
Missing helpers (#24)
* Detach buffers by sending to an empty message channel

* Move helpers out

* fix import

* export helpers

* Try browser testing

* messagechannel check

* xvfb-run --auto-servernum npm run test-browser fails weirdly on ci, removing

Co-authored-by: Mathias Buus <mathiasbuus@gmail.com>
2020-08-12 15:39:14 +02:00
Christophe Diederichs
e4693065fd update dependencies 2020-07-13 14:53:38 +02:00
Christophe Diederichs
44e5985630 change to universal hashes 2020-07-13 14:53:38 +02:00
Emil Bay
f11ff5a727 0.6.1 2020-06-24 16:30:16 +02:00
Emil Bay
9c30d3ead8 Nicer message formatting 2020-06-24 16:14:52 +02:00
Emil Bay
ddcdae69a1 Upgrade secretbox to sodium-native like api (not exposed there) 2020-06-24 16:12:12 +02:00
Emil Bay
80dd633012 Upgrade onetimeauth to sodium-native api 2020-06-24 16:11:56 +02:00
Emil Bay
d8d59d0443 Add note on sodium-universal 2020-06-24 15:06:54 +02:00
Emil Bay
ef00ddc878 Fix URLs 2020-06-24 15:06:48 +02:00
Emil Bay
cc52e58504 Update package metadata 2020-06-24 15:02:49 +02:00
Emil Bay
7b518f7b2c Fix offset ArrayBuffer views 2020-06-24 15:01:10 +02:00
Emil Bay
74a1067746
Fix filling larger width TypedArrays 2020-06-24 14:55:46 +02:00
Emil Bay
919896d2bb Revert accidental sign API change 2020-06-24 14:49:51 +02:00
Emil Bay
f3a80cb6f5 Upgrade deps 2020-06-24 14:49:38 +02:00
Emil Bay
40f9b887f4 Modernise example 2020-06-24 14:49:26 +02:00
Emil Bay
2ca6264f50 Add travis 2020-06-24 14:49:11 +02:00
Emil Bay
9d65d19e86 Standardize readme file 2020-06-24 14:49:05 +02:00
Emil Bay
30c3342156 Make linter happy 2020-06-24 14:08:55 +02:00
Emil Bay
930e77ad32 Move internal primitives 2020-06-24 14:02:00 +02:00
Emil Bay
e9ac929b5a Move memory helpers to their own module 2020-06-24 14:01:48 +02:00
Emil Bay
e77c70ef71 Bust crypto in browserify 2020-06-24 13:37:16 +02:00
Emil Bay
4bb40aa43d Clean up random bytes 2020-06-24 13:37:07 +02:00
Mathias Buus
fc90cbedba 0.6.0 2020-06-18 17:16:43 +02:00
Mathias Buus
63fb70028e bump sodium-test 2020-06-18 17:15:53 +02:00
Mathias Buus
f033af88bd copy -> set 2020-06-18 17:12:00 +02:00
Christophe Diederichs
b44f83f0a8
Split library into modules (#20)
* crypto_stream: signature change needed to modularise

* move ed25519 arithmetic to separate module

* module: poly1305

* module: crypto_scalarmult

* module: crypto_hash

* module: crypto_sign

* module: crypto_secretbox

* move verify functions to crypto_verify module

* leftover crypto_stream functions

* module: crypto_onetimeauth

* module: crypto_box

* tidy up

* require ed25519.js

* update: crypto_hash

* add chacha20; align API with PR#21

* update sha512 to wasm module

* fix bugs in crypto_sign

* be standard

* add: crypto_box_seed_keypair; alias crypto_kx methods to crypto_box

* scalarmult: import curve methods; be standard

* correction: crypto_kx is not actually an alias of crypto_box

* export _9 constant field element

* add: crypto_box_seed_keypair

* removed duplicate module.exports declaraion

* declare constants about exports

* rename memzero -> sodium-memzero

* update sodium_memzero function to arr.fill(0)

* tidy: remove legacy functions

* added: crypto_aead_chacha20poly1305_ietf methods

* listen to linter

* add assertions

* chacha: readUint32Le generalised for uint8array; aead: standard fix

* add null check on ad param

* added: sodium_memcmp

* export sodium_memcmp

* export crypto_verify module

* sodium_memcmp returns boolean

* added: sodium_is_zero

* catch syntax error

* throw if crypto_aead cannot validate, fix typo in crypto_verify

* move chacha20 alg to external module

* use Uint8Arrays instead of buffers

* change checks to assertions

* bump to chacha 1.0.3 - remove Buffer dependency

* reduce code branching, align return values with sodium-native

* add sha-wasm deps to package.json

* standard fixes

* bump chacha20 to 1.0.4: remove Buffer dep

* move crypto_hash_sha256 to module to uncouple wasm dependencies

* add endian check: all other modules require members of this set

* correct filename: crypto_hash_sha256

* export constant: crypto_hash_sha512_BYTES
2020-06-18 17:09:03 +02:00
Mathias Buus
51f8fbc2d3 0.5.6 2020-03-04 14:52:37 +01:00
Mathias Buus
f790621e60 add sodium_malloc 2020-03-04 14:50:09 +01:00
Fedor Indutny
4e42b942a5 crypto_box: fix keypair, implement seal/seal_open
Secret Key is a random nonce, and public key is a point on elliptic
curve.

`crypto_box_seal`/`crypto_box_seal_open` are implemented using existing
primitives and newly exported `core_hsalsa20` in `xsalsa20`
2019-11-14 09:27:36 +01:00
Daniel Regeci
49587c3d7f crypto_box_keypair - rename arguments to pk,sk 2018-03-19 18:07:17 +00:00
Daniel Regeci
92aee452df crypto_box_keypair 2018-03-19 18:07:17 +00:00
Mathias Buus
e1ca83f1bd 0.5.5 2018-03-19 19:03:43 +01:00
Peter van Hardenberg
c81ef709d1 react-native doesn't want crypto set to an empty module (#14)
React-Native is sort of like a browser, sort of a native environment. On react-native we don't have the browser's crypto implementation, so we need to require react-native-crypto. We can rewrite the module requirement to do that using the extraNodeModules feature in rn-cli.config.js, but the metro packager assumes that if there's a "browser" field in package.json that it's relevant to react-native libraries unless there's also a "react-native" field. Hurray.

Anyway, this silly little patch tells metro not to replace crypto with an empty module but actually to use whatever you currently have crypto set to (which is not solved here, so you'll still have to do that.)
2018-03-19 18:58:24 +01:00
Jim Pick
4e1c69ba13 Change crypto_kdf_KEYBYTES to be 32 and use subarray instead of slice
Thanks to Emil Bayes for the advice.
2018-03-03 17:24:12 +00:00
Jim Pick
5159d68fa9 In kdf, truncate key before passing to blake to match sodium-native behaviour
Currently, sodium-native and sodium-javascript are returning different
hashes. The code in hyperdrive passes a 64 byte secret key to the kdf,
but only 32 bytes are used by the native version, but all 64 bytes are
used in the javascript version. As a result, hyperdrive secret keys
can't be imported/exported across the two sodium implementations.

https://gist.github.com/jimpick/3e869522eddaad77ac1bc9e64f36e1a7
2018-03-03 17:24:12 +00:00
Mathias Buus
5ccdcdee17 0.5.4 2017-11-19 13:16:51 +01:00
Mathias Buus
48081c6896 ignore crypto in the browser 2017-11-19 13:16:35 +01:00
Mathias Buus
b1741bfdae 0.5.3 2017-11-17 12:09:34 +01:00
Mathias Buus
f7de366eec fix shorthash_ready being deprecated 2017-11-17 12:07:52 +01:00
Mathias Buus
51e11143e5 fix siphash24 not having ready 2017-11-17 10:43:01 +01:00
58 changed files with 10470 additions and 1854 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
node_modules node_modules
package-lock.json

18
.travis.yml Normal file
View File

@ -0,0 +1,18 @@
language: node_js
node_js:
- lts/*
env:
global:
- MOZ_HEADLESS=1
services:
- xvfb
addons:
firefox: latest
chrome: stable
cache:
npm: false
script:
- npm test
- xvfb-run --auto-servernum npm run test-browser -- --browser chrome
- xvfb-run --auto-servernum npm run test-browser -- --browser firefox

View File

@ -1,31 +1,29 @@
# sodium-javascript # `sodium-javascript`
WIP - a pure javascript version of [sodium-native](https://github.com/mafintosh/sodium-native). [![Build Status](https://travis-ci.org/sodium-friends/sodium-javascript.svg?branch=master)](https://travis-ci.org/sodium-friends/sodium-javascript)
> WIP - a pure javascript version of [sodium-native](https://github.com/sodium-friends/sodium-native).
Based on tweetnacl Based on tweetnacl
```
npm install sodium-javascript
```
## Usage ## Usage
``` js ``` js
var sodium = require('sodium-javascript') const sodium = require('sodium-javascript')
var key = new Buffer(sodium.crypto_secretbox_KEYBYTES) const key = Buffer.alloc(sodium.crypto_secretbox_KEYBYTES)
var nonce = new Buffer(sodium.crypto_secretbox_NONCEBYTES) const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES)
sodium.randombytes_buf(key) sodium.randombytes_buf(key)
sodium.randombytes_buf(nonce) sodium.randombytes_buf(nonce)
var message = new Buffer('Hello, World!') const message = Buffer.from('Hello, World!')
var cipher = new Buffer(message.length + sodium.crypto_secretbox_MACBYTES) const cipher = Buffer.alloc(message.length + sodium.crypto_secretbox_MACBYTES)
sodium.crypto_secretbox_easy(cipher, message, nonce, key) sodium.crypto_secretbox_easy(cipher, message, nonce, key)
console.log('Encrypted:', cipher) console.log('Encrypted:', cipher)
var plainText = new Buffer(cipher.length - sodium.crypto_secretbox_MACBYTES) const plainText = Buffer.alloc(cipher.length - sodium.crypto_secretbox_MACBYTES)
sodium.crypto_secretbox_open_easy(plainText, cipher, nonce, key) sodium.crypto_secretbox_open_easy(plainText, cipher, nonce, key)
@ -34,9 +32,20 @@ console.log('Plaintext:', plainText.toString())
## API ## API
See [sodium-native](https://github.com/mafintosh/sodium-native). See [sodium-native](https://github.com/sodium-friends/sodium-native).
This is a work in progress so all functions are not implemented yet. This is a work in progress so not all functions are implemented yet.
This module is organised into individual submodules which can be required
independently for smaller bundles in the browser. To leverage automatic
switching between `sodium-javascript` and `sodium-native`, see
[`sodium-universal`](https://github.com/sodium-friends/sodium-universal).
## Install
```
npm install sodium-javascript
```
## License ## License
MIT [MIT](LICENSE)

160
crypto_aead.js Normal file
View File

@ -0,0 +1,160 @@
/* eslint-disable camelcase */
const { crypto_stream_chacha20_ietf, crypto_stream_chacha20_ietf_xor_ic } = require('./crypto_stream_chacha20')
const { crypto_verify_16 } = require('./crypto_verify')
const Poly1305 = require('./internal/poly1305')
const assert = require('nanoassert')
const crypto_aead_chacha20poly1305_ietf_KEYBYTES = 32
const crypto_aead_chacha20poly1305_ietf_NSECBYTES = 0
const crypto_aead_chacha20poly1305_ietf_NPUBBYTES = 12
const crypto_aead_chacha20poly1305_ietf_ABYTES = 16
const crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX = Number.MAX_SAFE_INTEGER
const _pad0 = new Uint8Array(16)
function crypto_aead_chacha20poly1305_ietf_encrypt (c, m, ad, nsec, npub, k) {
if (ad === null) return crypto_aead_chacha20poly1305_ietf_encrypt(c, m, new Uint8Array(0), nsec, npub, k)
assert(c.byteLength === m.byteLength + crypto_aead_chacha20poly1305_ietf_ABYTES,
"ciphertext should be 'crypto_aead_chacha20poly1305_ietf_ABYTES' longer than message")
assert(npub.byteLength === crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
"npub should be 'crypto_aead_chacha20poly1305_ietf_NPUBBYTES' long")
assert(k.byteLength === crypto_aead_chacha20poly1305_ietf_KEYBYTES,
"k should be 'crypto_aead_chacha20poly1305_ietf_KEYBYTES' long")
assert(m.byteLength <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'message is too large')
const ret = crypto_aead_chacha20poly1305_ietf_encrypt_detached(c.subarray(0, m.byteLength),
c.subarray(m.byteLength), m, ad, nsec, npub, k)
return m.byteLength + ret
}
function crypto_aead_chacha20poly1305_ietf_encrypt_detached (c, mac, m, ad, nsec, npub, k) {
if (ad === null) return crypto_aead_chacha20poly1305_ietf_encrypt_detached(c, mac, m, new Uint8Array(0), nsec, npub, k)
assert(c.byteLength === m.byteLength, 'ciphertext should be same length than message')
assert(npub.byteLength === crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
"npub should be 'crypto_aead_chacha20poly1305_ietf_NPUBBYTES' long")
assert(k.byteLength === crypto_aead_chacha20poly1305_ietf_KEYBYTES,
"k should be 'crypto_aead_chacha20poly1305_ietf_KEYBYTES' long")
assert(m.byteLength <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'message is too large')
assert(mac.byteLength <= crypto_aead_chacha20poly1305_ietf_ABYTES,
"mac should be 'crypto_aead_chacha20poly1305_ietf_ABYTES' long")
const block0 = new Uint8Array(64)
var slen = new Uint8Array(8)
crypto_stream_chacha20_ietf(block0, npub, k)
const poly = new Poly1305(block0)
block0.fill(0)
poly.update(ad, 0, ad.byteLength)
poly.update(_pad0, 0, (0x10 - ad.byteLength) & 0xf)
crypto_stream_chacha20_ietf_xor_ic(c, m, npub, 1, k)
poly.update(c, 0, m.byteLength)
poly.update(_pad0, 0, (0x10 - m.byteLength) & 0xf)
write64LE(slen, 0, ad.byteLength)
poly.update(slen, 0, slen.byteLength)
write64LE(slen, 0, m.byteLength)
poly.update(slen, 0, slen.byteLength)
poly.finish(mac, 0)
slen.fill(0)
return crypto_aead_chacha20poly1305_ietf_ABYTES
}
function crypto_aead_chacha20poly1305_ietf_decrypt (m, nsec, c, ad, npub, k) {
if (ad === null) return crypto_aead_chacha20poly1305_ietf_decrypt(m, nsec, c, new Uint8Array(0), npub, k)
assert(m.byteLength === c.byteLength - crypto_aead_chacha20poly1305_ietf_ABYTES,
"message should be 'crypto_aead_chacha20poly1305_ietf_ABYTES' shorter than ciphertext")
assert(npub.byteLength === crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
"npub should be 'crypto_aead_chacha20poly1305_ietf_NPUBBYTES' long")
assert(k.byteLength === crypto_aead_chacha20poly1305_ietf_KEYBYTES,
"k should be 'crypto_aead_chacha20poly1305_ietf_KEYBYTES' long")
assert(m.byteLength <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'message is too large')
if (c.byteLength < crypto_aead_chacha20poly1305_ietf_ABYTES) throw new Error('could not verify data')
crypto_aead_chacha20poly1305_ietf_decrypt_detached(
m, nsec,
c.subarray(0, c.byteLength - crypto_aead_chacha20poly1305_ietf_ABYTES),
c.subarray(c.byteLength - crypto_aead_chacha20poly1305_ietf_ABYTES),
ad, npub, k)
return c.byteLength - crypto_aead_chacha20poly1305_ietf_ABYTES
}
function crypto_aead_chacha20poly1305_ietf_decrypt_detached (m, nsec, c, mac, ad, npub, k) {
if (ad === null) return crypto_aead_chacha20poly1305_ietf_decrypt_detached(m, nsec, c, mac, new Uint8Array(0), npub, k)
assert(c.byteLength === m.byteLength, 'message should be same length than ciphertext')
assert(npub.byteLength === crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
"npub should be 'crypto_aead_chacha20poly1305_ietf_NPUBBYTES' long")
assert(k.byteLength === crypto_aead_chacha20poly1305_ietf_KEYBYTES,
"k should be 'crypto_aead_chacha20poly1305_ietf_KEYBYTES' long")
assert(m.byteLength <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'message is too large')
assert(mac.byteLength <= crypto_aead_chacha20poly1305_ietf_ABYTES,
"mac should be 'crypto_aead_chacha20poly1305_ietf_ABYTES' long")
const block0 = new Uint8Array(64)
const slen = new Uint8Array(8)
const computed_mac = new Uint8Array(crypto_aead_chacha20poly1305_ietf_ABYTES)
crypto_stream_chacha20_ietf(block0, npub, k)
const poly = new Poly1305(block0)
block0.fill(0)
poly.update(ad, 0, ad.byteLength)
poly.update(_pad0, 0, (0x10 - ad.byteLength) & 0xf)
const mlen = c.byteLength
poly.update(c, 0, mlen)
poly.update(_pad0, 0, (0x10 - mlen) & 0xf)
write64LE(slen, 0, ad.byteLength)
poly.update(slen, 0, slen.byteLength)
write64LE(slen, 0, mlen)
poly.update(slen, 0, slen.byteLength)
poly.finish(computed_mac, 0)
assert(computed_mac.byteLength === 16)
const ret = crypto_verify_16(computed_mac, 0, mac, 0)
computed_mac.fill(0)
slen.fill(0)
if (!ret) {
m.fill(0)
throw new Error('could not verify data')
}
crypto_stream_chacha20_ietf_xor_ic(m, c, npub, 1, k)
}
function write64LE (buf, offset, int) {
buf.fill(0, 0, 8)
const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength)
view.setUint32(offset, int & 0xffffffff, true)
view.setUint32(offset + 4, (int / 2 ** 32) & 0xffffffff, true)
}
module.exports = {
crypto_aead_chacha20poly1305_ietf_encrypt,
crypto_aead_chacha20poly1305_ietf_encrypt_detached,
crypto_aead_chacha20poly1305_ietf_decrypt,
crypto_aead_chacha20poly1305_ietf_decrypt_detached,
crypto_aead_chacha20poly1305_ietf_ABYTES,
crypto_aead_chacha20poly1305_ietf_KEYBYTES,
crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
crypto_aead_chacha20poly1305_ietf_NSECBYTES,
crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX
}

35
crypto_auth.js Normal file
View File

@ -0,0 +1,35 @@
/* eslint-disable camelcase */
const { crypto_verify_32 } = require('./crypto_verify')
const Sha512 = require('sha512-universal')
const assert = require('nanoassert')
const crypto_auth_BYTES = 32
const crypto_auth_KEYBYTES = 32
function crypto_auth (out, input, k) {
assert(out.byteLength === crypto_auth_BYTES, "out should be 'crypto_auth_BYTES' in length")
assert(k.byteLength === crypto_auth_KEYBYTES, "key should be 'crypto_auth_KEYBYTES' in length")
const out0 = new Uint8Array(64)
const hmac = Sha512.HMAC(k)
hmac.update(input)
hmac.digest(out0)
out.set(out0.subarray(0, 32))
}
function crypto_auth_verify (h, input, k) {
assert(h.byteLength === crypto_auth_BYTES, "h should be 'crypto_auth_BYTES' in length")
assert(k.byteLength === crypto_auth_KEYBYTES, "key should be 'crypto_auth_KEYBYTES' in length")
const correct = Sha512.HMAC(k).update(input).digest()
return crypto_verify_32(h, 0, correct, 0)
}
module.exports = {
crypto_auth_BYTES,
crypto_auth_KEYBYTES,
crypto_auth,
crypto_auth_verify
}

200
crypto_box.js Normal file
View File

@ -0,0 +1,200 @@
/* eslint-disable camelcase */
const { crypto_hash_sha512 } = require('./crypto_hash')
const { crypto_scalarmult, crypto_scalarmult_base } = require('./crypto_scalarmult')
const { randombytes } = require('./randombytes')
const { crypto_generichash_batch } = require('./crypto_generichash')
const { crypto_stream_xsalsa20_MESSAGEBYTES_MAX } = require('./crypto_stream')
const {
crypto_secretbox_open_easy,
crypto_secretbox_easy,
crypto_secretbox_detached,
crypto_secretbox_open_detached
} = require('./crypto_secretbox')
const xsalsa20 = require('xsalsa20')
const assert = require('nanoassert')
const crypto_box_PUBLICKEYBYTES = 32
const crypto_box_SECRETKEYBYTES = 32
const crypto_box_NONCEBYTES = 24
const crypto_box_ZEROBYTES = 32
const crypto_box_BOXZEROBYTES = 16
const crypto_box_SEALBYTES = 48
const crypto_box_SEEDBYTES = 32
const crypto_box_BEFORENMBYTES = 32
const crypto_box_MACBYTES = 16
const crypto_box_curve25519xsalsa20poly1305_MACBYTES = 16
const crypto_box_MESSAGEBYTES_MAX =
crypto_stream_xsalsa20_MESSAGEBYTES_MAX -
crypto_box_curve25519xsalsa20poly1305_MACBYTES
module.exports = {
crypto_box_easy,
crypto_box_open_easy,
crypto_box_keypair,
crypto_box_seed_keypair,
crypto_box_seal,
crypto_box_seal_open,
crypto_box_PUBLICKEYBYTES,
crypto_box_SECRETKEYBYTES,
crypto_box_NONCEBYTES,
crypto_box_ZEROBYTES,
crypto_box_BOXZEROBYTES,
crypto_box_SEALBYTES,
crypto_box_SEEDBYTES,
crypto_box_BEFORENMBYTES,
crypto_box_MACBYTES
}
function crypto_box_keypair (pk, sk) {
check(pk, crypto_box_PUBLICKEYBYTES)
check(sk, crypto_box_SECRETKEYBYTES)
randombytes(sk, 32)
return crypto_scalarmult_base(pk, sk)
}
function crypto_box_seed_keypair (pk, sk, seed) {
assert(pk.byteLength === crypto_box_PUBLICKEYBYTES, "pk should be 'crypto_box_PUBLICKEYBYTES' bytes")
assert(sk.byteLength === crypto_box_SECRETKEYBYTES, "sk should be 'crypto_box_SECRETKEYBYTES' bytes")
assert(sk.byteLength === crypto_box_SEEDBYTES, "sk should be 'crypto_box_SEEDBYTES' bytes")
const hash = new Uint8Array(64)
crypto_hash_sha512(hash, seed, 32)
sk.set(hash.subarray(0, 32))
hash.fill(0)
return crypto_scalarmult_base(pk, sk)
}
function crypto_box_seal (c, m, pk) {
check(c, crypto_box_SEALBYTES + m.length)
check(pk, crypto_box_PUBLICKEYBYTES)
var epk = c.subarray(0, crypto_box_PUBLICKEYBYTES)
var esk = new Uint8Array(crypto_box_SECRETKEYBYTES)
crypto_box_keypair(epk, esk)
var n = new Uint8Array(crypto_box_NONCEBYTES)
crypto_generichash_batch(n, [epk, pk])
var s = new Uint8Array(crypto_box_PUBLICKEYBYTES)
crypto_scalarmult(s, esk, pk)
var k = new Uint8Array(crypto_box_BEFORENMBYTES)
var zero = new Uint8Array(16)
xsalsa20.core_hsalsa20(k, zero, s, xsalsa20.SIGMA)
crypto_secretbox_easy(c.subarray(epk.length), m, n, k)
cleanup(esk)
}
function crypto_box_seal_open (m, c, pk, sk) {
check(c, crypto_box_SEALBYTES)
check(m, c.length - crypto_box_SEALBYTES)
check(pk, crypto_box_PUBLICKEYBYTES)
check(sk, crypto_box_SECRETKEYBYTES)
var epk = c.subarray(0, crypto_box_PUBLICKEYBYTES)
var n = new Uint8Array(crypto_box_NONCEBYTES)
crypto_generichash_batch(n, [epk, pk])
var s = new Uint8Array(crypto_box_PUBLICKEYBYTES)
crypto_scalarmult(s, sk, epk)
var k = new Uint8Array(crypto_box_BEFORENMBYTES)
var zero = new Uint8Array(16)
xsalsa20.core_hsalsa20(k, zero, s, xsalsa20.SIGMA)
return crypto_secretbox_open_easy(m, c.subarray(epk.length), n, k)
}
function crypto_box_beforenm (k, pk, sk) {
const zero = new Uint8Array(16)
const s = new Uint8Array(32)
assert(crypto_scalarmult(s, sk, pk) === 0)
xsalsa20.core_hsalsa20(k, zero, s, xsalsa20.SIGMA)
return true
}
function crypto_box_detached_afternm (c, mac, m, n, k) {
return crypto_secretbox_detached(c, mac, m, n, k)
}
function crypto_box_detached (c, mac, m, n, pk, sk) {
check(mac, crypto_box_MACBYTES)
check(n, crypto_box_NONCEBYTES)
check(pk, crypto_box_PUBLICKEYBYTES)
check(sk, crypto_box_SECRETKEYBYTES)
const k = new Uint8Array(crypto_box_BEFORENMBYTES)
assert(crypto_box_beforenm(k, pk, sk))
const ret = crypto_box_detached_afternm(c, mac, m, n, k)
cleanup(k)
return ret
}
function crypto_box_easy (c, m, n, pk, sk) {
assert(
c.length >= m.length + crypto_box_MACBYTES,
"c should be at least 'm.length + crypto_box_MACBYTES' bytes"
)
assert(
m.length <= crypto_box_MESSAGEBYTES_MAX,
"m should be at most 'crypto_box_MESSAGEBYTES_MAX' bytes"
)
return crypto_box_detached(
c.subarray(crypto_box_MACBYTES, m.length + crypto_box_MACBYTES),
c.subarray(0, crypto_box_MACBYTES),
m,
n,
pk,
sk
)
}
function crypto_box_open_detached_afternm (m, c, mac, n, k) {
return crypto_secretbox_open_detached(m, c, mac, n, k)
}
function crypto_box_open_detached (m, c, mac, n, pk, sk) {
const k = new Uint8Array(crypto_box_BEFORENMBYTES)
assert(crypto_box_beforenm(k, pk, sk))
const ret = crypto_box_open_detached_afternm(m, c, mac, n, k)
cleanup(k)
return ret
}
function crypto_box_open_easy (m, c, n, pk, sk) {
assert(
c.length >= m.length + crypto_box_MACBYTES,
"c should be at least 'm.length + crypto_box_MACBYTES' bytes"
)
return crypto_box_open_detached(
m,
c.subarray(crypto_box_MACBYTES, m.length + crypto_box_MACBYTES),
c.subarray(0, crypto_box_MACBYTES),
n,
pk,
sk
)
}
function check (buf, len) {
if (!buf || (len && buf.length < len)) throw new Error('Argument must be a buffer' + (len ? ' of length ' + len : ''))
}
function cleanup (arr) {
for (let i = 0; i < arr.length; i++) arr[i] = 0
}

View File

@ -1,5 +1,7 @@
var blake2b = require('blake2b') var blake2b = require('blake2b')
if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.')
module.exports.crypto_generichash_PRIMITIVE = 'blake2b' module.exports.crypto_generichash_PRIMITIVE = 'blake2b'
module.exports.crypto_generichash_BYTES_MIN = blake2b.BYTES_MIN module.exports.crypto_generichash_BYTES_MIN = blake2b.BYTES_MIN
module.exports.crypto_generichash_BYTES_MAX = blake2b.BYTES_MAX module.exports.crypto_generichash_BYTES_MAX = blake2b.BYTES_MAX
@ -29,6 +31,6 @@ module.exports.crypto_generichash_instance = function (key, outlen) {
return blake2b(outlen, key) return blake2b(outlen, key)
} }
blake2b.ready(function (err) { blake2b.ready(function (_) {
module.exports.crypto_generichash_WASM_LOADED = blake2b.WASM_LOADED module.exports.crypto_generichash_WASM_LOADED = blake2b.WASM_LOADED
}) })

26
crypto_hash.js Normal file
View File

@ -0,0 +1,26 @@
/* eslint-disable camelcase */
const sha512 = require('sha512-universal')
const assert = require('nanoassert')
if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.')
const crypto_hash_sha512_BYTES = 64
const crypto_hash_BYTES = crypto_hash_sha512_BYTES
function crypto_hash_sha512 (out, m, n) {
assert(out.byteLength === crypto_hash_sha512_BYTES, "out must be 'crypto_hash_sha512_BYTES' bytes long")
sha512().update(m.subarray(0, n)).digest(out)
return 0
}
function crypto_hash (out, m, n) {
return crypto_hash_sha512(out, m, n)
}
module.exports = {
crypto_hash,
crypto_hash_sha512,
crypto_hash_sha512_BYTES,
crypto_hash_BYTES
}

19
crypto_hash_sha256.js Normal file
View File

@ -0,0 +1,19 @@
/* eslint-disable camelcase */
const sha256 = require('sha256-universal')
const assert = require('nanoassert')
if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.')
const crypto_hash_sha256_BYTES = 32
function crypto_hash_sha256 (out, m, n) {
assert(out.byteLength === crypto_hash_sha256_BYTES, "out must be 'crypto_hash_sha256_BYTES' bytes long")
sha256().update(m.subarray(0, n)).digest(out)
return 0
}
module.exports = {
crypto_hash_sha256,
crypto_hash_sha256_BYTES
}

View File

@ -1,14 +1,15 @@
var assert = require('nanoassert') /* eslint-disable camelcase */
var randombytes_buf = require('./randombytes').randombytes_buf const assert = require('nanoassert')
var blake2b = require('blake2b') const randombytes_buf = require('./randombytes').randombytes_buf
const blake2b = require('blake2b')
module.exports.crypto_kdf_PRIMITIVE = 'blake2b' module.exports.crypto_kdf_PRIMITIVE = 'blake2b'
module.exports.crypto_kdf_BYTES_MIN = 16 module.exports.crypto_kdf_BYTES_MIN = 16
module.exports.crypto_kdf_BYTES_MAX = 64 module.exports.crypto_kdf_BYTES_MAX = 64
module.exports.crypto_kdf_CONTEXTBYTES = 8 module.exports.crypto_kdf_CONTEXTBYTES = 8
module.exports.crypto_kdf_KEYBYTES = 64 module.exports.crypto_kdf_KEYBYTES = 32
function STORE64_LE(dest, int) { function STORE64_LE (dest, int) {
var mul = 1 var mul = 1
var i = 0 var i = 0
dest[0] = int & 0xFF dest[0] = int & 0xFF
@ -29,7 +30,7 @@ module.exports.crypto_kdf_derive_from_key = function crypto_kdf_derive_from_key
STORE64_LE(salt, subkey_id) STORE64_LE(salt, subkey_id)
var outlen = Math.min(subkey.length, module.exports.crypto_kdf_BYTES_MAX) var outlen = Math.min(subkey.length, module.exports.crypto_kdf_BYTES_MAX)
blake2b(outlen, key, salt, ctx_padded, true) blake2b(outlen, key.subarray(0, module.exports.crypto_kdf_KEYBYTES), salt, ctx_padded, true)
.final(subkey) .final(subkey)
} }

34
crypto_kx.js Normal file
View File

@ -0,0 +1,34 @@
/* eslint-disable camelcase */
const { crypto_scalarmult_base } = require('./crypto_scalarmult')
const { crypto_generichash } = require('./crypto_generichash')
const { randombytes_buf } = require('./randombytes')
const assert = require('nanoassert')
const crypto_kx_SEEDBYTES = 32
const crypto_kx_PUBLICKEYBYTES = 32
const crypto_kx_SECRETKEYBYTES = 32
function crypto_kx_keypair (pk, sk) {
assert(pk.byteLength === crypto_kx_PUBLICKEYBYTES, "pk must be 'crypto_kx_PUBLICKEYBYTES' bytes")
assert(sk.byteLength === crypto_kx_SECRETKEYBYTES, "sk must be 'crypto_kx_SECRETKEYBYTES' bytes")
randombytes_buf(sk, crypto_kx_SECRETKEYBYTES)
return crypto_scalarmult_base(pk, sk)
}
function crypto_kx_seed_keypair (pk, sk, seed) {
assert(pk.byteLength === crypto_kx_PUBLICKEYBYTES, "pk must be 'crypto_kx_PUBLICKEYBYTES' bytes")
assert(sk.byteLength === crypto_kx_SECRETKEYBYTES, "sk must be 'crypto_kx_SECRETKEYBYTES' bytes")
assert(seed.byteLength === crypto_kx_SEEDBYTES, "seed must be 'crypto_kx_SEEDBYTES' bytes")
crypto_generichash(sk, seed)
return crypto_scalarmult_base(pk, sk)
}
module.exports = {
crypto_kx_keypair,
crypto_kx_seed_keypair,
crypto_kx_SEEDBYTES,
crypto_kx_SECRETKEYBYTES,
crypto_kx_PUBLICKEYBYTES
}

36
crypto_onetimeauth.js Normal file
View File

@ -0,0 +1,36 @@
/* eslint-disable camelcase */
const assert = require('nanoassert')
const Poly1305 = require('./internal/poly1305')
const { crypto_verify_16 } = require('./crypto_verify')
const crypto_onetimeauth_BYTES = 16
const crypto_onetimeauth_KEYBYTES = 32
const crypto_onetimeauth_PRIMITIVE = 'poly1305'
module.exports = {
crypto_onetimeauth,
crypto_onetimeauth_verify,
crypto_onetimeauth_BYTES,
crypto_onetimeauth_KEYBYTES,
crypto_onetimeauth_PRIMITIVE
}
function crypto_onetimeauth (mac, msg, key) {
assert(mac.byteLength === crypto_onetimeauth_BYTES, "mac must be 'crypto_onetimeauth_BYTES' bytes")
assert(msg.byteLength != null, 'msg must be buffer')
assert(key.byteLength === crypto_onetimeauth_KEYBYTES, "key must be 'crypto_onetimeauth_KEYBYTES' bytes")
var s = new Poly1305(key)
s.update(msg, 0, msg.byteLength)
s.finish(mac, 0)
}
function crypto_onetimeauth_verify (mac, msg, key) {
assert(mac.byteLength === crypto_onetimeauth_BYTES, "mac must be 'crypto_onetimeauth_BYTES' bytes")
assert(msg.byteLength != null, 'msg must be buffer')
assert(key.byteLength === crypto_onetimeauth_KEYBYTES, "key must be 'crypto_onetimeauth_KEYBYTES' bytes")
var tmp = new Uint8Array(16)
crypto_onetimeauth(tmp, msg, key)
return crypto_verify_16(mac, 0, tmp, 0)
}

76
crypto_scalarmult.js Normal file
View File

@ -0,0 +1,76 @@
/* eslint-disable camelcase, one-var */
const { _9, _121665, gf, inv25519, pack25519, unpack25519, sel25519, A, M, Z, S } = require('./internal/ed25519')
const crypto_scalarmult_BYTES = 32
const crypto_scalarmult_SCALARBYTES = 32
module.exports = {
crypto_scalarmult,
crypto_scalarmult_base,
crypto_scalarmult_BYTES,
crypto_scalarmult_SCALARBYTES
}
function crypto_scalarmult (q, n, p) {
check(q, crypto_scalarmult_BYTES)
check(n, crypto_scalarmult_SCALARBYTES)
check(p, crypto_scalarmult_BYTES)
var z = new Uint8Array(32)
var x = new Float64Array(80), r, i
var a = gf(), b = gf(), c = gf(),
d = gf(), e = gf(), f = gf()
for (i = 0; i < 31; i++) z[i] = n[i]
z[31] = (n[31] & 127) | 64
z[0] &= 248
unpack25519(x, p)
for (i = 0; i < 16; i++) {
b[i] = x[i]
d[i] = a[i] = c[i] = 0
}
a[0] = d[0] = 1
for (i = 254; i >= 0; --i) {
r = (z[i >>> 3] >>> (i & 7)) & 1
sel25519(a, b, r)
sel25519(c, d, r)
A(e, a, c)
Z(a, a, c)
A(c, b, d)
Z(b, b, d)
S(d, e)
S(f, a)
M(a, c, a)
M(c, b, e)
A(e, a, c)
Z(a, a, c)
S(b, a)
Z(c, d, f)
M(a, c, _121665)
A(a, a, d)
M(c, c, a)
M(a, d, f)
M(d, b, x)
S(b, e)
sel25519(a, b, r)
sel25519(c, d, r)
}
for (i = 0; i < 16; i++) {
x[i + 16] = a[i]
x[i + 32] = c[i]
x[i + 48] = b[i]
x[i + 64] = d[i]
}
var x32 = x.subarray(32)
var x16 = x.subarray(16)
inv25519(x32, x32)
M(x16, x16, x32)
pack25519(q, x16)
return 0
}
function crypto_scalarmult_base (q, n) {
return crypto_scalarmult(q, n, _9)
}
function check (buf, len) {
if (!buf || (len && buf.length < len)) throw new Error('Argument must be a buffer' + (len ? ' of length ' + len : ''))
}

111
crypto_secretbox.js Normal file
View File

@ -0,0 +1,111 @@
/* eslint-disable camelcase */
const assert = require('nanoassert')
const { crypto_stream, crypto_stream_xor } = require('./crypto_stream')
const { crypto_onetimeauth, crypto_onetimeauth_verify, crypto_onetimeauth_BYTES, crypto_onetimeauth_KEYBYTES } = require('./crypto_onetimeauth')
const crypto_secretbox_KEYBYTES = 32
const crypto_secretbox_NONCEBYTES = 24
const crypto_secretbox_ZEROBYTES = 32
const crypto_secretbox_BOXZEROBYTES = 16
const crypto_secretbox_MACBYTES = 16
module.exports = {
crypto_secretbox,
crypto_secretbox_open,
crypto_secretbox_detached,
crypto_secretbox_open_detached,
crypto_secretbox_easy,
crypto_secretbox_open_easy,
crypto_secretbox_KEYBYTES,
crypto_secretbox_NONCEBYTES,
crypto_secretbox_ZEROBYTES,
crypto_secretbox_BOXZEROBYTES,
crypto_secretbox_MACBYTES
}
function crypto_secretbox (c, m, n, k) {
assert(c.byteLength === m.byteLength, "c must be 'm.byteLength' bytes")
const mlen = m.byteLength
assert(mlen >= crypto_secretbox_ZEROBYTES, "mlen must be at least 'crypto_secretbox_ZEROBYTES'")
assert(n.byteLength === crypto_secretbox_NONCEBYTES, "n must be 'crypto_secretbox_NONCEBYTES' bytes")
assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes")
crypto_stream_xor(c, m, n, k)
crypto_onetimeauth(
c.subarray(crypto_secretbox_BOXZEROBYTES, crypto_secretbox_BOXZEROBYTES + crypto_onetimeauth_BYTES),
c.subarray(crypto_secretbox_BOXZEROBYTES + crypto_onetimeauth_BYTES, c.byteLength),
c.subarray(0, crypto_onetimeauth_KEYBYTES)
)
c.fill(0, 0, crypto_secretbox_BOXZEROBYTES)
}
function crypto_secretbox_open (m, c, n, k) {
assert(c.byteLength === m.byteLength, "c must be 'm.byteLength' bytes")
const mlen = m.byteLength
assert(mlen >= crypto_secretbox_ZEROBYTES, "mlen must be at least 'crypto_secretbox_ZEROBYTES'")
assert(n.byteLength === crypto_secretbox_NONCEBYTES, "n must be 'crypto_secretbox_NONCEBYTES' bytes")
assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes")
const x = new Uint8Array(crypto_onetimeauth_KEYBYTES)
crypto_stream(x, n, k)
const validMac = crypto_onetimeauth_verify(
c.subarray(crypto_secretbox_BOXZEROBYTES, crypto_secretbox_BOXZEROBYTES + crypto_onetimeauth_BYTES),
c.subarray(crypto_secretbox_BOXZEROBYTES + crypto_onetimeauth_BYTES, c.byteLength),
x
)
if (validMac === false) return false
crypto_stream_xor(m, c, n, k)
m.fill(0, 0, 32)
return true
}
function crypto_secretbox_detached (o, mac, msg, n, k) {
assert(o.byteLength === msg.byteLength, "o must be 'msg.byteLength' bytes")
assert(mac.byteLength === crypto_secretbox_MACBYTES, "mac must be 'crypto_secretbox_MACBYTES' bytes")
assert(n.byteLength === crypto_secretbox_NONCEBYTES, "n must be 'crypto_secretbox_NONCEBYTES' bytes")
assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes")
const tmp = new Uint8Array(msg.byteLength + mac.byteLength)
crypto_secretbox_easy(tmp, msg, n, k)
mac.set(tmp.subarray(0, mac.byteLength))
o.set(tmp.subarray(mac.byteLength))
return true
}
function crypto_secretbox_open_detached (msg, o, mac, n, k) {
assert(o.byteLength === msg.byteLength, "o must be 'msg.byteLength' bytes")
assert(mac.byteLength === crypto_secretbox_MACBYTES, "mac must be 'crypto_secretbox_MACBYTES' bytes")
assert(n.byteLength === crypto_secretbox_NONCEBYTES, "n must be 'crypto_secretbox_NONCEBYTES' bytes")
assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes")
const tmp = new Uint8Array(o.byteLength + mac.byteLength)
tmp.set(mac)
tmp.set(o, mac.byteLength)
return crypto_secretbox_open_easy(msg, tmp, n, k)
}
function crypto_secretbox_easy (o, msg, n, k) {
assert(o.byteLength === msg.byteLength + crypto_secretbox_MACBYTES, "o must be 'msg.byteLength + crypto_secretbox_MACBYTES' bytes")
assert(n.byteLength === crypto_secretbox_NONCEBYTES, "n must be 'crypto_secretbox_NONCEBYTES' bytes")
assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes")
const m = new Uint8Array(crypto_secretbox_ZEROBYTES + msg.byteLength)
const c = new Uint8Array(m.byteLength)
m.set(msg, crypto_secretbox_ZEROBYTES)
crypto_secretbox(c, m, n, k)
o.set(c.subarray(crypto_secretbox_BOXZEROBYTES))
}
function crypto_secretbox_open_easy (msg, box, n, k) {
assert(box.byteLength === msg.byteLength + crypto_secretbox_MACBYTES, "box must be 'msg.byteLength + crypto_secretbox_MACBYTES' bytes")
assert(n.byteLength === crypto_secretbox_NONCEBYTES, "n must be 'crypto_secretbox_NONCEBYTES' bytes")
assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes")
const c = new Uint8Array(crypto_secretbox_BOXZEROBYTES + box.byteLength)
const m = new Uint8Array(c.byteLength)
c.set(box, crypto_secretbox_BOXZEROBYTES)
if (crypto_secretbox_open(m, c, n, k) === false) return false
msg.set(m.subarray(crypto_secretbox_ZEROBYTES))
return true
}

271
crypto_secretstream.js Normal file
View File

@ -0,0 +1,271 @@
/* eslint-disable camelcase */
const assert = require('nanoassert')
const { randombytes_buf } = require('./randombytes')
const {
crypto_stream_chacha20_ietf,
crypto_stream_chacha20_ietf_xor,
crypto_stream_chacha20_ietf_xor_ic,
crypto_stream_chacha20_ietf_KEYBYTES
} = require('./crypto_stream_chacha20')
const { crypto_core_hchacha20, crypto_core_hchacha20_INPUTBYTES } = require('./internal/hchacha20')
const Poly1305 = require('./internal/poly1305')
const { sodium_increment, sodium_is_zero, sodium_memcmp } = require('./helpers')
const crypto_onetimeauth_poly1305_BYTES = 16
const crypto_secretstream_xchacha20poly1305_COUNTERBYTES = 4
const crypto_secretstream_xchacha20poly1305_INONCEBYTES = 8
const crypto_aead_xchacha20poly1305_ietf_KEYBYTES = 32
const crypto_secretstream_xchacha20poly1305_KEYBYTES = crypto_aead_xchacha20poly1305_ietf_KEYBYTES
const crypto_aead_xchacha20poly1305_ietf_NPUBBYTES = 24
const crypto_secretstream_xchacha20poly1305_HEADERBYTES = crypto_aead_xchacha20poly1305_ietf_NPUBBYTES
const crypto_aead_xchacha20poly1305_ietf_ABYTES = 16
const crypto_secretstream_xchacha20poly1305_ABYTES = 1 + crypto_aead_xchacha20poly1305_ietf_ABYTES
const crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX = Number.MAX_SAFE_INTEGER
const crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX = Number.MAX_SAFE_INTEGER
const crypto_secretstream_xchacha20poly1305_TAGBYTES = 1
const crypto_secretstream_xchacha20poly1305_TAG_MESSAGE = new Uint8Array([0])
const crypto_secretstream_xchacha20poly1305_TAG_PUSH = new Uint8Array([1])
const crypto_secretstream_xchacha20poly1305_TAG_REKEY = new Uint8Array([2])
const crypto_secretstream_xchacha20poly1305_TAG_FINAL = new Uint8Array([crypto_secretstream_xchacha20poly1305_TAG_PUSH | crypto_secretstream_xchacha20poly1305_TAG_REKEY])
const crypto_secretstream_xchacha20poly1305_STATEBYTES = crypto_secretstream_xchacha20poly1305_KEYBYTES +
crypto_secretstream_xchacha20poly1305_INONCEBYTES + crypto_secretstream_xchacha20poly1305_COUNTERBYTES + 8
const KEY_OFFSET = 0
const NONCE_OFFSET = crypto_secretstream_xchacha20poly1305_KEYBYTES
const PAD_OFFSET = NONCE_OFFSET + crypto_secretstream_xchacha20poly1305_INONCEBYTES + crypto_secretstream_xchacha20poly1305_COUNTERBYTES
const _pad0 = new Uint8Array(16)
function STORE64_LE (dest, int) {
let mul = 1
let i = 0
dest[0] = int & 0xFF
while (++i < 8 && (mul *= 0x100)) {
dest[i] = (int / mul) & 0xFF
}
}
function crypto_secretstream_xchacha20poly1305_counter_reset (state) {
assert(state.byteLength === crypto_secretstream_xchacha20poly1305_STATEBYTES,
'state is should be crypto_secretstream_xchacha20poly1305_STATEBYTES long')
const nonce = state.subarray(NONCE_OFFSET, PAD_OFFSET)
for (let i = 0; i < crypto_secretstream_xchacha20poly1305_COUNTERBYTES; i++) {
nonce[i] = 0
}
nonce[0] = 1
}
function crypto_secretstream_xchacha20poly1305_keygen (k) {
assert(k.length === crypto_secretstream_xchacha20poly1305_KEYBYTES)
randombytes_buf(k)
}
function crypto_secretstream_xchacha20poly1305_init_push (state, out, key) {
assert(state.byteLength === crypto_secretstream_xchacha20poly1305_STATEBYTES,
'state is should be crypto_secretstream_xchacha20poly1305_STATEBYTES long')
assert(out instanceof Uint8Array && out.length === crypto_secretstream_xchacha20poly1305_HEADERBYTES, 'out not byte array of length crypto_secretstream_xchacha20poly1305_HEADERBYTES')
assert(key instanceof Uint8Array && key.length === crypto_secretstream_xchacha20poly1305_KEYBYTES, 'key not byte array of length crypto_secretstream_xchacha20poly1305_KEYBYTES')
const k = state.subarray(KEY_OFFSET, NONCE_OFFSET)
const nonce = state.subarray(NONCE_OFFSET, PAD_OFFSET)
const pad = state.subarray(PAD_OFFSET)
randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES)
crypto_core_hchacha20(k, out, key, null)
crypto_secretstream_xchacha20poly1305_counter_reset(state)
for (let i = 0; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
nonce[i + crypto_secretstream_xchacha20poly1305_COUNTERBYTES] = out[i + crypto_core_hchacha20_INPUTBYTES]
}
pad.fill(0)
}
function crypto_secretstream_xchacha20poly1305_init_pull (state, _in, key) {
assert(state.byteLength === crypto_secretstream_xchacha20poly1305_STATEBYTES,
'state is should be crypto_secretstream_xchacha20poly1305_STATEBYTES long')
assert(_in instanceof Uint8Array && _in.length === crypto_secretstream_xchacha20poly1305_HEADERBYTES,
'_in not byte array of length crypto_secretstream_xchacha20poly1305_HEADERBYTES')
assert(key instanceof Uint8Array && key.length === crypto_secretstream_xchacha20poly1305_KEYBYTES,
'key not byte array of length crypto_secretstream_xchacha20poly1305_KEYBYTES')
const k = state.subarray(KEY_OFFSET, NONCE_OFFSET)
const nonce = state.subarray(NONCE_OFFSET, PAD_OFFSET)
const pad = state.subarray(PAD_OFFSET)
crypto_core_hchacha20(k, _in, key, null)
crypto_secretstream_xchacha20poly1305_counter_reset(state)
for (let i = 0; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
nonce[i + crypto_secretstream_xchacha20poly1305_COUNTERBYTES] = _in[i + crypto_core_hchacha20_INPUTBYTES]
}
pad.fill(0)
}
function crypto_secretstream_xchacha20poly1305_rekey (state) {
assert(state.byteLength === crypto_secretstream_xchacha20poly1305_STATEBYTES,
'state is should be crypto_secretstream_xchacha20poly1305_STATEBYTES long')
const k = state.subarray(KEY_OFFSET, NONCE_OFFSET)
const nonce = state.subarray(NONCE_OFFSET, PAD_OFFSET)
const new_key_and_inonce = new Uint8Array(
crypto_stream_chacha20_ietf_KEYBYTES + crypto_secretstream_xchacha20poly1305_INONCEBYTES)
let i
for (i = 0; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
new_key_and_inonce[i] = k[i]
}
for (i = 0; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] =
nonce[crypto_secretstream_xchacha20poly1305_COUNTERBYTES + i]
}
crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce, nonce, k)
for (i = 0; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
k[i] = new_key_and_inonce[i]
}
for (i = 0; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
nonce[crypto_secretstream_xchacha20poly1305_COUNTERBYTES + i] =
new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i]
}
crypto_secretstream_xchacha20poly1305_counter_reset(state)
}
function crypto_secretstream_xchacha20poly1305_push (state, out, m, ad, tag) {
assert(state.byteLength === crypto_secretstream_xchacha20poly1305_STATEBYTES,
'state is should be crypto_secretstream_xchacha20poly1305_STATEBYTES long')
if (!ad) ad = new Uint8Array(0)
const k = state.subarray(KEY_OFFSET, NONCE_OFFSET)
const nonce = state.subarray(NONCE_OFFSET, PAD_OFFSET)
const block = new Uint8Array(64)
const slen = new Uint8Array(8)
assert(crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX <=
crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX)
crypto_stream_chacha20_ietf(block, nonce, k)
const poly = new Poly1305(block)
block.fill(0)
poly.update(ad, 0, ad.byteLength)
poly.update(_pad0, 0, (0x10 - ad.byteLength) & 0xf)
block[0] = tag[0]
crypto_stream_chacha20_ietf_xor_ic(block, block, nonce, 1, k)
poly.update(block, 0, block.byteLength)
out[0] = block[0]
const c = out.subarray(1, out.byteLength)
crypto_stream_chacha20_ietf_xor_ic(c, m, nonce, 2, k)
poly.update(c, 0, m.byteLength)
poly.update(_pad0, 0, (0x10 - block.byteLength + m.byteLength) & 0xf)
STORE64_LE(slen, ad.byteLength)
poly.update(slen, 0, slen.byteLength)
STORE64_LE(slen, block.byteLength + m.byteLength)
poly.update(slen, 0, slen.byteLength)
const mac = out.subarray(1 + m.byteLength, out.byteLength)
poly.finish(mac, 0)
assert(crypto_onetimeauth_poly1305_BYTES >=
crypto_secretstream_xchacha20poly1305_INONCEBYTES)
xor_buf(nonce.subarray(crypto_secretstream_xchacha20poly1305_COUNTERBYTES, nonce.length),
mac, crypto_secretstream_xchacha20poly1305_INONCEBYTES)
sodium_increment(nonce)
if ((tag[0] & crypto_secretstream_xchacha20poly1305_TAG_REKEY) !== 0 ||
sodium_is_zero(nonce.subarray(0, crypto_secretstream_xchacha20poly1305_COUNTERBYTES))) {
crypto_secretstream_xchacha20poly1305_rekey(state)
}
return crypto_secretstream_xchacha20poly1305_ABYTES + m.byteLength
}
function crypto_secretstream_xchacha20poly1305_pull (state, m, tag, _in, ad) {
assert(state.byteLength === crypto_secretstream_xchacha20poly1305_STATEBYTES,
'state is should be crypto_secretstream_xchacha20poly1305_STATEBYTES long')
if (!ad) ad = new Uint8Array(0)
const k = state.subarray(KEY_OFFSET, NONCE_OFFSET)
const nonce = state.subarray(NONCE_OFFSET, PAD_OFFSET)
const block = new Uint8Array(64)
const slen = new Uint8Array(8)
const mac = new Uint8Array(crypto_onetimeauth_poly1305_BYTES)
assert(_in.byteLength >= crypto_secretstream_xchacha20poly1305_ABYTES,
'ciphertext is too short.')
const mlen = _in.byteLength - crypto_secretstream_xchacha20poly1305_ABYTES
crypto_stream_chacha20_ietf(block, nonce, k)
const poly = new Poly1305(block)
block.fill(0) // sodium_memzero(block, sizeof block);
poly.update(ad, 0, ad.byteLength)
poly.update(_pad0, 0, (0x10 - ad.byteLength) & 0xf)
block.fill(0) // memset(block, 0, sizeof block);
block[0] = _in[0]
crypto_stream_chacha20_ietf_xor_ic(block, block, nonce, 1, k)
tag[0] = block[0]
block[0] = _in[0]
poly.update(block, 0, block.byteLength)
const c = _in.subarray(1, _in.length)
poly.update(c, 0, mlen)
poly.update(_pad0, 0, (0x10 - block.byteLength + mlen) & 0xf)
STORE64_LE(slen, ad.byteLength)
poly.update(slen, 0, slen.byteLength)
STORE64_LE(slen, block.byteLength + m.byteLength)
poly.update(slen, 0, slen.byteLength)
poly.finish(mac, 0)
const stored_mac = _in.subarray(1 + mlen, _in.length)
if (!sodium_memcmp(mac, stored_mac)) {
mac.fill(0)
throw new Error('MAC could not be verified.')
}
crypto_stream_chacha20_ietf_xor_ic(m, c.subarray(0, m.length), nonce, 2, k)
xor_buf(nonce.subarray(crypto_secretstream_xchacha20poly1305_COUNTERBYTES, nonce.length),
mac, crypto_secretstream_xchacha20poly1305_INONCEBYTES)
sodium_increment(nonce)
if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) !== 0 ||
sodium_is_zero(nonce.subarray(0, crypto_secretstream_xchacha20poly1305_COUNTERBYTES))) {
crypto_secretstream_xchacha20poly1305_rekey(state)
}
return mlen
}
function xor_buf (out, _in, n) {
for (let i = 0; i < n; i++) {
out[i] ^= _in[i]
}
}
module.exports = {
crypto_secretstream_xchacha20poly1305_keygen,
crypto_secretstream_xchacha20poly1305_init_push,
crypto_secretstream_xchacha20poly1305_init_pull,
crypto_secretstream_xchacha20poly1305_rekey,
crypto_secretstream_xchacha20poly1305_push,
crypto_secretstream_xchacha20poly1305_pull,
crypto_secretstream_xchacha20poly1305_STATEBYTES,
crypto_secretstream_xchacha20poly1305_ABYTES,
crypto_secretstream_xchacha20poly1305_HEADERBYTES,
crypto_secretstream_xchacha20poly1305_KEYBYTES,
crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX,
crypto_secretstream_xchacha20poly1305_TAGBYTES,
crypto_secretstream_xchacha20poly1305_TAG_MESSAGE,
crypto_secretstream_xchacha20poly1305_TAG_PUSH,
crypto_secretstream_xchacha20poly1305_TAG_REKEY,
crypto_secretstream_xchacha20poly1305_TAG_FINAL
}

View File

@ -1,17 +1,14 @@
var siphash = require('siphash24') var siphash = require('siphash24')
if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.')
exports.crypto_shorthash_PRIMITIVE = 'siphash24' exports.crypto_shorthash_PRIMITIVE = 'siphash24'
exports.crypto_shorthash_BYTES = siphash.BYTES exports.crypto_shorthash_BYTES = siphash.BYTES
exports.crypto_shorthash_KEYBYTES = siphash.KEYBYTES exports.crypto_shorthash_KEYBYTES = siphash.KEYBYTES
exports.crypto_shorthash_WASM_SUPPORTED = siphash.WASM_SUPPORTED exports.crypto_shorthash_WASM_SUPPORTED = siphash.WASM_SUPPORTED
exports.crypto_shorthash_WASM_LOADED = siphash.WASM_LOADED exports.crypto_shorthash_WASM_LOADED = siphash.WASM_LOADED
exports.crypto_shorthash_ready = siphash.ready
exports.crypto_shorthash = shorthash exports.crypto_shorthash = shorthash
siphash.ready(function () {
exports.crypto_shorthash_WASM_LOADED = siphash.WASM_LOADED
})
function shorthash (out, data, key, noAssert) { function shorthash (out, data, key, noAssert) {
siphash(data, key, out, noAssert) siphash(data, key, out, noAssert)
} }

469
crypto_sign.js Normal file
View File

@ -0,0 +1,469 @@
/* eslint-disable camelcase, one-var */
const { crypto_verify_32 } = require('./crypto_verify')
const { crypto_hash } = require('./crypto_hash')
const {
gf, gf0, gf1, D, D2,
X, Y, I, A, Z, M, S,
sel25519, pack25519,
inv25519, unpack25519
} = require('./internal/ed25519')
const { randombytes } = require('./randombytes')
const { crypto_scalarmult_BYTES } = require('./crypto_scalarmult.js')
const { crypto_hash_sha512_BYTES } = require('./crypto_hash.js')
const assert = require('nanoassert')
const crypto_sign_ed25519_PUBLICKEYBYTES = 32
const crypto_sign_ed25519_SECRETKEYBYTES = 64
const crypto_sign_ed25519_SEEDBYTES = 32
const crypto_sign_ed25519_BYTES = 64
const crypto_sign_BYTES = crypto_sign_ed25519_BYTES
const crypto_sign_PUBLICKEYBYTES = crypto_sign_ed25519_PUBLICKEYBYTES
const crypto_sign_SECRETKEYBYTES = crypto_sign_ed25519_SECRETKEYBYTES
const crypto_sign_SEEDBYTES = crypto_sign_ed25519_SEEDBYTES
module.exports = {
crypto_sign_keypair,
crypto_sign_seed_keypair,
crypto_sign,
crypto_sign_detached,
crypto_sign_open,
crypto_sign_verify_detached,
crypto_sign_BYTES,
crypto_sign_PUBLICKEYBYTES,
crypto_sign_SECRETKEYBYTES,
crypto_sign_SEEDBYTES,
crypto_sign_ed25519_PUBLICKEYBYTES,
crypto_sign_ed25519_SECRETKEYBYTES,
crypto_sign_ed25519_SEEDBYTES,
crypto_sign_ed25519_BYTES,
crypto_sign_ed25519_pk_to_curve25519,
crypto_sign_ed25519_sk_to_curve25519,
crypto_sign_ed25519_sk_to_pk,
unpackneg,
pack
}
function set25519 (r, a) {
for (let i = 0; i < 16; i++) r[i] = a[i] | 0
}
function pow2523 (o, i) {
var c = gf()
var a
for (a = 0; a < 16; a++) c[a] = i[a]
for (a = 250; a >= 0; a--) {
S(c, c)
if (a !== 1) M(c, c, i)
}
for (a = 0; a < 16; a++) o[a] = c[a]
}
function add (p, q) {
var a = gf(), b = gf(), c = gf(),
d = gf(), e = gf(), f = gf(),
g = gf(), h = gf(), t = gf()
Z(a, p[1], p[0])
Z(t, q[1], q[0])
M(a, a, t)
A(b, p[0], p[1])
A(t, q[0], q[1])
M(b, b, t)
M(c, p[3], q[3])
M(c, c, D2)
M(d, p[2], q[2])
A(d, d, d)
Z(e, b, a)
Z(f, d, c)
A(g, d, c)
A(h, b, a)
M(p[0], e, f)
M(p[1], h, g)
M(p[2], g, f)
M(p[3], e, h)
}
function cswap (p, q, b) {
var i
for (i = 0; i < 4; i++) {
sel25519(p[i], q[i], b)
}
}
function pack (r, p) {
var tx = gf(), ty = gf(), zi = gf()
inv25519(zi, p[2])
M(tx, p[0], zi)
M(ty, p[1], zi)
pack25519(r, ty)
r[31] ^= par25519(tx) << 7
}
function scalarmult (p, q, s) {
// don't mutate q
var h = [gf(q[0]), gf(q[1]), gf(q[2]), gf(q[3])]
var b, i
set25519(p[0], gf0)
set25519(p[1], gf1)
set25519(p[2], gf1)
set25519(p[3], gf0)
for (i = 255; i >= 0; --i) {
b = (s[(i / 8) | 0] >> (i & 7)) & 1
cswap(p, h, b)
add(h, p)
add(p, p)
cswap(p, h, b)
}
}
function scalarbase (p, s) {
var q = [gf(), gf(), gf(), gf()]
set25519(q[0], X)
set25519(q[1], Y)
set25519(q[2], gf1)
M(q[3], X, Y)
scalarmult(p, q, s)
}
function crypto_sign_keypair (pk, sk, seeded) {
check(pk, crypto_sign_PUBLICKEYBYTES)
check(sk, crypto_sign_SECRETKEYBYTES)
var d = new Uint8Array(64)
var p = [gf(), gf(), gf(), gf()]
var i
if (!seeded) randombytes(sk, 32)
crypto_hash(d, sk, 32)
d[0] &= 248
d[31] &= 127
d[31] |= 64
scalarbase(p, d)
pack(pk, p)
for (i = 0; i < 32; i++) sk[i + 32] = pk[i]
}
function crypto_sign_seed_keypair (pk, sk, seed) {
check(seed, crypto_sign_SEEDBYTES)
sk.set(seed)
return crypto_sign_keypair(pk, sk, true)
}
var L = new Float64Array([0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10])
function modL (r, x) {
var carry, i, j, k
for (i = 63; i >= 32; --i) {
carry = 0
for (j = i - 32, k = i - 12; j < k; ++j) {
x[j] += carry - 16 * x[i] * L[j - (i - 32)]
carry = (x[j] + 128) >> 8
x[j] -= carry * 256
}
x[j] += carry
x[i] = 0
}
carry = 0
for (j = 0; j < 32; j++) {
x[j] += carry - (x[31] >> 4) * L[j]
carry = x[j] >> 8
x[j] &= 255
}
for (j = 0; j < 32; j++) x[j] -= carry * L[j]
for (i = 0; i < 32; i++) {
x[i + 1] += x[i] >> 8
r[i] = x[i] & 255
}
}
function reduce (r) {
var x = new Float64Array(64)
for (let i = 0; i < 64; i++) x[i] = r[i]
for (let i = 0; i < 64; i++) r[i] = 0
modL(r, x)
}
// Note: difference from C - smlen returned, not passed as argument.
function crypto_sign (sm, m, sk) {
check(sm, crypto_sign_BYTES + m.length)
check(m, 0)
check(sk, crypto_sign_SECRETKEYBYTES)
var n = m.length
var d = new Uint8Array(64), h = new Uint8Array(64), r = new Uint8Array(64)
var i, j, x = new Float64Array(64)
var p = [gf(), gf(), gf(), gf()]
crypto_hash(d, sk, 32)
d[0] &= 248
d[31] &= 127
d[31] |= 64
var smlen = n + 64
for (i = 0; i < n; i++) sm[64 + i] = m[i]
for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i]
crypto_hash(r, sm.subarray(32), n + 32)
reduce(r)
scalarbase(p, r)
pack(sm, p)
for (i = 32; i < 64; i++) sm[i] = sk[i]
crypto_hash(h, sm, n + 64)
reduce(h)
for (i = 0; i < 64; i++) x[i] = 0
for (i = 0; i < 32; i++) x[i] = r[i]
for (i = 0; i < 32; i++) {
for (j = 0; j < 32; j++) {
x[i + j] += h[i] * d[j]
}
}
modL(sm.subarray(32), x)
return smlen
}
function crypto_sign_detached (sig, m, sk) {
var sm = new Uint8Array(m.length + crypto_sign_BYTES)
crypto_sign(sm, m, sk)
for (let i = 0; i < crypto_sign_BYTES; i++) sig[i] = sm[i]
}
function unpackneg (r, p) {
var t = gf(), chk = gf(), num = gf(),
den = gf(), den2 = gf(), den4 = gf(),
den6 = gf()
set25519(r[2], gf1)
unpack25519(r[1], p)
S(num, r[1])
M(den, num, D)
Z(num, num, r[2])
A(den, r[2], den)
S(den2, den)
S(den4, den2)
M(den6, den4, den2)
M(t, den6, num)
M(t, t, den)
pow2523(t, t)
M(t, t, num)
M(t, t, den)
M(t, t, den)
M(r[0], t, den)
S(chk, r[0])
M(chk, chk, den)
if (!neq25519(chk, num)) M(r[0], r[0], I)
S(chk, r[0])
M(chk, chk, den)
if (!neq25519(chk, num)) return false
if (par25519(r[0]) === (p[31] >> 7)) {
Z(r[0], gf(), r[0])
}
M(r[3], r[0], r[1])
return true
}
/* eslint-disable no-unused-vars */
function crypto_sign_open (msg, sm, pk) {
check(msg, sm.length - crypto_sign_BYTES)
check(sm, crypto_sign_BYTES)
check(pk, crypto_sign_PUBLICKEYBYTES)
var n = sm.length
var m = new Uint8Array(sm.length)
var i, mlen
var t = new Uint8Array(32), h = new Uint8Array(64)
var p = [gf(), gf(), gf(), gf()],
q = [gf(), gf(), gf(), gf()]
mlen = -1
if (n < 64) return false
if (!unpackneg(q, pk)) return false
for (i = 0; i < n; i++) m[i] = sm[i]
for (i = 0; i < 32; i++) m[i + 32] = pk[i]
crypto_hash(h, m, n)
reduce(h)
scalarmult(p, q, h)
scalarbase(q, sm.subarray(32))
add(p, q)
pack(t, p)
n -= 64
if (!crypto_verify_32(sm, 0, t, 0)) {
for (i = 0; i < n; i++) m[i] = 0
return false
// throw new Error('crypto_sign_open failed')
}
for (i = 0; i < n; i++) msg[i] = sm[i + 64]
mlen = n
return true
}
/* eslint-enable no-unused-vars */
function crypto_sign_verify_detached (sig, m, pk) {
check(sig, crypto_sign_BYTES)
var sm = new Uint8Array(m.length + crypto_sign_BYTES)
var i = 0
for (i = 0; i < crypto_sign_BYTES; i++) sm[i] = sig[i]
for (i = 0; i < m.length; i++) sm[i + crypto_sign_BYTES] = m[i]
return crypto_sign_open(m, sm, pk)
}
function par25519 (a) {
var d = new Uint8Array(32)
pack25519(d, a)
return d[0] & 1
}
function neq25519 (a, b) {
var c = new Uint8Array(32), d = new Uint8Array(32)
pack25519(c, a)
pack25519(d, b)
return crypto_verify_32(c, 0, d, 0)
}
function ed25519_mul_l (p, q) {
scalarmult(p, q, L)
}
function ed25519_is_on_main_subgroup (p) {
var pl = [gf(), gf(), gf(), gf()]
ed25519_mul_l(pl, p)
var zero = 0
for (let i = 0; i < 16; i++) {
zero |= (pl[0][i] & 0xffff)
}
return zero === 0
}
function crypto_sign_ed25519_pk_to_curve25519 (x25519_pk, ed25519_pk) {
check(x25519_pk, crypto_sign_PUBLICKEYBYTES)
check(ed25519_pk, crypto_sign_ed25519_PUBLICKEYBYTES)
var a = [gf(), gf(), gf(), gf()]
var x = gf([1])
var one_minus_y = gf([1])
assert(
isSmallOrder(ed25519_pk) &&
unpackneg(a, ed25519_pk) &&
ed25519_is_on_main_subgroup(a), 'Cannot convert key: bad point')
for (let i = 0; i < a.length; i++) {
pack25519(x25519_pk, a[i])
}
Z(one_minus_y, one_minus_y, a[1])
A(x, x, a[1])
inv25519(one_minus_y, one_minus_y)
M(x, x, one_minus_y)
pack25519(x25519_pk, x)
return 0
}
function isSmallOrder (s) {
Uint8Array.from([])
var bad_points = [
// 0 (order 4)
Uint8Array.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
// 1 (order 1)
Uint8Array.from([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
// 2707385501144840649318225287225658788936804267575313519463743609750303402022(order 8)
Uint8Array.from([0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3,
0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x05, 0xd3,
0xc6, 0x33, 0x39, 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05]),
// 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8)
Uint8Array.from([0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c,
0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c,
0x39, 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a]),
// p-1 (order 2)
Uint8Array.from([0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]),
// p (=0 order 4)
Uint8Array.from([0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]),
// p + 1 (=1 order 1)
Uint8Array.from([0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f])
]
var c = new Uint8Array(7)
var j
check(bad_points, 7)
for (let i = 0; i < bad_points.length; i++) {
for (j = 0; j < 31; j++) {
c[i] |= s[j] ^ bad_points[i][j]
}
}
for (let i = 0; i < bad_points.length; i++) {
c[i] |= (s[j] & 0x7f) ^ bad_points[i][j]
}
var k = 0
for (let i = 0; i < bad_points.length; i++) {
k |= (c[i] - 1)
}
return ((k >> 8) & 1) === 0
}
function crypto_sign_ed25519_sk_to_pk (pk, sk) {
check(pk, crypto_sign_ed25519_PUBLICKEYBYTES)
pk.set(sk.subarray(crypto_sign_ed25519_SEEDBYTES))
return pk
}
function crypto_sign_ed25519_sk_to_curve25519 (curveSk, edSk) {
assert(curveSk && curveSk.byteLength === crypto_scalarmult_BYTES, "curveSk must be 'crypto_sign_SECRETKEYBYTES' long")
assert(edSk && edSk.byteLength === crypto_sign_ed25519_SECRETKEYBYTES, "edSk must be 'crypto_sign_ed25519_SECRETKEYBYTES' long")
var h = new Uint8Array(crypto_hash_sha512_BYTES)
crypto_hash(h, edSk, 32)
h[0] &= 248
h[31] &= 127
h[31] |= 64
curveSk.set(h.subarray(0, crypto_scalarmult_BYTES))
h.fill(0)
return curveSk
}
function check (buf, len, arg = 'Argument') {
if (!buf || (len && buf.length < len)) throw new Error(arg + ' must be a buffer' + (len ? ' of length ' + len : ''))
}

View File

@ -1,17 +1,22 @@
var xsalsa20 = require('xsalsa20') /* eslint-disable camelcase */
const xsalsa20 = require('xsalsa20')
if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.')
exports.crypto_stream_KEYBYTES = 32 exports.crypto_stream_KEYBYTES = 32
exports.crypto_stream_NONCEBYTES = 24 exports.crypto_stream_NONCEBYTES = 24
exports.crypto_stream_PRIMITIVE = 'xsalsa20' exports.crypto_stream_PRIMITIVE = 'xsalsa20'
exports.crypto_stream_xsalsa20_MESSAGEBYTES_MAX = Number.MAX_SAFE_INTEGER
exports.crypto_stream = function (out, nonce, key) { exports.crypto_stream = function (c, nonce, key) {
out.fill(0) c.fill(0)
exports.crypto_stream_xor(out, out, nonce, key) exports.crypto_stream_xor(c, c, nonce, key)
} }
exports.crypto_stream_xor = function (out, inp, nonce, key) { exports.crypto_stream_xor = function (c, m, nonce, key) {
var xor = xsalsa20(nonce, key) const xor = xsalsa20(nonce, key)
xor.update(inp, out)
xor.update(m, c)
xor.final() xor.final()
} }

84
crypto_stream_chacha20.js Normal file
View File

@ -0,0 +1,84 @@
const assert = require('nanoassert')
const Chacha20 = require('chacha20-universal')
if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.')
exports.crypto_stream_chacha20_KEYBYTES = 32
exports.crypto_stream_chacha20_NONCEBYTES = 8
exports.crypto_stream_chacha20_MESSAGEBYTES_MAX = Number.MAX_SAFE_INTEGER
exports.crypto_stream_chacha20_ietf_KEYBYTES = 32
exports.crypto_stream_chacha20_ietf_NONCEBYTES = 12
exports.crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX = 2 ** 32
exports.crypto_stream_chacha20 = function (c, n, k) {
c.fill(0)
exports.crypto_stream_chacha20_xor(c, c, n, k)
}
exports.crypto_stream_chacha20_xor = function (c, m, n, k) {
assert(n.byteLength === exports.crypto_stream_chacha20_NONCEBYTES,
'n should be crypto_stream_chacha20_NONCEBYTES')
assert(k.byteLength === exports.crypto_stream_chacha20_KEYBYTES,
'k should be crypto_stream_chacha20_KEYBYTES')
const xor = new Chacha20(n, k)
xor.update(c, m)
xor.final()
}
exports.crypto_stream_chacha20_xor_ic = function (c, m, n, ic, k) {
assert(n.byteLength === exports.crypto_stream_chacha20_NONCEBYTES,
'n should be crypto_stream_chacha20_NONCEBYTES')
assert(k.byteLength === exports.crypto_stream_chacha20_KEYBYTES,
'k should be crypto_stream_chacha20_KEYBYTES')
const xor = new Chacha20(n, k, ic)
xor.update(c, m)
xor.final()
}
exports.crypto_stream_chacha20_xor_instance = function (n, k) {
assert(n.byteLength === exports.crypto_stream_chacha20_NONCEBYTES,
'n should be crypto_stream_chacha20_NONCEBYTES')
assert(k.byteLength === exports.crypto_stream_chacha20_KEYBYTES,
'k should be crypto_stream_chacha20_KEYBYTES')
return new Chacha20(n, k)
}
exports.crypto_stream_chacha20_ietf = function (c, n, k) {
c.fill(0)
exports.crypto_stream_chacha20_ietf_xor(c, c, n, k)
}
exports.crypto_stream_chacha20_ietf_xor = function (c, m, n, k) {
assert(n.byteLength === exports.crypto_stream_chacha20_ietf_NONCEBYTES,
'n should be crypto_stream_chacha20_ietf_NONCEBYTES')
assert(k.byteLength === exports.crypto_stream_chacha20_ietf_KEYBYTES,
'k should be crypto_stream_chacha20_ietf_KEYBYTES')
const xor = new Chacha20(n, k)
xor.update(c, m)
xor.final()
}
exports.crypto_stream_chacha20_ietf_xor_ic = function (c, m, n, ic, k) {
assert(n.byteLength === exports.crypto_stream_chacha20_ietf_NONCEBYTES,
'n should be crypto_stream_chacha20_ietf_NONCEBYTES')
assert(k.byteLength === exports.crypto_stream_chacha20_ietf_KEYBYTES,
'k should be crypto_stream_chacha20_ietf_KEYBYTES')
const xor = new Chacha20(n, k, ic)
xor.update(c, m)
xor.final()
}
exports.crypto_stream_chacha20_ietf_xor_instance = function (n, k) {
assert(n.byteLength === exports.crypto_stream_chacha20_ietf_NONCEBYTES,
'n should be crypto_stream_chacha20_ietf_NONCEBYTES')
assert(k.byteLength === exports.crypto_stream_chacha20_ietf_KEYBYTES,
'k should be crypto_stream_chacha20_ietf_KEYBYTES')
return new Chacha20(n, k)
}

29
crypto_verify.js Normal file
View File

@ -0,0 +1,29 @@
/* eslint-disable camelcase */
module.exports = {
crypto_verify_16,
crypto_verify_32,
crypto_verify_64
}
function vn (x, xi, y, yi, n) {
var d = 0
for (let i = 0; i < n; i++) d |= x[xi + i] ^ y[yi + i]
return (1 & ((d - 1) >>> 8)) - 1
}
// Make non enumerable as this is an internal function
Object.defineProperty(module.exports, 'vn', {
value: vn
})
function crypto_verify_16 (x, xi, y, yi) {
return vn(x, xi, y, yi, 16) === 0
}
function crypto_verify_32 (x, xi, y, yi) {
return vn(x, xi, y, yi, 32) === 0
}
function crypto_verify_64 (x, xi, y, yi) {
return vn(x, xi, y, yi, 64) === 0
}

View File

@ -1,19 +1,19 @@
var sodium = require('./') const sodium = require('./')
var key = new Buffer(sodium.crypto_secretbox_KEYBYTES) const key = Buffer.alloc(sodium.crypto_secretbox_KEYBYTES)
var nonce = new Buffer(sodium.crypto_secretbox_NONCEBYTES) const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES)
sodium.randombytes_buf(key) sodium.randombytes_buf(key)
sodium.randombytes_buf(nonce) sodium.randombytes_buf(nonce)
var message = new Buffer('Hello, World!') const message = Buffer.from('Hello, World!')
var cipher = new Buffer(message.length + sodium.crypto_secretbox_MACBYTES) const cipher = Buffer.alloc(message.length + sodium.crypto_secretbox_MACBYTES)
sodium.crypto_secretbox_easy(cipher, message, nonce, key) sodium.crypto_secretbox_easy(cipher, message, nonce, key)
console.log('Encrypted:', cipher) console.log('Encrypted:', cipher)
var plainText = new Buffer(cipher.length - sodium.crypto_secretbox_MACBYTES) const plainText = Buffer.alloc(cipher.length - sodium.crypto_secretbox_MACBYTES)
sodium.crypto_secretbox_open_easy(plainText, cipher, nonce, key) sodium.crypto_secretbox_open_easy(plainText, cipher, nonce, key)

31
helpers.js Normal file
View File

@ -0,0 +1,31 @@
/* eslint-disable camelcase */
const assert = require('nanoassert')
const { vn } = require('./crypto_verify')
function sodium_increment (n) {
const nlen = n.byteLength
var c = 1
for (var i = 0; i < nlen; i++) {
c += n[i]
n[i] = c
c >>= 8
}
}
function sodium_memcmp (a, b) {
assert(a.byteLength === b.byteLength, 'buffers must be the same size')
return vn(a, 0, b, 0, a.byteLength) === 0
}
function sodium_is_zero (arr) {
var d = 0
for (let i = 0; i < arr.length; i++) d |= arr[i]
return d === 0
}
module.exports = {
sodium_increment,
sodium_memcmp,
sodium_is_zero
}

1805
index.js

File diff suppressed because it is too large Load Diff

483
internal/ed25519.js Normal file
View File

@ -0,0 +1,483 @@
if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.')
var gf = function(init) {
var i, r = new Float64Array(16);
if (init) for (i = 0; i < init.length; i++) r[i] = init[i];
return r;
}
var _0 = new Uint8Array(16);
var _9 = new Uint8Array(32); _9[0] = 9;
var gf0 = gf(),
gf1 = gf([1]),
_121665 = gf([0xdb41, 1]),
D = gf([0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]),
D2 = gf([0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]),
X = gf([0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]),
Y = gf([0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]),
I = gf([0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]);
function A(o, a, b) {
for (var i = 0; i < 16; i++) o[i] = a[i] + b[i];
}
function Z(o, a, b) {
for (var i = 0; i < 16; i++) o[i] = a[i] - b[i];
}
function M(o, a, b) {
var v, c,
t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0,
t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0,
t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0,
t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0,
b0 = b[0],
b1 = b[1],
b2 = b[2],
b3 = b[3],
b4 = b[4],
b5 = b[5],
b6 = b[6],
b7 = b[7],
b8 = b[8],
b9 = b[9],
b10 = b[10],
b11 = b[11],
b12 = b[12],
b13 = b[13],
b14 = b[14],
b15 = b[15];
v = a[0];
t0 += v * b0;
t1 += v * b1;
t2 += v * b2;
t3 += v * b3;
t4 += v * b4;
t5 += v * b5;
t6 += v * b6;
t7 += v * b7;
t8 += v * b8;
t9 += v * b9;
t10 += v * b10;
t11 += v * b11;
t12 += v * b12;
t13 += v * b13;
t14 += v * b14;
t15 += v * b15;
v = a[1];
t1 += v * b0;
t2 += v * b1;
t3 += v * b2;
t4 += v * b3;
t5 += v * b4;
t6 += v * b5;
t7 += v * b6;
t8 += v * b7;
t9 += v * b8;
t10 += v * b9;
t11 += v * b10;
t12 += v * b11;
t13 += v * b12;
t14 += v * b13;
t15 += v * b14;
t16 += v * b15;
v = a[2];
t2 += v * b0;
t3 += v * b1;
t4 += v * b2;
t5 += v * b3;
t6 += v * b4;
t7 += v * b5;
t8 += v * b6;
t9 += v * b7;
t10 += v * b8;
t11 += v * b9;
t12 += v * b10;
t13 += v * b11;
t14 += v * b12;
t15 += v * b13;
t16 += v * b14;
t17 += v * b15;
v = a[3];
t3 += v * b0;
t4 += v * b1;
t5 += v * b2;
t6 += v * b3;
t7 += v * b4;
t8 += v * b5;
t9 += v * b6;
t10 += v * b7;
t11 += v * b8;
t12 += v * b9;
t13 += v * b10;
t14 += v * b11;
t15 += v * b12;
t16 += v * b13;
t17 += v * b14;
t18 += v * b15;
v = a[4];
t4 += v * b0;
t5 += v * b1;
t6 += v * b2;
t7 += v * b3;
t8 += v * b4;
t9 += v * b5;
t10 += v * b6;
t11 += v * b7;
t12 += v * b8;
t13 += v * b9;
t14 += v * b10;
t15 += v * b11;
t16 += v * b12;
t17 += v * b13;
t18 += v * b14;
t19 += v * b15;
v = a[5];
t5 += v * b0;
t6 += v * b1;
t7 += v * b2;
t8 += v * b3;
t9 += v * b4;
t10 += v * b5;
t11 += v * b6;
t12 += v * b7;
t13 += v * b8;
t14 += v * b9;
t15 += v * b10;
t16 += v * b11;
t17 += v * b12;
t18 += v * b13;
t19 += v * b14;
t20 += v * b15;
v = a[6];
t6 += v * b0;
t7 += v * b1;
t8 += v * b2;
t9 += v * b3;
t10 += v * b4;
t11 += v * b5;
t12 += v * b6;
t13 += v * b7;
t14 += v * b8;
t15 += v * b9;
t16 += v * b10;
t17 += v * b11;
t18 += v * b12;
t19 += v * b13;
t20 += v * b14;
t21 += v * b15;
v = a[7];
t7 += v * b0;
t8 += v * b1;
t9 += v * b2;
t10 += v * b3;
t11 += v * b4;
t12 += v * b5;
t13 += v * b6;
t14 += v * b7;
t15 += v * b8;
t16 += v * b9;
t17 += v * b10;
t18 += v * b11;
t19 += v * b12;
t20 += v * b13;
t21 += v * b14;
t22 += v * b15;
v = a[8];
t8 += v * b0;
t9 += v * b1;
t10 += v * b2;
t11 += v * b3;
t12 += v * b4;
t13 += v * b5;
t14 += v * b6;
t15 += v * b7;
t16 += v * b8;
t17 += v * b9;
t18 += v * b10;
t19 += v * b11;
t20 += v * b12;
t21 += v * b13;
t22 += v * b14;
t23 += v * b15;
v = a[9];
t9 += v * b0;
t10 += v * b1;
t11 += v * b2;
t12 += v * b3;
t13 += v * b4;
t14 += v * b5;
t15 += v * b6;
t16 += v * b7;
t17 += v * b8;
t18 += v * b9;
t19 += v * b10;
t20 += v * b11;
t21 += v * b12;
t22 += v * b13;
t23 += v * b14;
t24 += v * b15;
v = a[10];
t10 += v * b0;
t11 += v * b1;
t12 += v * b2;
t13 += v * b3;
t14 += v * b4;
t15 += v * b5;
t16 += v * b6;
t17 += v * b7;
t18 += v * b8;
t19 += v * b9;
t20 += v * b10;
t21 += v * b11;
t22 += v * b12;
t23 += v * b13;
t24 += v * b14;
t25 += v * b15;
v = a[11];
t11 += v * b0;
t12 += v * b1;
t13 += v * b2;
t14 += v * b3;
t15 += v * b4;
t16 += v * b5;
t17 += v * b6;
t18 += v * b7;
t19 += v * b8;
t20 += v * b9;
t21 += v * b10;
t22 += v * b11;
t23 += v * b12;
t24 += v * b13;
t25 += v * b14;
t26 += v * b15;
v = a[12];
t12 += v * b0;
t13 += v * b1;
t14 += v * b2;
t15 += v * b3;
t16 += v * b4;
t17 += v * b5;
t18 += v * b6;
t19 += v * b7;
t20 += v * b8;
t21 += v * b9;
t22 += v * b10;
t23 += v * b11;
t24 += v * b12;
t25 += v * b13;
t26 += v * b14;
t27 += v * b15;
v = a[13];
t13 += v * b0;
t14 += v * b1;
t15 += v * b2;
t16 += v * b3;
t17 += v * b4;
t18 += v * b5;
t19 += v * b6;
t20 += v * b7;
t21 += v * b8;
t22 += v * b9;
t23 += v * b10;
t24 += v * b11;
t25 += v * b12;
t26 += v * b13;
t27 += v * b14;
t28 += v * b15;
v = a[14];
t14 += v * b0;
t15 += v * b1;
t16 += v * b2;
t17 += v * b3;
t18 += v * b4;
t19 += v * b5;
t20 += v * b6;
t21 += v * b7;
t22 += v * b8;
t23 += v * b9;
t24 += v * b10;
t25 += v * b11;
t26 += v * b12;
t27 += v * b13;
t28 += v * b14;
t29 += v * b15;
v = a[15];
t15 += v * b0;
t16 += v * b1;
t17 += v * b2;
t18 += v * b3;
t19 += v * b4;
t20 += v * b5;
t21 += v * b6;
t22 += v * b7;
t23 += v * b8;
t24 += v * b9;
t25 += v * b10;
t26 += v * b11;
t27 += v * b12;
t28 += v * b13;
t29 += v * b14;
t30 += v * b15;
t0 += 38 * t16;
t1 += 38 * t17;
t2 += 38 * t18;
t3 += 38 * t19;
t4 += 38 * t20;
t5 += 38 * t21;
t6 += 38 * t22;
t7 += 38 * t23;
t8 += 38 * t24;
t9 += 38 * t25;
t10 += 38 * t26;
t11 += 38 * t27;
t12 += 38 * t28;
t13 += 38 * t29;
t14 += 38 * t30;
// t15 left as is
// first car
c = 1;
v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536;
v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536;
v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536;
v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536;
v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536;
v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536;
v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536;
v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536;
v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536;
v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536;
v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536;
v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536;
v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536;
v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536;
v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536;
v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536;
t0 += c-1 + 37 * (c-1);
// second car
c = 1;
v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536;
v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536;
v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536;
v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536;
v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536;
v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536;
v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536;
v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536;
v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536;
v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536;
v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536;
v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536;
v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536;
v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536;
v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536;
v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536;
t0 += c-1 + 37 * (c-1);
o[ 0] = t0;
o[ 1] = t1;
o[ 2] = t2;
o[ 3] = t3;
o[ 4] = t4;
o[ 5] = t5;
o[ 6] = t6;
o[ 7] = t7;
o[ 8] = t8;
o[ 9] = t9;
o[10] = t10;
o[11] = t11;
o[12] = t12;
o[13] = t13;
o[14] = t14;
o[15] = t15;
}
function S(o, a) {
M(o, a, a);
}
function sel25519(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 pack25519(o, n) {
var i, j, b;
var m = gf(), t = gf();
for (i = 0; i < 16; i++) t[i] = n[i];
car25519(t);
car25519(t);
car25519(t);
for (j = 0; j < 2; j++) {
m[0] = t[0] - 0xffed;
for (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;
sel25519(t, m, 1-b);
}
for (i = 0; i < 16; i++) {
o[2*i] = t[i] & 0xff;
o[2*i+1] = t[i]>>8;
}
}
function unpack25519(o, n) {
var i;
for (i = 0; i < 16; i++) o[i] = n[2*i] + (n[2*i+1] << 8);
o[15] &= 0x7fff;
}
function inv25519(o, i) {
var c = gf();
var a;
for (a = 0; a < 16; a++) c[a] = i[a];
for (a = 253; a >= 0; a--) {
S(c, c);
if(a !== 2 && a !== 4) M(c, c, i);
}
for (a = 0; a < 16; a++) o[a] = c[a];
}
function car25519(o) {
var i, v, c = 1;
for (i = 0; i < 16; i++) {
v = o[i] + c + 65535;
c = Math.floor(v / 65536);
o[i] = v - c * 65536;
}
o[0] += c-1 + 37 * (c-1);
}
module.exports = {
gf,
A,
Z,
M,
S,
sel25519,
pack25519,
unpack25519,
inv25519,
gf0,
gf1,
_9,
_121665,
D,
D2,
X,
Y,
I
}

128
internal/hchacha20.js Normal file
View File

@ -0,0 +1,128 @@
/* eslint-disable camelcase */
const { sodium_malloc } = require('../memory')
const assert = require('nanoassert')
if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.')
const crypto_core_hchacha20_OUTPUTBYTES = 32
const crypto_core_hchacha20_INPUTBYTES = 16
const crypto_core_hchacha20_KEYBYTES = 32
const crypto_core_hchacha20_CONSTBYTES = 16
function ROTL32 (x, b) {
x &= 0xFFFFFFFF
b &= 0xFFFFFFFF
return (x << b) | (x >>> (32 - b))
}
function LOAD32_LE (src, offset) {
assert(src instanceof Uint8Array, 'src not byte array')
let w = src[offset]
w |= src[offset + 1] << 8
w |= src[offset + 2] << 16
w |= src[offset + 3] << 24
return w
}
function STORE32_LE (dest, int, offset) {
assert(dest instanceof Uint8Array, 'dest not byte array')
var mul = 1
var i = 0
dest[offset] = int & 0xFF // grab bottom byte
while (++i < 4 && (mul *= 0x100)) {
dest[offset + i] = (int / mul) & 0xFF
}
}
function QUARTERROUND (l, A, B, C, D) {
l[A] += l[B]
l[D] = ROTL32(l[D] ^ l[A], 16)
l[C] += l[D]
l[B] = ROTL32(l[B] ^ l[C], 12)
l[A] += l[B]
l[D] = ROTL32(l[D] ^ l[A], 8)
l[C] += l[D]
l[B] = ROTL32(l[B] ^ l[C], 7)
}
function crypto_core_hchacha20 (out, _in, k, c) {
assert(out instanceof Uint8Array && out.length === 32, 'out is not an array of 32 bytes')
assert(k instanceof Uint8Array && k.length === 32, 'k is not an array of 32 bytes')
assert(c === null || (c instanceof Uint8Array && c.length === 16), 'c is not null or an array of 16 bytes')
let i = 0
const x = new Uint32Array(16)
if (!c) {
x[0] = 0x61707865
x[1] = 0x3320646E
x[2] = 0x79622D32
x[3] = 0x6B206574
} else {
x[0] = LOAD32_LE(c, 0)
x[1] = LOAD32_LE(c, 4)
x[2] = LOAD32_LE(c, 8)
x[3] = LOAD32_LE(c, 12)
}
x[4] = LOAD32_LE(k, 0)
x[5] = LOAD32_LE(k, 4)
x[6] = LOAD32_LE(k, 8)
x[7] = LOAD32_LE(k, 12)
x[8] = LOAD32_LE(k, 16)
x[9] = LOAD32_LE(k, 20)
x[10] = LOAD32_LE(k, 24)
x[11] = LOAD32_LE(k, 28)
x[12] = LOAD32_LE(_in, 0)
x[13] = LOAD32_LE(_in, 4)
x[14] = LOAD32_LE(_in, 8)
x[15] = LOAD32_LE(_in, 12)
for (i = 0; i < 10; i++) {
QUARTERROUND(x, 0, 4, 8, 12)
QUARTERROUND(x, 1, 5, 9, 13)
QUARTERROUND(x, 2, 6, 10, 14)
QUARTERROUND(x, 3, 7, 11, 15)
QUARTERROUND(x, 0, 5, 10, 15)
QUARTERROUND(x, 1, 6, 11, 12)
QUARTERROUND(x, 2, 7, 8, 13)
QUARTERROUND(x, 3, 4, 9, 14)
}
STORE32_LE(out, x[0], 0)
STORE32_LE(out, x[1], 4)
STORE32_LE(out, x[2], 8)
STORE32_LE(out, x[3], 12)
STORE32_LE(out, x[12], 16)
STORE32_LE(out, x[13], 20)
STORE32_LE(out, x[14], 24)
STORE32_LE(out, x[15], 28)
return 0
}
function crypto_core_hchacha20_outputbytes () {
return crypto_core_hchacha20_OUTPUTBYTES
}
function crypto_core_hchacha20_inputbytes () {
return crypto_core_hchacha20_INPUTBYTES
}
function crypto_core_hchacha20_keybytes () {
return crypto_core_hchacha20_KEYBYTES
}
function crypto_core_hchacha20_constbytes () {
return crypto_core_hchacha20_CONSTBYTES
}
module.exports = {
crypto_core_hchacha20_INPUTBYTES,
LOAD32_LE,
STORE32_LE,
QUARTERROUND,
crypto_core_hchacha20,
crypto_core_hchacha20_outputbytes,
crypto_core_hchacha20_inputbytes,
crypto_core_hchacha20_keybytes,
crypto_core_hchacha20_constbytes
}

360
internal/poly1305.js Normal file
View File

@ -0,0 +1,360 @@
/*
* Port of Andrew Moon's Poly1305-donna-16. Public domain.
* https://github.com/floodyberry/poly1305-donna
*/
if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.')
var poly1305 = function(key) {
this.buffer = new Uint8Array(16);
this.r = new Uint16Array(10);
this.h = new Uint16Array(10);
this.pad = new Uint16Array(8);
this.leftover = 0;
this.fin = 0;
var t0, t1, t2, t3, t4, t5, t6, t7;
t0 = key[ 0] & 0xff | (key[ 1] & 0xff) << 8; this.r[0] = ( t0 ) & 0x1fff;
t1 = key[ 2] & 0xff | (key[ 3] & 0xff) << 8; this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff;
t2 = key[ 4] & 0xff | (key[ 5] & 0xff) << 8; this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03;
t3 = key[ 6] & 0xff | (key[ 7] & 0xff) << 8; this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff;
t4 = key[ 8] & 0xff | (key[ 9] & 0xff) << 8; this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff;
this.r[5] = ((t4 >>> 1)) & 0x1ffe;
t5 = key[10] & 0xff | (key[11] & 0xff) << 8; this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff;
t6 = key[12] & 0xff | (key[13] & 0xff) << 8; this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81;
t7 = key[14] & 0xff | (key[15] & 0xff) << 8; this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff;
this.r[9] = ((t7 >>> 5)) & 0x007f;
this.pad[0] = key[16] & 0xff | (key[17] & 0xff) << 8;
this.pad[1] = key[18] & 0xff | (key[19] & 0xff) << 8;
this.pad[2] = key[20] & 0xff | (key[21] & 0xff) << 8;
this.pad[3] = key[22] & 0xff | (key[23] & 0xff) << 8;
this.pad[4] = key[24] & 0xff | (key[25] & 0xff) << 8;
this.pad[5] = key[26] & 0xff | (key[27] & 0xff) << 8;
this.pad[6] = key[28] & 0xff | (key[29] & 0xff) << 8;
this.pad[7] = key[30] & 0xff | (key[31] & 0xff) << 8;
};
poly1305.prototype.blocks = function(m, mpos, bytes) {
var hibit = this.fin ? 0 : (1 << 11);
var t0, t1, t2, t3, t4, t5, t6, t7, c;
var d0, d1, d2, d3, d4, d5, d6, d7, d8, d9;
var h0 = this.h[0],
h1 = this.h[1],
h2 = this.h[2],
h3 = this.h[3],
h4 = this.h[4],
h5 = this.h[5],
h6 = this.h[6],
h7 = this.h[7],
h8 = this.h[8],
h9 = this.h[9];
var r0 = this.r[0],
r1 = this.r[1],
r2 = this.r[2],
r3 = this.r[3],
r4 = this.r[4],
r5 = this.r[5],
r6 = this.r[6],
r7 = this.r[7],
r8 = this.r[8],
r9 = this.r[9];
while (bytes >= 16) {
t0 = m[mpos+ 0] & 0xff | (m[mpos+ 1] & 0xff) << 8; h0 += ( t0 ) & 0x1fff;
t1 = m[mpos+ 2] & 0xff | (m[mpos+ 3] & 0xff) << 8; h1 += ((t0 >>> 13) | (t1 << 3)) & 0x1fff;
t2 = m[mpos+ 4] & 0xff | (m[mpos+ 5] & 0xff) << 8; h2 += ((t1 >>> 10) | (t2 << 6)) & 0x1fff;
t3 = m[mpos+ 6] & 0xff | (m[mpos+ 7] & 0xff) << 8; h3 += ((t2 >>> 7) | (t3 << 9)) & 0x1fff;
t4 = m[mpos+ 8] & 0xff | (m[mpos+ 9] & 0xff) << 8; h4 += ((t3 >>> 4) | (t4 << 12)) & 0x1fff;
h5 += ((t4 >>> 1)) & 0x1fff;
t5 = m[mpos+10] & 0xff | (m[mpos+11] & 0xff) << 8; h6 += ((t4 >>> 14) | (t5 << 2)) & 0x1fff;
t6 = m[mpos+12] & 0xff | (m[mpos+13] & 0xff) << 8; h7 += ((t5 >>> 11) | (t6 << 5)) & 0x1fff;
t7 = m[mpos+14] & 0xff | (m[mpos+15] & 0xff) << 8; h8 += ((t6 >>> 8) | (t7 << 8)) & 0x1fff;
h9 += ((t7 >>> 5)) | hibit;
c = 0;
d0 = c;
d0 += h0 * r0;
d0 += h1 * (5 * r9);
d0 += h2 * (5 * r8);
d0 += h3 * (5 * r7);
d0 += h4 * (5 * r6);
c = (d0 >>> 13); d0 &= 0x1fff;
d0 += h5 * (5 * r5);
d0 += h6 * (5 * r4);
d0 += h7 * (5 * r3);
d0 += h8 * (5 * r2);
d0 += h9 * (5 * r1);
c += (d0 >>> 13); d0 &= 0x1fff;
d1 = c;
d1 += h0 * r1;
d1 += h1 * r0;
d1 += h2 * (5 * r9);
d1 += h3 * (5 * r8);
d1 += h4 * (5 * r7);
c = (d1 >>> 13); d1 &= 0x1fff;
d1 += h5 * (5 * r6);
d1 += h6 * (5 * r5);
d1 += h7 * (5 * r4);
d1 += h8 * (5 * r3);
d1 += h9 * (5 * r2);
c += (d1 >>> 13); d1 &= 0x1fff;
d2 = c;
d2 += h0 * r2;
d2 += h1 * r1;
d2 += h2 * r0;
d2 += h3 * (5 * r9);
d2 += h4 * (5 * r8);
c = (d2 >>> 13); d2 &= 0x1fff;
d2 += h5 * (5 * r7);
d2 += h6 * (5 * r6);
d2 += h7 * (5 * r5);
d2 += h8 * (5 * r4);
d2 += h9 * (5 * r3);
c += (d2 >>> 13); d2 &= 0x1fff;
d3 = c;
d3 += h0 * r3;
d3 += h1 * r2;
d3 += h2 * r1;
d3 += h3 * r0;
d3 += h4 * (5 * r9);
c = (d3 >>> 13); d3 &= 0x1fff;
d3 += h5 * (5 * r8);
d3 += h6 * (5 * r7);
d3 += h7 * (5 * r6);
d3 += h8 * (5 * r5);
d3 += h9 * (5 * r4);
c += (d3 >>> 13); d3 &= 0x1fff;
d4 = c;
d4 += h0 * r4;
d4 += h1 * r3;
d4 += h2 * r2;
d4 += h3 * r1;
d4 += h4 * r0;
c = (d4 >>> 13); d4 &= 0x1fff;
d4 += h5 * (5 * r9);
d4 += h6 * (5 * r8);
d4 += h7 * (5 * r7);
d4 += h8 * (5 * r6);
d4 += h9 * (5 * r5);
c += (d4 >>> 13); d4 &= 0x1fff;
d5 = c;
d5 += h0 * r5;
d5 += h1 * r4;
d5 += h2 * r3;
d5 += h3 * r2;
d5 += h4 * r1;
c = (d5 >>> 13); d5 &= 0x1fff;
d5 += h5 * r0;
d5 += h6 * (5 * r9);
d5 += h7 * (5 * r8);
d5 += h8 * (5 * r7);
d5 += h9 * (5 * r6);
c += (d5 >>> 13); d5 &= 0x1fff;
d6 = c;
d6 += h0 * r6;
d6 += h1 * r5;
d6 += h2 * r4;
d6 += h3 * r3;
d6 += h4 * r2;
c = (d6 >>> 13); d6 &= 0x1fff;
d6 += h5 * r1;
d6 += h6 * r0;
d6 += h7 * (5 * r9);
d6 += h8 * (5 * r8);
d6 += h9 * (5 * r7);
c += (d6 >>> 13); d6 &= 0x1fff;
d7 = c;
d7 += h0 * r7;
d7 += h1 * r6;
d7 += h2 * r5;
d7 += h3 * r4;
d7 += h4 * r3;
c = (d7 >>> 13); d7 &= 0x1fff;
d7 += h5 * r2;
d7 += h6 * r1;
d7 += h7 * r0;
d7 += h8 * (5 * r9);
d7 += h9 * (5 * r8);
c += (d7 >>> 13); d7 &= 0x1fff;
d8 = c;
d8 += h0 * r8;
d8 += h1 * r7;
d8 += h2 * r6;
d8 += h3 * r5;
d8 += h4 * r4;
c = (d8 >>> 13); d8 &= 0x1fff;
d8 += h5 * r3;
d8 += h6 * r2;
d8 += h7 * r1;
d8 += h8 * r0;
d8 += h9 * (5 * r9);
c += (d8 >>> 13); d8 &= 0x1fff;
d9 = c;
d9 += h0 * r9;
d9 += h1 * r8;
d9 += h2 * r7;
d9 += h3 * r6;
d9 += h4 * r5;
c = (d9 >>> 13); d9 &= 0x1fff;
d9 += h5 * r4;
d9 += h6 * r3;
d9 += h7 * r2;
d9 += h8 * r1;
d9 += h9 * r0;
c += (d9 >>> 13); d9 &= 0x1fff;
c = (((c << 2) + c)) | 0;
c = (c + d0) | 0;
d0 = c & 0x1fff;
c = (c >>> 13);
d1 += c;
h0 = d0;
h1 = d1;
h2 = d2;
h3 = d3;
h4 = d4;
h5 = d5;
h6 = d6;
h7 = d7;
h8 = d8;
h9 = d9;
mpos += 16;
bytes -= 16;
}
this.h[0] = h0;
this.h[1] = h1;
this.h[2] = h2;
this.h[3] = h3;
this.h[4] = h4;
this.h[5] = h5;
this.h[6] = h6;
this.h[7] = h7;
this.h[8] = h8;
this.h[9] = h9;
};
poly1305.prototype.finish = function(mac, macpos) {
var g = new Uint16Array(10);
var c, mask, f, i;
if (this.leftover) {
i = this.leftover;
this.buffer[i++] = 1;
for (; i < 16; i++) this.buffer[i] = 0;
this.fin = 1;
this.blocks(this.buffer, 0, 16);
}
c = this.h[1] >>> 13;
this.h[1] &= 0x1fff;
for (i = 2; i < 10; i++) {
this.h[i] += c;
c = this.h[i] >>> 13;
this.h[i] &= 0x1fff;
}
this.h[0] += (c * 5);
c = this.h[0] >>> 13;
this.h[0] &= 0x1fff;
this.h[1] += c;
c = this.h[1] >>> 13;
this.h[1] &= 0x1fff;
this.h[2] += c;
g[0] = this.h[0] + 5;
c = g[0] >>> 13;
g[0] &= 0x1fff;
for (i = 1; i < 10; i++) {
g[i] = this.h[i] + c;
c = g[i] >>> 13;
g[i] &= 0x1fff;
}
g[9] -= (1 << 13);
mask = (c ^ 1) - 1;
for (i = 0; i < 10; i++) g[i] &= mask;
mask = ~mask;
for (i = 0; i < 10; i++) this.h[i] = (this.h[i] & mask) | g[i];
this.h[0] = ((this.h[0] ) | (this.h[1] << 13) ) & 0xffff;
this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10) ) & 0xffff;
this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7) ) & 0xffff;
this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4) ) & 0xffff;
this.h[4] = ((this.h[4] >>> 12) | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff;
this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11) ) & 0xffff;
this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8) ) & 0xffff;
this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5) ) & 0xffff;
f = this.h[0] + this.pad[0];
this.h[0] = f & 0xffff;
for (i = 1; i < 8; i++) {
f = (((this.h[i] + this.pad[i]) | 0) + (f >>> 16)) | 0;
this.h[i] = f & 0xffff;
}
mac[macpos+ 0] = (this.h[0] >>> 0) & 0xff;
mac[macpos+ 1] = (this.h[0] >>> 8) & 0xff;
mac[macpos+ 2] = (this.h[1] >>> 0) & 0xff;
mac[macpos+ 3] = (this.h[1] >>> 8) & 0xff;
mac[macpos+ 4] = (this.h[2] >>> 0) & 0xff;
mac[macpos+ 5] = (this.h[2] >>> 8) & 0xff;
mac[macpos+ 6] = (this.h[3] >>> 0) & 0xff;
mac[macpos+ 7] = (this.h[3] >>> 8) & 0xff;
mac[macpos+ 8] = (this.h[4] >>> 0) & 0xff;
mac[macpos+ 9] = (this.h[4] >>> 8) & 0xff;
mac[macpos+10] = (this.h[5] >>> 0) & 0xff;
mac[macpos+11] = (this.h[5] >>> 8) & 0xff;
mac[macpos+12] = (this.h[6] >>> 0) & 0xff;
mac[macpos+13] = (this.h[6] >>> 8) & 0xff;
mac[macpos+14] = (this.h[7] >>> 0) & 0xff;
mac[macpos+15] = (this.h[7] >>> 8) & 0xff;
};
poly1305.prototype.update = function(m, mpos, bytes) {
var i, want;
if (this.leftover) {
want = (16 - this.leftover);
if (want > bytes)
want = bytes;
for (i = 0; i < want; i++)
this.buffer[this.leftover + i] = m[mpos+i];
bytes -= want;
mpos += want;
this.leftover += want;
if (this.leftover < 16)
return;
this.blocks(this.buffer, 0, 16);
this.leftover = 0;
}
if (bytes >= 16) {
want = bytes - (bytes % 16);
this.blocks(m, mpos, want);
mpos += want;
bytes -= want;
}
if (bytes) {
for (i = 0; i < bytes; i++)
this.buffer[this.leftover + i] = m[mpos+i];
this.leftover += bytes;
}
};
module.exports = poly1305

30
memory.js Normal file
View File

@ -0,0 +1,30 @@
/* eslint-disable camelcase */
function sodium_malloc (n) {
return new Uint8Array(n)
}
function sodium_free (n) {
sodium_memzero(n)
loadSink().port1.postMessage(n.buffer, [n.buffer])
}
function sodium_memzero (arr) {
arr.fill(0)
}
var sink
function loadSink () {
if (sink) return sink
var MessageChannel = globalThis.MessageChannel
if (MessageChannel == null) ({ MessageChannel } = require('worker' + '_threads'))
sink = new MessageChannel()
return sink
}
module.exports = {
sodium_malloc,
sodium_free,
sodium_memzero
}

View File

@ -1,32 +1,52 @@
{ {
"name": "sodium-javascript", "name": "sodium-javascript",
"version": "0.5.2", "version": "0.8.0",
"description": "WIP - a pure javascript version of sodium-native", "description": "WIP - a pure javascript version of sodium-native",
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"blake2b": "^2.1.1", "blake2b": "^2.1.1",
"nanoassert": "^1.0.0", "chacha20-universal": "^1.0.4",
"nanoassert": "^2.0.0",
"sha256-universal": "^1.1.0",
"sha512-universal": "^1.1.0",
"siphash24": "^1.0.1", "siphash24": "^1.0.1",
"xsalsa20": "^1.0.0" "xsalsa20": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"browser-run": "^4.0.2", "brittle": "^3.2.1",
"browserify": "^14.1.0", "browserify": "^16.5.1",
"sodium-test": "^0.7.0" "standard": "^15.0.1"
},
"standard": {
"ignore": [
"/internal/**/*.js",
"/test/fixtures/*.js"
],
"rules": {
"camelcase": "off"
}
},
"browser": {
"crypto": false,
"worker_threads": false
}, },
"scripts": { "scripts": {
"browser": "browserify test.js | browser-run", "pretest": "standard",
"browser-manual": "browserify test.js | browser-run -p 1234", "test": "brittle test/*.js",
"test": "node test.js" "test-browser": "browserify test.js | tape-run"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/mafintosh/sodium-javascript.git" "url": "git+https://github.com/sodium-friends/sodium-javascript.git"
}, },
"author": "Mathias Buus (@mafintosh)", "contributors": [
"Christophe Diederichs <chm-diederichs@hyperdivision.dk>",
"Emil Bay <github@tixz.dk> (http://bayes.dk)",
"Mathias Buus <mathiasbuus@gmail.com> (https://mafinto.sh)"
],
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/mafintosh/sodium-javascript/issues" "url": "https://github.com/sodium-friends/sodium-javascript/issues"
}, },
"homepage": "https://github.com/mafintosh/sodium-javascript" "homepage": "https://github.com/sodium-friends/sodium-javascript#readme"
} }

View File

@ -1,40 +1,40 @@
var assert = require('nanoassert') var assert = require('nanoassert')
var randombytes = (function () { var randombytes = (function () {
var QUOTA = 65536 // limit for QuotaExceededException var QUOTA = 65536 // limit for QuotaExceededException
var crypto = typeof global !== 'undefined' ? crypto = (global.crypto || global.msCrypto) : null var crypto = globalThis.crypto || globalThis.msCrypto
function browserBytes (out, n) { function browserBytes (out, n) {
for (var i = 0; i < n; i += QUOTA) { for (let i = 0; i < n; i += QUOTA) {
crypto.getRandomValues(out.subarray(i, i + Math.min(n - i, QUOTA))) crypto.getRandomValues(new Uint8Array(out.buffer, i + out.byteOffset, Math.min(n - i, QUOTA)))
} }
} }
function nodeBytes (out, n) { function nodeBytes (out, n) {
out.set(crypto.randomBytes(n)) new Uint8Array(out.buffer, out.byteOffset, n).set(crypto.randomBytes(n))
} }
function noImpl () { function noImpl () {
throw new Error('No secure random number generator available') throw new Error('No secure random number generator available')
} }
if (crypto && crypto.getRandomValues) { if (crypto && crypto.getRandomValues) return browserBytes
return browserBytes
} else if (typeof require !== 'undefined') { if (require != null) {
// Node.js. // Node.js. Bust Browserify
crypto = require('cry' + 'pto'); crypto = require('cry' + 'pto')
if (crypto && crypto.randomBytes) { if (crypto && crypto.randomBytes) return nodeBytes
return nodeBytes
}
} }
return noImpl return noImpl
})() })()
// Make non enumerable as this is an internal function
Object.defineProperty(module.exports, 'randombytes', { Object.defineProperty(module.exports, 'randombytes', {
value: randombytes value: randombytes
}) })
module.exports.randombytes_buf = function (out) { module.exports.randombytes_buf = function (out) {
assert(out, 'out must be given') assert(out, 'out must be given')
randombytes(out, out.length) randombytes(out, out.byteLength)
} }

View File

@ -1,3 +0,0 @@
require('sodium-test')(require('.'))
if (typeof window !== 'undefined') window.close()

View File

@ -0,0 +1,285 @@
/* eslint-disable camelcase */
const test = require('brittle')
const b4a = require('b4a')
const sodium = require('..')
test('constants', function (t) {
t.is(typeof sodium.crypto_aead_chacha20poly1305_ietf_ABYTES, 'number')
t.is(typeof sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES, 'number')
t.is(typeof sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES, 'number')
t.is(typeof sodium.crypto_aead_chacha20poly1305_ietf_NSECBYTES, 'number')
t.is(sodium.crypto_aead_chacha20poly1305_ietf_NSECBYTES, 0)
t.is(typeof sodium.crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'number')
t.is(sodium.crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, Number.MAX_SAFE_INTEGER) // to make sure, see note in binding.cc
})
test('ported from libsodium', function (t) {
const mlen = 114
const adlen = 12
const clen = mlen + sodium.crypto_aead_chacha20poly1305_ietf_ABYTES
const firstkey = b4a.from([
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
])
const message = b4a.from('Ladies and Gentlemen of the class of \'99: If I could offer you only one tip for the future, sunscreen would be it.')
const m = sodium.sodium_malloc(mlen)
const nonce = b4a.from([
0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43,
0x44, 0x45, 0x46, 0x47
])
t.is(nonce.length, sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES)
const ad = b4a.from([
0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7
])
t.is(ad.length, adlen)
const c = sodium.sodium_malloc(clen)
const detachedc = sodium.sodium_malloc(mlen)
const mac = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_ABYTES)
const m2 = sodium.sodium_malloc(mlen)
let foundclen = 0
let foundmaclen = 0
let m2len = 0
let i = 0
t.is(message.length, mlen)
b4a.copy(message, m)
foundclen = sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c, m, ad, null, nonce, firstkey)
t.is(foundclen, mlen + sodium.crypto_aead_chacha20poly1305_ietf_ABYTES)
const exp1 = new Uint8Array([
0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc,
0x53, 0xef, 0x7e, 0xc2, 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, 0x3d, 0xbe, 0xa4, 0x5e,
0x8c, 0xa9, 0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6,
0x7e, 0xcd, 0x3b, 0x36, 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, 0xfa, 0xb3, 0x24, 0xe4,
0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65,
0x86, 0xce, 0xc6, 0x4b, 0x61, 0x16, 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09,
0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
])
t.alike(c, exp1)
foundmaclen = sodium.crypto_aead_chacha20poly1305_ietf_encrypt_detached(detachedc, mac, m, ad, null, nonce, firstkey)
t.is(foundmaclen, sodium.crypto_aead_chacha20poly1305_ietf_ABYTES)
const exp0 = c.slice(0, mlen)
t.alike(detachedc, exp0)
m2len = sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c, ad, nonce, firstkey)
t.is(m2len, mlen)
t.alike(m, m2)
m2.fill(0)
sodium.crypto_aead_chacha20poly1305_ietf_decrypt_detached(m2, null, c.slice(0, mlen), mac, ad, nonce, firstkey)
t.alike(m, m2)
for (i = 0; i < clen; i++) {
c[i] ^= (i + 1)
t.exception.all(_ => sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c, ad, nonce, firstkey))
if (b4a.equals(m, m2)) t.fail()
c[i] ^= (i + 1)
}
foundclen = sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c, m, null, null, nonce, firstkey)
t.is(foundclen, clen)
const exp2 = new Uint8Array([
0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc,
0x53, 0xef, 0x7e, 0xc2, 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, 0x3d, 0xbe, 0xa4, 0x5e,
0x8c, 0xa9, 0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6,
0x7e, 0xcd, 0x3b, 0x36, 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, 0xfa, 0xb3, 0x24, 0xe4,
0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65,
0x86, 0xce, 0xc6, 0x4b, 0x61, 0x16, 0x6a, 0x23, 0xa4, 0x68, 0x1f, 0xd5,
0x94, 0x56, 0xae, 0xa1, 0xd2, 0x9f, 0x82, 0x47, 0x72, 0x16
])
t.alike(c, exp2)
m2len = sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c, null, nonce, firstkey)
t.is(m2len, mlen)
t.alike(m2, m)
b4a.copy(m, c)
foundclen = sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c, c.slice(0, mlen), null, null, nonce, firstkey)
t.is(foundclen, clen, 'clen is properly set (adlen=0)')
const exp3 = new Uint8Array([
0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc,
0x53, 0xef, 0x7e, 0xc2, 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, 0x3d, 0xbe, 0xa4, 0x5e,
0x8c, 0xa9, 0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6,
0x7e, 0xcd, 0x3b, 0x36, 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, 0xfa, 0xb3, 0x24, 0xe4,
0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65,
0x86, 0xce, 0xc6, 0x4b, 0x61, 0x16, 0x6a, 0x23, 0xa4, 0x68, 0x1f, 0xd5,
0x94, 0x56, 0xae, 0xa1, 0xd2, 0x9f, 0x82, 0x47, 0x72, 0x16
])
t.alike(c, exp3)
const decrypted = sodium.sodium_malloc(c.byteLength - sodium.crypto_aead_chacha20poly1305_ietf_ABYTES)
m2len = sodium.crypto_aead_chacha20poly1305_ietf_decrypt(decrypted, null, c, null, nonce, firstkey)
t.is(m2len, mlen, 'm2len is properly set (adlen=0)')
t.alike(m, decrypted, 'm == c (adlen=0)')
})
test.skip('keygen', function (t) {
const key1 = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES)
const key2 = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES)
sodium.crypto_aead_chacha20poly1305_ietf_keygen(key1)
sodium.crypto_aead_chacha20poly1305_ietf_keygen(key2)
t.unlike(key1, key2)
})
test.skip('different keys', function (t) {
const m = b4a.from('Ladies and Gentlemen of the class of \'99: If I could offer you only one tip for the future, sunscreen would be it.')
const key1 = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES)
const key2 = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES)
sodium.crypto_aead_chacha20poly1305_ietf_keygen(key1)
sodium.crypto_aead_chacha20poly1305_ietf_keygen(key2)
const nonce = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES)
sodium.randombytes_buf(nonce)
const clen = m.byteLength + sodium.crypto_aead_chacha20poly1305_ietf_ABYTES
const c1 = sodium.sodium_malloc(clen)
const c2 = sodium.sodium_malloc(clen)
const m1 = sodium.sodium_malloc(m.byteLength)
const m2 = sodium.sodium_malloc(m.byteLength)
t.is(sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c1, m, null, null, nonce, key1), clen)
t.absent(c1.equals(c2))
t.absent(c1.equals(m))
t.is(sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c2, m, null, null, nonce, key2), clen)
t.absent(c1.equals(c2))
t.absent(c2.equals(m))
t.exception.all(_ => sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m1, null, c1, null, nonce, key2))
t.exception.all(_ => sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c2, null, nonce, key1))
t.is(sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m1, null, c1, null, nonce, key1), m.byteLength)
t.ok(m.equals(m1))
t.is(sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c2, null, nonce, key2), m.byteLength)
t.ok(m.equals(m2))
})
test.skip('different nonce', function (t) {
const m = b4a.from('Ladies and Gentlemen of the class of \'99: If I could offer you only one tip for the future, sunscreen would be it.')
const key = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES)
sodium.crypto_aead_chacha20poly1305_ietf_keygen(key)
const n1 = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES)
const n2 = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES)
sodium.randombytes_buf(n1)
sodium.randombytes_buf(n2)
const clen = m.byteLength + sodium.crypto_aead_chacha20poly1305_ietf_ABYTES
const c1 = sodium.sodium_malloc(clen)
const c2 = sodium.sodium_malloc(clen)
const m1 = sodium.sodium_malloc(m.byteLength)
const m2 = sodium.sodium_malloc(m.byteLength)
t.is(sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c1, m, null, null, n1, key), clen)
t.absent(c1.equals(c2))
t.absent(c1.equals(m))
t.is(sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c2, m, null, null, n2, key), clen)
t.absent(c1.equals(c2))
t.absent(c2.equals(m))
t.exception.all(_ => sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m1, null, c1, null, n2, key))
t.exception.all(_ => sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c2, null, n1, key))
t.is(sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m1, null, c1, null, n1, key), m.byteLength)
t.ok(m.equals(m1))
t.is(sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c2, null, n2, key), m.byteLength)
t.ok(m.equals(m2))
})
test.skip('detached -> non-detached', function (t) {
const m = b4a.from('Ladies and Gentlemen of the class of \'99: If I could offer you only one tip for the future, sunscreen would be it.')
m.secure = true
const key = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES)
sodium.crypto_aead_chacha20poly1305_ietf_keygen(key)
const nonce = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES)
sodium.randombytes_buf(nonce)
const mac = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_ABYTES)
const clen = m.byteLength
const c = sodium.sodium_malloc(clen)
t.is(sodium.crypto_aead_chacha20poly1305_ietf_encrypt_detached(c, mac, m, null, null, nonce, key), mac.byteLength)
const m1 = sodium.sodium_malloc(m.byteLength)
t.is(sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m1, null, b4a.concat([c, mac]), null, nonce, key), m.byteLength)
t.alike(m, m1)
})
test.skip('non-detached -> detached', function (t) {
const m = b4a.from('Ladies and Gentlemen of the class of \'99: If I could offer you only one tip for the future, sunscreen would be it.')
m.secure = true
const key = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES)
sodium.crypto_aead_chacha20poly1305_ietf_keygen(key)
const nonce = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES)
sodium.randombytes_buf(nonce)
const clen = m.byteLength + sodium.crypto_aead_chacha20poly1305_ietf_ABYTES
const c = sodium.sodium_malloc(clen)
t.is(sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c, m, null, null, nonce, key), c.byteLength)
const m1 = sodium.sodium_malloc(m.byteLength)
const csub = c.subarray(0, clen - sodium.crypto_aead_chacha20poly1305_ietf_ABYTES)
const macsub = c.subarray(csub.byteLength)
sodium.crypto_aead_chacha20poly1305_ietf_decrypt_detached(m1, null, csub, macsub, null, nonce, key)
t.alike(m, m1)
})
/**
* Need to test in-place encryption
* detach can talk to non detach
* encrypt - decrypt
* different nonce
* different key
* return values
*/

219
test/crypto_auth.js Normal file
View File

@ -0,0 +1,219 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('crypto_auth', function (t) {
const key = Buffer.alloc(sodium.crypto_auth_KEYBYTES)
sodium.randombytes_buf(key)
const mac = Buffer.alloc(sodium.crypto_auth_BYTES)
const value = Buffer.from('Hej, Verden')
sodium.crypto_auth(mac, value, key)
t.not(mac, Buffer.alloc(mac.length), 'mac not blank')
t.absent(sodium.crypto_auth_verify(Buffer.alloc(mac.length), value, key), 'does not verify')
t.ok(sodium.crypto_auth_verify(mac, value, key), 'verifies')
})
test('crypto_auth #1', t => {
// "Test Case 2" from RFC 4231
const key = stringToArray('Jefe', 32)
const c = stringToArray('what do ya want for nothing?')
const c1 = stringToArray('wwhat do ya want for nothing')
const a = new Uint8Array(sodium.crypto_auth_BYTES)
const exp = [
new Uint8Array([
0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2,
0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3,
0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6,
0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54
]),
new Uint8Array([
0x7b, 0x9d, 0x83, 0x38, 0xeb, 0x1e, 0x3d, 0xdd,
0xba, 0x8a, 0x9a, 0x35, 0x08, 0xd0, 0x34, 0xa1,
0xec, 0xbe, 0x75, 0x11, 0x37, 0xfa, 0x1b, 0xcb,
0xa0, 0xf9, 0x2a, 0x3e, 0x6d, 0xfc, 0x79, 0x80
]),
new Uint8Array([
0xb9, 0xd1, 0x4c, 0x51, 0xa6, 0xd4, 0xdd, 0x41,
0x60, 0x4e, 0xb0, 0x6c, 0x9c, 0x24, 0x0f, 0x1f,
0x64, 0xf1, 0x43, 0xb5, 0xcf, 0xde, 0xa3, 0x71,
0x29, 0xb2, 0x8b, 0xb7, 0x5d, 0x13, 0x71, 0xd3
])
]
sodium.crypto_auth(a, c, key)
t.alike(a, exp[0])
t.ok(sodium.crypto_auth_verify(exp[0], c, key))
a.fill(0)
sodium.crypto_auth(a, c1, key)
t.alike(a, exp[1])
t.ok(sodium.crypto_auth_verify(exp[1], c1, key))
// Empty message tests
a.fill(0)
sodium.crypto_auth(a, new Uint8Array(0), key)
t.alike(a, exp[2])
t.ok(sodium.crypto_auth_verify(exp[2], new Uint8Array(0), key))
t.end()
})
test('crypto_auth', function (t) {
const key = stringToArray('Jefe', 32)
const c = stringToArray('what do ya want for nothing?')
const a = new Uint8Array(sodium.crypto_auth_BYTES)
const expected = new Uint8Array([
0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, 0xe3, 0x95, 0xfb, 0xe7,
0x3b, 0x56, 0xe0, 0xa3, 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6,
0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54
])
sodium.crypto_auth(a, c, key)
t.alike(a, expected)
t.ok(sodium.crypto_auth_verify(a, c, key))
c[Math.floor(Math.random() * c.length)] += 1
t.absent(sodium.crypto_auth_verify(a, c, key))
t.end()
})
test('wrong keylength', t => {
const a = new Uint8Array(32)
const c = new Uint8Array(0)
for (let i = 0; i < 128; i++) {
if (i === 32) continue
const k = new Uint8Array(i)
try {
sodium.crypto_auth(a, c, k)
t.fail('failed on test #' + i)
} catch (e) {
try {
sodium.crypto_auth_verify(a, c, k)
t.fail('failed on test #' + i)
} catch (e) {
try {
sodium.crypto_auth_verify(k, c, a)
t.fail('failed on test #' + i)
} catch {}
}
}
}
t.pass('should not accept bad input length')
t.end()
})
test('crypto_auth constants', t => {
t.is(sodium.crypto_auth_BYTES, 32)
t.is(sodium.crypto_auth_KEYBYTES, 32)
t.end()
})
test('rfc4231 test case #6', t => {
const keys = [
new Uint8Array([
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]),
new Uint8Array([
0x4a, 0x65, 0x66, 0x65, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]),
new Uint8Array([
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]),
new Uint8Array([
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
])
]
const data = [
new Uint8Array([
0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65
]),
new Uint8Array([
0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20,
0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20,
0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68,
0x69, 0x6e, 0x67, 0x3f
]),
new Uint8Array([
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd
]),
new Uint8Array([
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd
])
]
const exp = [
new Uint8Array([
0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d,
0x4f, 0xf0, 0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0,
0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78,
0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde
]),
new Uint8Array([
0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2,
0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3,
0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6,
0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54
]),
new Uint8Array([
0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84,
0xef, 0xb0, 0xf0, 0x75, 0x6c, 0x89, 0x0b, 0xe9,
0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36,
0x55, 0xf8, 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39
]),
new Uint8Array([
0xb0, 0xba, 0x46, 0x56, 0x37, 0x45, 0x8c, 0x69,
0x90, 0xe5, 0xa8, 0xc5, 0xf6, 0x1d, 0x4a, 0xf7,
0xe5, 0x76, 0xd9, 0x7f, 0xf9, 0x4b, 0x87, 0x2d,
0xe7, 0x6f, 0x80, 0x50, 0x36, 0x1e, 0xe3, 0xdb
])
]
const a = new Uint8Array(sodium.crypto_auth_BYTES)
for (let i = 0; i < keys.length; i++) {
sodium.crypto_auth(a, data[i], keys[i])
t.alike(a, exp[i])
t.ok(sodium.crypto_auth_verify(exp[i], data[i], keys[i]))
}
t.end()
})
function stringToArray (s, size = s.length) {
const array = new Uint8Array(size)
array.set(s.split('').map((c) => c.charCodeAt(0)))
return array
}

305
test/crypto_box.js Normal file
View File

@ -0,0 +1,305 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('crypto_box_seed_keypair', function (t) {
const pk = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES)
const sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES)
const seed = Buffer.alloc(sodium.crypto_box_SEEDBYTES, 'lo')
t.exception.all(function () {
sodium.crypto_box_seed_keypair()
}, 'should validate input')
t.exception.all(function () {
sodium.crypto_box_seed_keypair(Buffer.alloc(0), Buffer.alloc(0), Buffer.alloc(0))
}, 'should validate input length')
sodium.crypto_box_seed_keypair(pk, sk, seed)
const eSk = '8661a95d21b134adc02881022ad86d37f32a230d537b525b997bce27aa745afc'
const ePk = '425c5ba523e70411c77300bb48dd846562e6c1fcf0142d81d2567d650ce76c3b'
t.alike(pk.toString('hex'), ePk, 'seeded public key')
t.alike(sk.toString('hex'), eSk, 'seeded secret key')
})
test('crypto_box_keypair', function (t) {
const pk = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES)
const sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES)
sodium.crypto_box_keypair(pk, sk)
t.not(pk, Buffer.alloc(pk.length), 'made public key')
t.not(sk, Buffer.alloc(sk.length), 'made secret key')
t.exception.all(function () {
sodium.crypto_box_keypair()
}, 'should validate input')
t.exception.all(function () {
sodium.crypto_box_keypair(Buffer.alloc(0), Buffer.alloc(0))
}, 'should validate input length')
})
test('crypto_box_detached', function (t) {
const pk = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES)
const sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES)
const nonce = Buffer.alloc(sodium.crypto_box_NONCEBYTES)
sodium.crypto_box_keypair(pk, sk)
const message = Buffer.from('Hello, World!')
const mac = Buffer.alloc(sodium.crypto_box_MACBYTES)
const cipher = Buffer.alloc(message.length)
sodium.crypto_box_detached(cipher, mac, message, nonce, pk, sk)
t.not(cipher, Buffer.alloc(cipher.length), 'not blank')
const plain = Buffer.alloc(cipher.length)
t.absent(sodium.crypto_box_open_detached(plain, cipher, Buffer.alloc(mac.length), nonce, pk, sk), 'does not decrypt')
t.ok(sodium.crypto_box_open_detached(plain, cipher, mac, nonce, pk, sk), 'decrypts')
t.alike(plain, message, 'same message')
})
test('crypto_box_easy', function (t) {
const pk = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES)
const sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES)
const nonce = Buffer.alloc(sodium.crypto_box_NONCEBYTES)
sodium.crypto_box_keypair(pk, sk)
const message = Buffer.from('Hello, World!')
const cipher = Buffer.alloc(message.length + sodium.crypto_box_MACBYTES)
sodium.crypto_box_easy(cipher, message, nonce, pk, sk)
t.not(cipher, Buffer.alloc(cipher.length), 'not blank')
const plain = Buffer.alloc(cipher.length - sodium.crypto_box_MACBYTES)
t.absent(sodium.crypto_box_open_easy(plain, Buffer.alloc(cipher.length), nonce, pk, sk), 'does not decrypt')
t.ok(sodium.crypto_box_open_easy(plain, cipher, nonce, pk, sk), 'decrypts')
t.alike(plain, message, 'same message')
})
test('crypto_box_seal', function (t) {
const pk = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES)
const sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES)
sodium.crypto_box_keypair(pk, sk)
const pk2 = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES)
const sk2 = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES)
sodium.crypto_box_keypair(pk2, sk2)
const message = Buffer.from('Hello, sealed World!')
const cipher = Buffer.alloc(message.length + sodium.crypto_box_SEALBYTES)
sodium.crypto_box_seal(cipher, message, pk)
t.not(cipher, message, 'did not encrypt!')
t.not(cipher, Buffer.alloc(cipher.length), 'not blank')
const plain = Buffer.alloc(cipher.length - sodium.crypto_box_SEALBYTES)
t.absent(sodium.crypto_box_seal_open(plain, cipher, pk2, sk2), 'does not decrypt')
t.ok(sodium.crypto_box_seal_open(plain, cipher, pk, sk), 'decrypts')
t.alike(plain, message, 'same message')
})
test('crypto_box_seal/crypto_box_seal_open self-decrypt', function (t) {
const pubKey = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES)
const secret = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES)
sodium.crypto_box_keypair(pubKey, secret)
const msg = Buffer.from('hello world')
const cipher = Buffer.alloc(sodium.crypto_box_SEALBYTES + msg.length)
sodium.crypto_box_seal(cipher, msg, pubKey)
const out = Buffer.alloc(cipher.length - sodium.crypto_box_SEALBYTES)
sodium.crypto_box_seal_open(out, cipher, pubKey, secret)
t.alike(out.toString(), msg.toString())
t.end()
})
test('crypto_box_seal_open cross-decrypt', function (t) {
const pubKey = Buffer.from(
'e0bb844ae3f48bb04323c8dfe7c34cf86608db2e2112f927953060c80506287f', 'hex')
const secret = Buffer.from(
'036a9de1ecc9d152cf39fed1b3e15bf761ae39a299031adc011cc9809041abfa', 'hex')
const cipher = Buffer.from(
'249912e916ad8bcf96a3f9b750da2703' +
'2eccdf83b5cff0d6a59a8bbe0bcd5823' +
'5de9fbca55bd5416c754e5e0e0fe2f0c' +
'4e50df0cb302f1c4378f80', 'hex')
const out = Buffer.alloc(cipher.length - sodium.crypto_box_SEALBYTES)
sodium.crypto_box_seal_open(out, cipher, pubKey, secret)
t.alike(out.toString(), 'hello world')
t.end()
})
test('crypto_box_seed_keypair', function (t) {
const seed = Buffer.from([
0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5,
0x7d, 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2,
0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb,
0xc0, 0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5,
0x1d, 0xb9, 0x2c, 0x2a
])
const expPk = Buffer.from([
0xed, 0x77, 0x49, 0xb4, 0xd9, 0x89, 0xf6, 0x95,
0x7f, 0x3b, 0xfd, 0xe6, 0xc5, 0x67, 0x67, 0xe9,
0x88, 0xe2, 0x1c, 0x9f, 0x87, 0x84, 0xd9, 0x1d,
0x61, 0x00, 0x11, 0xcd, 0x55, 0x3f, 0x9b, 0x06
])
const expSk = Buffer.from([
0xac, 0xcd, 0x44, 0xeb, 0x8e, 0x93, 0x31, 0x9c,
0x05, 0x70, 0xbc, 0x11, 0x00, 0x5c, 0x0e, 0x01,
0x89, 0xd3, 0x4f, 0xf0, 0x2f, 0x6c, 0x17, 0x77,
0x34, 0x11, 0xad, 0x19, 0x12, 0x93, 0xc9, 0x8f
])
const sk = Buffer.alloc(32)
const pk = Buffer.alloc(32)
sodium.crypto_box_seed_keypair(pk, sk, seed)
t.alike(pk, expPk)
t.alike(sk, expSk)
t.end()
})
test('crypto_box_easy', (t) => {
const alicesk = new Uint8Array([
0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72,
0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a,
0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a
])
const bobpk = new Uint8Array([
0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61, 0xc2,
0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d,
0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f
])
const nonce = new Uint8Array([
0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73, 0xcd, 0x62, 0xbd, 0xa8,
0x75, 0xfc, 0x73, 0xd6, 0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37
])
const m = new Uint8Array([
0xbe, 0x07, 0x5f, 0xc5, 0x3c, 0x81, 0xf2, 0xd5, 0xcf, 0x14, 0x13, 0x16,
0xeb, 0xeb, 0x0c, 0x7b, 0x52, 0x28, 0xc5, 0x2a, 0x4c, 0x62, 0xcb, 0xd4,
0x4b, 0x66, 0x84, 0x9b, 0x64, 0x24, 0x4f, 0xfc, 0xe5, 0xec, 0xba, 0xaf,
0x33, 0xbd, 0x75, 0x1a, 0x1a, 0xc7, 0x28, 0xd4, 0x5e, 0x6c, 0x61, 0x29,
0x6c, 0xdc, 0x3c, 0x01, 0x23, 0x35, 0x61, 0xf4, 0x1d, 0xb6, 0x6c, 0xce,
0x31, 0x4a, 0xdb, 0x31, 0x0e, 0x3b, 0xe8, 0x25, 0x0c, 0x46, 0xf0, 0x6d,
0xce, 0xea, 0x3a, 0x7f, 0xa1, 0x34, 0x80, 0x57, 0xe2, 0xf6, 0x55, 0x6a,
0xd6, 0xb1, 0x31, 0x8a, 0x02, 0x4a, 0x83, 0x8f, 0x21, 0xaf, 0x1f, 0xde,
0x04, 0x89, 0x77, 0xeb, 0x48, 0xf5, 0x9f, 0xfd, 0x49, 0x24, 0xca, 0x1c,
0x60, 0x90, 0x2e, 0x52, 0xf0, 0xa0, 0x89, 0xbc, 0x76, 0x89, 0x70, 0x40,
0xe0, 0x82, 0xf9, 0x37, 0x76, 0x38, 0x48, 0x64, 0x5e, 0x07, 0x05
])
const c = new Uint8Array(147)
sodium.crypto_box_easy(c, m, nonce, bobpk, alicesk)
const expected1 = new Uint8Array([
0xf3, 0xff, 0xc7, 0x70, 0x3f, 0x94, 0x00, 0xe5, 0x2a, 0x7d, 0xfb, 0x4b,
0x3d, 0x33, 0x05, 0xd9, 0x8e, 0x99, 0x3b, 0x9f, 0x48, 0x68, 0x12, 0x73,
0xc2, 0x96, 0x50, 0xba, 0x32, 0xfc, 0x76, 0xce, 0x48, 0x33, 0x2e, 0xa7,
0x16, 0x4d, 0x96, 0xa4, 0x47, 0x6f, 0xb8, 0xc5, 0x31, 0xa1, 0x18, 0x6a,
0xc0, 0xdf, 0xc1, 0x7c, 0x98, 0xdc, 0xe8, 0x7b, 0x4d, 0xa7, 0xf0, 0x11,
0xec, 0x48, 0xc9, 0x72, 0x71, 0xd2, 0xc2, 0x0f, 0x9b, 0x92, 0x8f, 0xe2,
0x27, 0x0d, 0x6f, 0xb8, 0x63, 0xd5, 0x17, 0x38, 0xb4, 0x8e, 0xee, 0xe3,
0x14, 0xa7, 0xcc, 0x8a, 0xb9, 0x32, 0x16, 0x45, 0x48, 0xe5, 0x26, 0xae,
0x90, 0x22, 0x43, 0x68, 0x51, 0x7a, 0xcf, 0xea, 0xbd, 0x6b, 0xb3, 0x73,
0x2b, 0xc0, 0xe9, 0xda, 0x99, 0x83, 0x2b, 0x61, 0xca, 0x01, 0xb6, 0xde,
0x56, 0x24, 0x4a, 0x9e, 0x88, 0xd5, 0xf9, 0xb3, 0x79, 0x73, 0xf6, 0x22,
0xa4, 0x3d, 0x14, 0xa6, 0x59, 0x9b, 0x1f, 0x65, 0x4c, 0xb4, 0x5a, 0x74,
0xe3, 0x55, 0xa5
])
t.alike(c, expected1, 'encrypts correctly')
// This test isn't found upstream, but it seems necessary to have at least
// one crypto_box_open_easy() working since the next test diverges.
const o = new Uint8Array(131)
t.ok(sodium.crypto_box_open_easy(o, expected1, nonce, bobpk, alicesk))
t.alike(o, m, 'decrypts correctly')
const guardPage = new Uint8Array(0)
t.execution(() => sodium.crypto_box_easy(
c.subarray(0, sodium.crypto_box_MACBYTES),
guardPage,
nonce,
bobpk,
alicesk
))
const expected2 = new Uint8Array([
0x25, 0x39, 0x12, 0x1d, 0x8e, 0x23, 0x4e, 0x65, 0x2d, 0x65, 0x1f, 0xa4,
0xc8, 0xcf, 0xf8, 0x80, 0x8e
])
t.alike(c.subarray(0, expected2.length), expected2)
t.ok(sodium.crypto_box_open_easy(
new Uint8Array(0),
c.subarray(0, sodium.crypto_box_MACBYTES),
nonce,
bobpk,
alicesk
))
c[Math.floor(Math.random() * sodium.crypto_box_MACBYTES)] += 1
t.absent(sodium.crypto_box_open_easy(new Uint8Array(0), c.subarray(0, sodium.crypto_box_MACBYTES), nonce, bobpk, alicesk))
t.end()
})
/* eslint-disable camelcase */
test('crypto_box_easy2', t => {
const alicepk = new Uint8Array(sodium.crypto_box_PUBLICKEYBYTES)
const alicesk = new Uint8Array(sodium.crypto_box_SECRETKEYBYTES)
const bobpk = new Uint8Array(sodium.crypto_box_PUBLICKEYBYTES)
const bobsk = new Uint8Array(sodium.crypto_box_SECRETKEYBYTES)
const nonce = new Uint8Array(sodium.crypto_box_NONCEBYTES)
const m_size = 7 + Math.floor(Math.random() * 1000)
const m = new Uint8Array(m_size)
const m2 = new Uint8Array(m_size)
const c = new Uint8Array(sodium.crypto_box_MACBYTES + m_size)
sodium.crypto_box_keypair(alicepk, alicesk)
sodium.crypto_box_keypair(bobpk, bobsk)
const mlen = Math.floor(Math.random() * m_size) + 1
sodium.randombytes_buf(m.subarray(0, mlen))
sodium.randombytes_buf(nonce.subarray(0, sodium.crypto_box_NONCEBYTES))
t.execution(() => sodium.crypto_box_easy(c.subarray(0, mlen + sodium.crypto_box_MACBYTES), m.subarray(0, mlen), nonce, bobpk, alicesk))
t.ok(sodium.crypto_box_open_easy(m2.subarray(0, mlen), c.subarray(0, mlen + sodium.crypto_box_MACBYTES), nonce, alicepk, bobsk))
t.alike(m.subarray(0, mlen), m2.subarray(0, mlen))
for (let i = sodium.crypto_box_MACBYTES; i < mlen + sodium.crypto_box_MACBYTES - 1; i++) {
if (sodium.crypto_box_open_easy(m2.subarray(0, i - sodium.crypto_box_MACBYTES), c.subarray(0, i), nonce, alicepk, bobsk)) {
t.fail('short open() should fail.')
}
}
c.set(m.subarray(0, mlen))
t.execution(() => sodium.crypto_box_easy(c.subarray(0, mlen + sodium.crypto_box_MACBYTES), c.subarray(0, mlen), nonce, bobpk, alicesk))
t.unlike(m.subarray(0, mlen), c.subarray(0, mlen))
t.unlike(m.subarray(0, mlen), c.subarray(sodium.crypto_box_MACBYTES, sodium.crypto_box_MACBYTES + mlen))
t.ok(sodium.crypto_box_open_easy(c.subarray(0, mlen), c.subarray(0, mlen + sodium.crypto_box_MACBYTES), nonce, alicepk, bobsk))
t.end()
})

133
test/crypto_generichash.js Normal file
View File

@ -0,0 +1,133 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('crypto_generichash', function (t) {
const buf = Buffer.from('Hello, World!')
const out = Buffer.alloc(sodium.crypto_generichash_BYTES)
sodium.crypto_generichash(out, buf)
t.alike(out.toString('hex'), '511bc81dde11180838c562c82bb35f3223f46061ebde4a955c27b3f489cf1e03', 'hashed buffer')
const min = Buffer.alloc(sodium.crypto_generichash_BYTES_MIN)
sodium.crypto_generichash(min, buf)
t.alike(min.toString('hex'), '3895c59e4aeb0903396b5be3fbec69fe', 'hashed buffer min')
const max = Buffer.alloc(sodium.crypto_generichash_BYTES_MAX)
sodium.crypto_generichash(max, buf)
const res = '7dfdb888af71eae0e6a6b751e8e3413d767ef4fa52a7993daa9ef097f7aa3d949199c113caa37c94f80cf3b22f7d9d6e4f5def4ff927830cffe4857c34be3d89'
t.alike(max.toString('hex'), res, 'hashed buffer max')
})
test('crypto_generichash with key', function (t) {
const buf = Buffer.from('Hello, World!')
const key = Buffer.alloc(sodium.crypto_generichash_KEYBYTES)
key.fill('lo')
const out = Buffer.alloc(sodium.crypto_generichash_BYTES)
sodium.crypto_generichash(out, buf, key)
t.alike(out.toString('hex'), 'f4113fe33d43c24c54627d40efa1a78838d4a6d689fd6e83c213848904fffa8c', 'hashed buffer')
const min = Buffer.alloc(sodium.crypto_generichash_BYTES_MIN)
sodium.crypto_generichash(min, buf, key)
t.alike(min.toString('hex'), 'c8226257b0d1c3dcf4bbc3ef79574689', 'hashed buffer min')
const max = Buffer.alloc(sodium.crypto_generichash_BYTES_MAX)
sodium.crypto_generichash(max, buf, key)
const res = '763eda46f4c6c61abb4310eb8a488950e9e0667b2fca03c463dc7489e94f065b7af6063fe86b0441c3eb9052800121d55730412abb2cbe0761b1d66f9b047c1c'
t.alike(max.toString('hex'), res, 'hashed buffer max')
})
test.skip('crypto_generichash_state', function (t) {
const state = Buffer.alloc(sodium.crypto_generichash_STATEBYTES)
sodium.crypto_generichash_init(state, null, sodium.crypto_generichash_BYTES)
const buf = Buffer.from('Hej, Verden')
for (let i = 0; i < 10; i++) sodium.crypto_generichash_update(state, buf)
const out = Buffer.alloc(sodium.crypto_generichash_BYTES)
sodium.crypto_generichash_final(state, out)
t.alike(out.toString('hex'), 'cbc20f347f5dfe37dc13231cbf7eaa4ec48e585ec055a96839b213f62bd8ce00', 'streaming hash')
})
test.skip('crypto_generichash state with key', function (t) {
const key = Buffer.alloc(sodium.crypto_generichash_KEYBYTES)
key.fill('lo')
const state = Buffer.alloc(sodium.crypto_generichash_STATEBYTES)
sodium.crypto_generichash_init(state, key, sodium.crypto_generichash_BYTES)
const buf = Buffer.from('Hej, Verden')
for (let i = 0; i < 10; i++) sodium.crypto_generichash_update(state, buf)
const out = Buffer.alloc(sodium.crypto_generichash_BYTES)
sodium.crypto_generichash_final(state, out)
t.alike(out.toString('hex'), '405f14acbeeb30396b8030f78e6a84bab0acf08cb1376aa200a500f669f675dc', 'streaming keyed hash')
})
test.skip('crypto_generichash state with hash length', function (t) {
const state = Buffer.alloc(sodium.crypto_generichash_STATEBYTES)
sodium.crypto_generichash_init(state, null, sodium.crypto_generichash_BYTES_MIN)
const buf = Buffer.from('Hej, Verden')
for (let i = 0; i < 10; i++) sodium.crypto_generichash_update(state, buf)
const out = Buffer.alloc(sodium.crypto_generichash_BYTES_MIN)
sodium.crypto_generichash_final(state, out)
t.alike(out.toString('hex'), 'decacdcc3c61948c79d9f8dee5b6aa99', 'streaming short hash')
})
test.skip('crypto_generichash state with key and hash length', function (t) {
const key = Buffer.alloc(sodium.crypto_generichash_KEYBYTES)
key.fill('lo')
const state = Buffer.alloc(sodium.crypto_generichash_STATEBYTES)
sodium.crypto_generichash_init(state, key, sodium.crypto_generichash_BYTES_MIN)
const buf = Buffer.from('Hej, Verden')
for (let i = 0; i < 10; i++) sodium.crypto_generichash_update(state, buf)
const out = Buffer.alloc(sodium.crypto_generichash_BYTES_MIN)
sodium.crypto_generichash_final(state, out)
t.alike(out.toString('hex'), 'fb43f0ab6872cbfd39ec4f8a1bc6fb37', 'streaming short keyed hash')
})
test('crypto_generichash_batch', function (t) {
const buf = Buffer.from('Hej, Verden')
const batch = []
for (let i = 0; i < 10; i++) batch.push(buf)
const out = Buffer.alloc(sodium.crypto_generichash_BYTES)
sodium.crypto_generichash_batch(out, batch)
t.alike(out.toString('hex'), 'cbc20f347f5dfe37dc13231cbf7eaa4ec48e585ec055a96839b213f62bd8ce00', 'batch hash')
})
test('crypto_generichash_batch with key', function (t) {
const key = Buffer.alloc(sodium.crypto_generichash_KEYBYTES)
key.fill('lo')
const buf = Buffer.from('Hej, Verden')
const batch = []
for (let i = 0; i < 10; i++) batch.push(buf)
const out = Buffer.alloc(sodium.crypto_generichash_BYTES)
sodium.crypto_generichash_batch(out, batch, key)
t.alike(out.toString('hex'), '405f14acbeeb30396b8030f78e6a84bab0acf08cb1376aa200a500f669f675dc', 'batch keyed hash')
})

17
test/crypto_hash.js Normal file
View File

@ -0,0 +1,17 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('crypto_hash', function (t) {
const out = Buffer.alloc(sodium.crypto_hash_BYTES)
const inp = Buffer.from('Hej, Verden!')
t.exception.all(function () {
sodium.crypto_hash(Buffer.alloc(0), inp)
}, 'throws on bad input')
sodium.crypto_hash(out, inp)
const result = 'bcf8e6d11dec2da6e93abb99a73c8e9c387886a5f84fbca5e25af85af26ee39161b7e0c9f9cf547f2aef40523f1aab80e26ec3c630db43ce78adc8c058dc5d16'
t.alike(out.toString('hex'), result, 'hashed the string')
})

View File

@ -0,0 +1,32 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('crypto_hash_sha256', function (t) {
const out = Buffer.alloc(sodium.crypto_hash_sha256_BYTES)
const inp = Buffer.from('Hej, Verden!')
t.exception.all(function () {
sodium.crypto_hash(Buffer.alloc(0), inp)
}, 'throws on bad input')
sodium.crypto_hash_sha256(out, inp)
const result = 'f0704b1e832b05d01223952fb2512181af4f843ce7bb6b443afd5ea028010e6c'
t.alike(out.toString('hex'), result, 'hashed the string')
})
test.skip('crypto_hash_sha256_state', function (t) {
const state = Buffer.alloc(sodium.crypto_hash_sha256_STATEBYTES)
sodium.crypto_hash_sha256_init(state)
const buf = Buffer.from('Hej, Verden!')
for (let i = 0; i < 10; i++) sodium.crypto_hash_sha256_update(state, buf)
const out = Buffer.alloc(sodium.crypto_hash_sha256_BYTES)
sodium.crypto_hash_sha256_final(state, out)
const result = '14207db33c6ac7d39ca5fe0e74432fa7a2ed15caf7f6ab5ef68d24017a899974'
t.alike(out.toString('hex'), result, 'hashed the string')
})

View File

@ -0,0 +1,32 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('crypto_hash_sha512', function (t) {
const out = Buffer.alloc(sodium.crypto_hash_sha512_BYTES)
const inp = Buffer.from('Hej, Verden!')
t.exception.all(function () {
sodium.crypto_hash(Buffer.alloc(0), inp)
}, 'throws on bad input')
sodium.crypto_hash_sha512(out, inp)
const result = 'bcf8e6d11dec2da6e93abb99a73c8e9c387886a5f84fbca5e25af85af26ee39161b7e0c9f9cf547f2aef40523f1aab80e26ec3c630db43ce78adc8c058dc5d16'
t.alike(out.toString('hex'), result, 'hashed the string')
})
test.skip('crypto_hash_sha512_state', function (t) {
const state = Buffer.alloc(sodium.crypto_hash_sha512_STATEBYTES)
sodium.crypto_hash_sha512_init(state)
const buf = Buffer.from('Hej, Verden!')
for (let i = 0; i < 10; i++) sodium.crypto_hash_sha512_update(state, buf)
const out = Buffer.alloc(sodium.crypto_hash_sha512_BYTES)
sodium.crypto_hash_sha512_final(state, out)
const result = 'a0a9b965c23be41fa8c344f483da39bedcf88b7f25cdc0bc9ea335fa264dc3db51f08c1d0f5f6f0ffb08a1d8643e2a1cd0ea8f03408ca03711c751d61787a229'
t.alike(out.toString('hex'), result, 'hashed the string')
})

71
test/crypto_kdf.js Normal file
View File

@ -0,0 +1,71 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('crypto_kdf_keygen', function (t) {
const key = Buffer.alloc(sodium.crypto_kdf_KEYBYTES)
t.exception.all(function () {
sodium.crypto_kdf_keygen(Buffer.alloc(1))
})
sodium.crypto_kdf_keygen(key)
t.not(key, Buffer.alloc(key.length))
})
test('crypto_kdf_derive_from_key', function (t) {
const key = Buffer.alloc(sodium.crypto_kdf_KEYBYTES)
sodium.crypto_kdf_keygen(key)
const subkey = Buffer.alloc(sodium.crypto_kdf_BYTES_MIN)
sodium.crypto_kdf_derive_from_key(subkey, 0, Buffer.from('context_'), key)
t.not(subkey, Buffer.alloc(subkey.length))
const subkey2 = Buffer.alloc(sodium.crypto_kdf_BYTES_MIN)
sodium.crypto_kdf_derive_from_key(subkey2, 1, Buffer.from('context_'), key)
t.not(subkey, subkey2)
sodium.crypto_kdf_derive_from_key(subkey2, 0, Buffer.from('context_'), key)
t.alike(subkey, subkey2)
})
test('test vectors', function (assert) {
const fixtures = require('./fixtures/crypto_kdf.json')
for (let i = 0; i < fixtures.length; i++) {
const key = Buffer.from(fixtures[i].key, 'hex')
const subkeyLen = fixtures[i].subkey_len
const id = fixtures[i].id
const context = Buffer.from(fixtures[i].context, 'hex')
const shouldError = fixtures[i].error
const actual = Buffer.alloc(subkeyLen)
try {
sodium.crypto_kdf_derive_from_key(actual, id, context, key)
const expected = Buffer.from(fixtures[i].subkey, 'hex')
if (Buffer.compare(actual, expected) !== 0) {
assert.fail('Failed on fixture #' + i)
}
} catch (ex) {
if (shouldError === false) assert.fail('Failed on fixture #' + i)
}
}
assert.pass('Passed all fixtures')
assert.end()
})
test('constants', function (t) {
t.ok(sodium.crypto_kdf_PRIMITIVE)
t.ok(sodium.crypto_kdf_BYTES_MAX > 0)
t.ok(sodium.crypto_kdf_BYTES_MIN <= sodium.crypto_kdf_BYTES_MAX)
t.ok(sodium.crypto_kdf_CONTEXTBYTES > 0)
t.ok(sodium.crypto_kdf_KEYBYTES >= 16)
t.end()
})

265
test/crypto_kx.js Normal file
View File

@ -0,0 +1,265 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('crypto_kx_seed_keypair', function (t) {
const pk = Buffer.alloc(sodium.crypto_kx_PUBLICKEYBYTES)
const sk = Buffer.alloc(sodium.crypto_kx_SECRETKEYBYTES)
const seed = Buffer.alloc(sodium.crypto_kx_SEEDBYTES, 'lo')
t.exception.all(function () {
sodium.crypto_kx_seed_keypair()
}, 'should validate input')
t.exception.all(function () {
sodium.crypto_kx_seed_keypair(Buffer.alloc(0), Buffer.alloc(0), Buffer.alloc(0))
}, 'should validate input length')
sodium.crypto_kx_seed_keypair(pk, sk, seed)
const eSk = '768475983073421d5b1676c4aabb24fdf17c3a5f19e6e9e9cdefbfeb45ceb153'
const ePk = '0cd703bbd6b1d46dc431a1fc4f1f7724c64b1d4c471e8c17de4966c9e15bf85e'
t.alike(pk.toString('hex'), ePk, 'seeded public key')
t.alike(sk.toString('hex'), eSk, 'seeded secret key')
})
test('crypto_kx_keypair', function (t) {
const pk = Buffer.alloc(sodium.crypto_kx_PUBLICKEYBYTES)
const sk = Buffer.alloc(sodium.crypto_kx_SECRETKEYBYTES)
sodium.crypto_kx_keypair(pk, sk)
t.not(pk, Buffer.alloc(pk.length), 'made public key')
t.not(sk, Buffer.alloc(sk.length), 'made secret key')
t.exception.all(function () {
sodium.crypto_kx_keypair()
}, 'should validate input')
t.exception.all(function () {
sodium.crypto_kx_keypair(Buffer.alloc(0), Buffer.alloc(0))
}, 'should validate input length')
})
test.skip('crypto_kx_client_session_keys', function (t) {
const clientPk = Buffer.alloc(sodium.crypto_kx_PUBLICKEYBYTES)
const clientSk = Buffer.alloc(sodium.crypto_kx_SECRETKEYBYTES)
const serverPk = Buffer.alloc(sodium.crypto_kx_PUBLICKEYBYTES)
const serverSk = Buffer.alloc(sodium.crypto_kx_SECRETKEYBYTES)
const serverRx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES)
const serverTx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES)
const clientRx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES)
const clientTx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES)
sodium.crypto_kx_keypair(serverPk, serverSk)
sodium.crypto_kx_keypair(clientPk, clientSk)
t.exception.all(function () {
sodium.crypto_kx_client_session_keys()
}, 'should validate')
t.exception.all(function () {
sodium.crypto_kx_server_session_keys()
}, 'should validate')
sodium.crypto_kx_client_session_keys(clientRx, clientTx, clientPk, clientSk, serverPk)
sodium.crypto_kx_server_session_keys(serverRx, serverTx, serverPk, serverSk, clientPk)
t.alike(clientRx, serverTx)
t.alike(clientTx, serverRx)
})
test.skip('crypto_kx_client_session_keys one NULL', function (t) {
const clientPk = Buffer.alloc(sodium.crypto_kx_PUBLICKEYBYTES)
const clientSk = Buffer.alloc(sodium.crypto_kx_SECRETKEYBYTES)
const serverPk = Buffer.alloc(sodium.crypto_kx_PUBLICKEYBYTES)
const serverSk = Buffer.alloc(sodium.crypto_kx_SECRETKEYBYTES)
const serverRx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES)
const serverTx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES)
const clientRx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES)
const clientTx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES)
sodium.crypto_kx_keypair(serverPk, serverSk)
sodium.crypto_kx_keypair(clientPk, clientSk)
t.exception.all(function () {
sodium.crypto_kx_client_session_keys()
}, 'should validate')
t.exception.all(function () {
sodium.crypto_kx_server_session_keys()
}, 'should validate')
t.exception(function () {
sodium.crypto_kx_server_session_keys(null, null, clientPk, clientSk, serverPk)
}, 'should validate')
t.exception(function () {
sodium.crypto_kx_client_session_keys(null, null, clientPk, clientSk, serverPk)
}, 'should validate')
sodium.crypto_kx_client_session_keys(clientRx, null, clientPk, clientSk, serverPk)
sodium.crypto_kx_server_session_keys(null, serverTx, serverPk, serverSk, clientPk)
t.alike(clientRx, serverTx)
sodium.crypto_kx_client_session_keys(null, clientTx, clientPk, clientSk, serverPk)
sodium.crypto_kx_server_session_keys(serverRx, null, serverPk, serverSk, clientPk)
t.alike(clientTx, serverRx)
})
test('crypto_kx constants', function (t) {
t.alike(typeof sodium.crypto_kx_SESSIONKEYBYTES, 'number')
t.alike(typeof sodium.crypto_kx_PUBLICKEYBYTES, 'number')
t.alike(typeof sodium.crypto_kx_SECRETKEYBYTES, 'number')
t.alike(typeof sodium.crypto_kx_SEEDBYTES, 'number')
t.alike(typeof sodium.crypto_kx_PRIMITIVE, 'string')
t.is(sodium.crypto_kx_SEEDBYTES, 32)
t.is(sodium.crypto_kx_PUBLICKEYBYTES, 32)
t.is(sodium.crypto_kx_SESSIONKEYBYTES, 32)
t.is(sodium.crypto_kx_SECRETKEYBYTES, 32)
t.end()
})
/* eslint-disable camelcase */
test.skip('libsodium', function (t) {
const small_order_p = new Uint8Array([
0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3,
0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32,
0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00
])
const seed = new Uint8Array(sodium.crypto_kx_SEEDBYTES)
const client_pk = new Uint8Array(sodium.crypto_kx_PUBLICKEYBYTES)
const client_sk = new Uint8Array(sodium.crypto_kx_SECRETKEYBYTES)
const client_rx = new Uint8Array(sodium.crypto_kx_SESSIONKEYBYTES)
const client_tx = new Uint8Array(sodium.crypto_kx_SESSIONKEYBYTES)
const server_pk = new Uint8Array(sodium.crypto_kx_PUBLICKEYBYTES)
const server_sk = new Uint8Array(sodium.crypto_kx_SECRETKEYBYTES)
const server_rx = new Uint8Array(sodium.crypto_kx_SESSIONKEYBYTES)
const server_tx = new Uint8Array(sodium.crypto_kx_SESSIONKEYBYTES)
for (let i = 0; i < sodium.crypto_kx_SEEDBYTES; i++) {
seed[i] = i
}
sodium.crypto_kx_seed_keypair(client_pk, client_sk, seed)
const exp1 = new Uint8Array([
0x0e, 0x02, 0x16, 0x22, 0x3f, 0x14, 0x71, 0x43, 0xd3, 0x26, 0x15,
0xa9, 0x11, 0x89, 0xc2, 0x88, 0xc1, 0x72, 0x8c, 0xba, 0x3c, 0xc5,
0xf9, 0xf6, 0x21, 0xb1, 0x02, 0x6e, 0x03, 0xd8, 0x31, 0x29
])
const exp2 = new Uint8Array([
0xcb, 0x2f, 0x51, 0x60, 0xfc, 0x1f, 0x7e, 0x05, 0xa5, 0x5e, 0xf4,
0x9d, 0x34, 0x0b, 0x48, 0xda, 0x2e, 0x5a, 0x78, 0x09, 0x9d, 0x53,
0x39, 0x33, 0x51, 0xcd, 0x57, 0x9d, 0xd4, 0x25, 0x03, 0xd6
])
t.alike(client_pk, exp1, 'client_pk')
t.alike(client_sk, exp2, 'client_pk')
sodium.crypto_kx_keypair(server_pk, server_sk)
t.exception(() => {
sodium.crypto_kx_client_session_keys(client_rx, client_tx, client_pk, client_sk, small_order_p)
})
t.execution(() => {
sodium.crypto_kx_client_session_keys(client_rx, client_tx, client_pk, client_sk, server_pk)
})
t.exception(() => sodium.crypto_kx_server_session_keys(server_rx, server_tx, server_pk, server_sk, small_order_p))
t.execution(() => {
sodium.crypto_kx_server_session_keys(server_rx, server_tx, server_pk, server_sk, client_pk)
})
t.alike(server_rx, client_tx)
t.alike(server_tx, client_rx)
sodium.sodium_increment(client_pk)
t.execution(() => {
sodium.crypto_kx_server_session_keys(server_rx, server_tx, server_pk, server_sk, client_pk)
})
t.unlike(server_rx, client_tx)
t.unlike(server_tx, client_rx)
sodium.crypto_kx_keypair(client_pk, client_sk)
t.execution(() => {
sodium.crypto_kx_server_session_keys(server_rx, server_tx, server_pk, server_sk, client_pk)
})
t.unlike(server_rx, client_tx)
t.unlike(server_tx, client_rx)
sodium.crypto_kx_seed_keypair(client_pk, client_sk, seed)
sodium.sodium_increment(seed)
sodium.crypto_kx_seed_keypair(server_pk, server_sk, seed)
t.execution(() => {
sodium.crypto_kx_server_session_keys(server_rx, server_tx, server_pk, server_sk, client_pk)
})
const exp3 = new Uint8Array([
0x62, 0xc8, 0xf4, 0xfa, 0x81, 0x80, 0x0a, 0xbd, 0x05, 0x77, 0xd9,
0x99, 0x18, 0xd1, 0x29, 0xb6, 0x5d, 0xeb, 0x78, 0x9a, 0xf8, 0xc8,
0x35, 0x1f, 0x39, 0x1f, 0xeb, 0x0c, 0xbf, 0x23, 0x86, 0x04
])
const exp4 = new Uint8Array([
0x74, 0x95, 0x19, 0xc6, 0x80, 0x59, 0xbc, 0xe6, 0x9f, 0x7c, 0xfc,
0xc7, 0xb3, 0x87, 0xa3, 0xde, 0x1a, 0x1e, 0x82, 0x37, 0xd1, 0x10,
0x99, 0x13, 0x23, 0xbf, 0x62, 0x87, 0x01, 0x15, 0x73, 0x1a
])
t.alike(server_rx, exp3)
t.alike(server_tx, exp4)
t.execution(() => {
sodium.crypto_kx_client_session_keys(client_rx, client_tx, client_pk, client_sk, server_pk)
})
const exp5 = new Uint8Array([
0x74, 0x95, 0x19, 0xc6, 0x80, 0x59, 0xbc, 0xe6, 0x9f, 0x7c, 0xfc,
0xc7, 0xb3, 0x87, 0xa3, 0xde, 0x1a, 0x1e, 0x82, 0x37, 0xd1, 0x10,
0x99, 0x13, 0x23, 0xbf, 0x62, 0x87, 0x01, 0x15, 0x73, 0x1a
])
const exp6 = new Uint8Array([
0x62, 0xc8, 0xf4, 0xfa, 0x81, 0x80, 0x0a, 0xbd, 0x05, 0x77, 0xd9,
0x99, 0x18, 0xd1, 0x29, 0xb6, 0x5d, 0xeb, 0x78, 0x9a, 0xf8, 0xc8,
0x35, 0x1f, 0x39, 0x1f, 0xeb, 0x0c, 0xbf, 0x23, 0x86, 0x04
])
t.alike(client_rx, exp5)
t.alike(client_tx, exp6)
sodium.randombytes_buf(client_rx)
sodium.randombytes_buf(client_tx)
sodium.randombytes_buf(server_rx)
sodium.randombytes_buf(server_tx)
t.execution(() => sodium.crypto_kx_client_session_keys(client_rx, null,
client_pk, client_sk, server_pk))
t.execution(() => sodium.crypto_kx_client_session_keys(null, client_tx,
client_pk, client_sk, server_pk))
t.execution(() => sodium.crypto_kx_server_session_keys(server_rx, null,
server_pk, server_sk, client_pk))
t.execution(() => sodium.crypto_kx_server_session_keys(null, server_tx,
server_pk, server_sk, client_pk))
t.alike(client_rx, client_tx)
t.alike(client_tx, server_rx)
t.alike(server_rx, server_tx)
})

View File

@ -0,0 +1,37 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('crypto_onetimeauth', function (t) {
const key = Buffer.alloc(sodium.crypto_onetimeauth_KEYBYTES)
const mac = Buffer.alloc(sodium.crypto_onetimeauth_BYTES)
const value = Buffer.from('Hello, World!')
sodium.randombytes_buf(key)
sodium.crypto_onetimeauth(mac, value, key)
t.not(mac, Buffer.alloc(mac.length), 'not blank')
t.absent(sodium.crypto_onetimeauth_verify(Buffer.alloc(mac.length), value, key), 'does not verify')
t.ok(sodium.crypto_onetimeauth_verify(mac, value, key), 'verifies')
})
test.skip('crypto_onetimeauth_state', function (t) {
const key = Buffer.alloc(sodium.crypto_onetimeauth_KEYBYTES, 'lo')
const state = Buffer.alloc(sodium.crypto_onetimeauth_STATEBYTES)
t.exception.all(function () {
sodium.crypto_onetimeauth_init(state)
}, 'key required')
key[0] = 42
sodium.crypto_onetimeauth_init(state, key)
const value = Buffer.from('Hello, World!')
for (let i = 0; i < 10; i++) sodium.crypto_onetimeauth_update(state, value)
const mac = Buffer.alloc(sodium.crypto_onetimeauth_BYTES)
sodium.crypto_onetimeauth_final(state, mac)
t.alike(mac.toString('hex'), 'ac35df70e6b95051e015de11a6cbf4ab', 'streaming mac')
})

39
test/crypto_scalarmult.js Normal file
View File

@ -0,0 +1,39 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('crypto_scalarmult_base', function (t) {
const keys = keyPair()
t.not(keys.secretKey, Buffer.alloc(keys.secretKey.length), 'secret key not blank')
t.not(keys.publicKey, Buffer.alloc(keys.publicKey.length), 'public key not blank')
})
test('crypto_scalarmult', function (t) {
const peer1 = keyPair()
const peer2 = keyPair()
t.not(peer1.secretKey, peer2.secretKey, 'diff secret keys')
t.not(peer1.publicKey, peer2.publicKey, 'diff public keys')
const shared1 = Buffer.alloc(sodium.crypto_scalarmult_BYTES)
const shared2 = Buffer.alloc(sodium.crypto_scalarmult_BYTES)
sodium.crypto_scalarmult(shared1, peer1.secretKey, peer2.publicKey)
sodium.crypto_scalarmult(shared2, peer2.secretKey, peer1.publicKey)
t.alike(shared1, shared2, 'same shared secret')
})
function keyPair () {
const secretKey = Buffer.alloc(sodium.crypto_scalarmult_SCALARBYTES)
sodium.randombytes_buf(secretKey)
const publicKey = Buffer.alloc(sodium.crypto_scalarmult_BYTES)
sodium.crypto_scalarmult_base(publicKey, secretKey)
return {
publicKey,
secretKey
}
}

72
test/crypto_secretbox.js Normal file
View File

@ -0,0 +1,72 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('crypto_secretbox_easy', function (t) {
const message = Buffer.from('Hej, Verden!')
const output = Buffer.alloc(message.length + sodium.crypto_secretbox_MACBYTES)
const key = Buffer.alloc(sodium.crypto_secretbox_KEYBYTES)
sodium.randombytes_buf(key)
const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES)
sodium.randombytes_buf(nonce)
t.exception.all(function () {
sodium.crypto_secretbox_easy(Buffer.alloc(0), message, nonce, key)
}, 'throws if output is too small')
t.exception.all(function () {
sodium.crypto_secretbox_easy(Buffer.alloc(message.length), message, nonce, key)
}, 'throws if output is too small')
sodium.crypto_secretbox_easy(output, message, nonce, key)
t.not(output, Buffer.alloc(output.length))
const result = Buffer.alloc(output.length - sodium.crypto_secretbox_MACBYTES)
t.absent(sodium.crypto_secretbox_open_easy(result, output, Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES), key), 'could not decrypt')
t.ok(sodium.crypto_secretbox_open_easy(result, output, nonce, key), 'could decrypt')
t.alike(result, message, 'decrypted message is correct')
})
test('crypto_secretbox_easy overwrite buffer', function (t) {
const output = Buffer.alloc(Buffer.byteLength('Hej, Verden!') + sodium.crypto_secretbox_MACBYTES)
output.write('Hej, Verden!', sodium.crypto_secretbox_MACBYTES)
const key = Buffer.alloc(sodium.crypto_secretbox_KEYBYTES)
sodium.randombytes_buf(key)
const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES)
sodium.randombytes_buf(nonce)
sodium.crypto_secretbox_easy(output, output.slice(sodium.crypto_secretbox_MACBYTES), nonce, key)
t.not(output, Buffer.alloc(output.length))
t.ok(sodium.crypto_secretbox_open_easy(output.slice(sodium.crypto_secretbox_MACBYTES), output, nonce, key), 'could decrypt')
t.alike(output.slice(sodium.crypto_secretbox_MACBYTES), Buffer.from('Hej, Verden!'), 'decrypted message is correct')
})
test('crypto_secretbox_detached', function (t) {
const message = Buffer.from('Hej, Verden!')
const output = Buffer.alloc(message.length)
const mac = Buffer.alloc(sodium.crypto_secretbox_MACBYTES)
const key = Buffer.alloc(sodium.crypto_secretbox_KEYBYTES)
sodium.randombytes_buf(key)
const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES)
sodium.randombytes_buf(nonce)
sodium.crypto_secretbox_detached(output, mac, message, nonce, key)
t.not(mac, Buffer.alloc(mac.length), 'mac not blank')
t.not(output, Buffer.alloc(output.length), 'output not blank')
const result = Buffer.alloc(output.length)
t.absent(sodium.crypto_secretbox_open_detached(result, output, mac, nonce, Buffer.alloc(key.length)), 'could not decrypt')
t.ok(sodium.crypto_secretbox_open_detached(result, output, mac, nonce, key), 'could decrypt')
t.alike(result, message, 'decrypted message is correct')
})

148
test/crypto_secretstream.js Normal file
View File

@ -0,0 +1,148 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('constants', function (t) {
t.alike(typeof sodium.crypto_secretstream_xchacha20poly1305_ABYTES, 'number', 'crypto_secretstream_xchacha20poly1305_ABYTES is number')
t.alike(typeof sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES, 'number', 'crypto_secretstream_xchacha20poly1305_HEADERBYTES is number')
t.alike(typeof sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES, 'number', 'crypto_secretstream_xchacha20poly1305_KEYBYTES is number')
t.alike(typeof sodium.crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX, 'bigint', 'crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX is number')
t.ok(typeof sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE === 'number', 'crypto_secretstream_xchacha20poly1305_TAG_MESSAGE is Buffer')
t.ok(typeof sodium.crypto_secretstream_xchacha20poly1305_TAG_PUSH === 'number', 'crypto_secretstream_xchacha20poly1305_TAG_PUSH is Buffer')
t.ok(typeof sodium.crypto_secretstream_xchacha20poly1305_TAG_REKEY === 'number', 'crypto_secretstream_xchacha20poly1305_TAG_REKEY is Buffer')
t.ok(typeof sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL === 'number', 'crypto_secretstream_xchacha20poly1305_TAG_FINAL is Buffer')
})
test.skip('crypto_secretstream', function (t) {
const state = Buffer.alloc(sodium.crypto_secretstream_xchacha20poly1305_STATEBYTES)
const header = Buffer.alloc(sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES)
const ad = Buffer.alloc(Math.floor(Math.random() * 100))
sodium.randombytes_buf(ad)
const m1 = Buffer.alloc(Math.floor(Math.random() * 1000))
sodium.randombytes_buf(m1)
const m2 = Buffer.alloc(Math.floor(Math.random() * 1000))
sodium.randombytes_buf(m2)
const m3 = Buffer.alloc(Math.floor(Math.random() * 1000))
sodium.randombytes_buf(m3)
const m4 = Buffer.alloc(Math.floor(Math.random() * 1000))
sodium.randombytes_buf(m4)
const m1_ = Buffer.from(m1)
const m2_ = Buffer.from(m2)
const m3_ = Buffer.from(m3)
const m4_ = Buffer.from(m4)
const c1 = Buffer.alloc(m1.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES)
const c2 = Buffer.alloc(m2.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES)
const c3 = Buffer.alloc(m3.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES)
const c4 = Buffer.alloc(m4.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES)
const key = Buffer.alloc(sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES)
let ret
const tag = Buffer.alloc(sodium.crypto_secretstream_xchacha20poly1305_TAGBYTES, 0xdb)
sodium.crypto_secretstream_xchacha20poly1305_keygen(key)
sodium.crypto_secretstream_xchacha20poly1305_init_push(state, header, key)
t.unlike(header.toString('hex'), '000000000000000000000000000000000000000000000000')
ret = sodium.crypto_secretstream_xchacha20poly1305_push(state, c1, m1, null, sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE)
t.alike(ret, m1.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES)
ret = sodium.crypto_secretstream_xchacha20poly1305_push(state, c2, m2, ad.slice(0, 0), sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE)
t.alike(ret, m2.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES)
ret = sodium.crypto_secretstream_xchacha20poly1305_push(state, c3, m3, ad, sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE)
t.alike(ret, m3.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES)
ret = sodium.crypto_secretstream_xchacha20poly1305_push(state, c4, m4, null, sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL)
t.alike(ret, m4.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES)
sodium.crypto_secretstream_xchacha20poly1305_init_pull(state, header, key)
m1.fill(0)
tag.fill(0xdb)
ret = sodium.crypto_secretstream_xchacha20poly1305_pull(state, m1, tag, c1, null)
t.alike(ret, c1.length - sodium.crypto_secretstream_xchacha20poly1305_ABYTES)
t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE)
t.ok(m1.equals(m1_))
m2.fill(0)
tag.fill(0xdb)
ret = sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2, null)
t.alike(ret, c2.length - sodium.crypto_secretstream_xchacha20poly1305_ABYTES)
t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE)
t.ok(m2.equals(m2_))
if (ad.length > 0) {
t.exception.all(function () {
sodium.crypto_secretstream_xchacha20poly1305_pull(state, m3, tag, c3, null)
})
}
m3.fill(0)
tag.fill(0xdb)
ret = sodium.crypto_secretstream_xchacha20poly1305_pull(state, m3, tag, c3, ad)
t.alike(ret, c3.length - sodium.crypto_secretstream_xchacha20poly1305_ABYTES)
t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE)
t.ok(m3.equals(m3_))
m4.fill(0)
tag.fill(0xdb)
ret = sodium.crypto_secretstream_xchacha20poly1305_pull(state, m4, tag, c4, null)
t.alike(ret, c4.length - sodium.crypto_secretstream_xchacha20poly1305_ABYTES)
t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL)
t.ok(m4.equals(m4_))
t.exception.all(function () {
sodium.crypto_secretstream_xchacha20poly1305_pull(state, m4, tag, c4, null)
}, 'previous with FINAL tag')
t.exception.all(function () {
sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2, null)
}, 'previous with without tag')
t.exception.all(function () {
sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2.slice(0, Math.random() * sodium.crypto_secretstream_xchacha20poly1305_ABYTES | 0), null) // fixme
}, 'short ciphertext')
t.exception.all(function () {
sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2.slice(0, sodium.crypto_secretstream_xchacha20poly1305_ABYTES), null)
}, 'empty ciphertext')
/* without explicit rekeying */
sodium.crypto_secretstream_xchacha20poly1305_init_push(state, header, key)
sodium.crypto_secretstream_xchacha20poly1305_push(state, c1, m1, null, sodium.crypto_secretstream_xchacha20poly1305_TAG_REKEY)
sodium.crypto_secretstream_xchacha20poly1305_push(state, c2, m2, null, sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE)
sodium.crypto_secretstream_xchacha20poly1305_init_pull(state, header, key)
tag.fill(0xdb)
sodium.crypto_secretstream_xchacha20poly1305_pull(state, m1, tag, c1, null)
t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_REKEY)
tag.fill(0xdb)
sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2, null)
t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE)
/* with explicit rekeying */
sodium.crypto_secretstream_xchacha20poly1305_init_push(state, header, key)
sodium.crypto_secretstream_xchacha20poly1305_push(state, c1, m1, null, sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE)
sodium.crypto_secretstream_xchacha20poly1305_rekey(state)
sodium.crypto_secretstream_xchacha20poly1305_push(state, c2, m2, null, sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE)
sodium.crypto_secretstream_xchacha20poly1305_init_pull(state, header, key)
tag.fill(0xdb)
sodium.crypto_secretstream_xchacha20poly1305_pull(state, m1, tag, c1, null)
t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE)
t.exception.all(function () {
sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2, null)
})
sodium.crypto_secretstream_xchacha20poly1305_rekey(state)
tag.fill(0xdb)
sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2, null)
t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE)
})

214
test/crypto_shorthash.js Normal file
View File

@ -0,0 +1,214 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
const vectors = [ // generated from https://github.com/jedisct1/siphash-js/blob/master/test/index.js
['aON1dHrq90SbG8Hx', 'v7LyiwuCrB7EgAibPve6Yg2gLmggxE6j7ocR37EudrH_P9XX2rQK', [147, 73, 50, 63, 71, 98, 203, 42]],
['YOT4AG5F7ONRW5na', '4Ks1pPO_2wGYR-gfJShqUO-FirA9c5cF4oKwvStp2Ix5hHUg2klPofVJ8TZoBdFfgTh8', [138, 27, 129, 27, 185, 163, 160, 153]],
['63UlqXfSckA3Dv8S', 'bMQudI8yVdDx5ScGQCMQy4K_QXYCq1w1eC', [6, 78, 44, 167, 186, 29, 113, 244]],
['P3hpmZEuwfDO_uZ-', 'Wh8yRitk__n4MsETCTRFrB4bjWRtPjUZVLPnywlvv5nTMA2C71', [241, 171, 151, 44, 166, 163, 156, 234]],
['d9oTrpd-a_Na4b6w', 'f-NT', [182, 147, 203, 88, 65, 57, 119, 203]],
['fe88HBnyyEiuIJ8G', 'KSWP9sFkhSdGsha0Fmd5raCf_eA5gnV1', [218, 10, 3, 10, 16, 50, 241, 229]],
['o6LxtnACG0RGQ3z-', 'k8zMl', [16, 158, 19, 145, 214, 142, 177, 55]],
['AHGkoQQ6xdf90MD9', 'HC9bz8XUYkan0jxYSaj0vP-cs324Y4PrnAXutwKBgIko5oOOOViJSjLD2m8WenV8HdF78J', [157, 186, 255, 238, 165, 21, 187, 163]],
['TlVmpfbZMFkeuENo', '5is', [166, 36, 114, 58, 101, 106, 79, 30]],
['iBLscVfsPM1xrSFJ', 'J-aH-', [14, 91, 64, 158, 190, 247, 72, 26]],
['hUehErdKolgd0erH', 'DhS94w_07-vaAXo_msv8Fk57slIHnuxy3iv4Yymh5k', [45, 207, 192, 24, 158, 243, 93, 68]],
['B-aq-09jmO0z_PUD', '1p2IMG4A1NMyWsfUS02VK8fOEhn', [161, 224, 65, 80, 91, 44, 131, 177]],
['fyNYE8SMJvYrDgao', 'HWCtQs19BHZcH', [122, 114, 254, 14, 124, 226, 23, 173]],
['5vQHK_yJlJez45N5', '8YJwfpxwbH9h-N27i-uTUUK2Vt', [142, 216, 87, 77, 16, 17, 8, 199]],
['q7Oo0g9DDjLJ_pyV', 'jQFAHtrTUDaCaSIcis5h2j4fyOJpJGfdZBMTO5GOAAB4AwZtutDenNZ', [230, 111, 182, 25, 233, 231, 14, 141]],
['IUle6P8g2uyX_8ms', 'hOKGFGrsAux60CQmbOjQd-EzQBKUjLbDUhhtsKt3ZY4', [64, 247, 102, 236, 211, 145, 4, 152]],
['-bZa23onpInwqNWG', 'DNbtZuulH9', [247, 2, 142, 172, 208, 100, 60, 127]],
['1xjmLXTmVJwse8M-', 'j1_Hh', [197, 81, 6, 184, 57, 173, 83, 126]],
['Ey7hygEVd8RxZdtX', 'GNRDNJDu00L', [137, 196, 184, 4, 146, 27, 188, 191]],
['weTzikz4EGUbhSgC', 'g1SXT7b4Zz6q2tQykV1tZS', [105, 39, 69, 220, 198, 210, 96, 240]],
['OjSaplYVoQPDXG7S', 'QCk4v3D9s6R471p0xa--Vv00vzIaMpJ1S48Qnz6uzhmtke99HmWcY9vapyjdWVS', [183, 208, 142, 194, 95, 247, 239, 122]],
['4g2ZB-SA-HlqJT7D', 'N5Ht5QIk6KziyTE4-q5eNkqGdQgg8fxkr4w-ARqRgdaZd3XpbePGGb4jPFo3', [127, 245, 152, 248, 155, 148, 212, 127]],
['CXOF2EKm5CDPYpNC', 'xkY0T8bPF4JFq6Mu0K5YtFp7KfOni', [124, 172, 24, 66, 198, 236, 234, 226]],
['ID4UzFBiztXW--b0', 'qyICNMPaivgDmX', [46, 95, 156, 18, 186, 88, 188, 122]],
['TaGesMDe_0UNGzcp', 'nlNv', [103, 245, 211, 70, 87, 104, 0, 17]],
['lMDS8Vcs-8aCV9hJ', 'KW44Qk', [69, 47, 130, 50, 196, 101, 206, 62]],
['BmQCaB-c777zvFsc', 'o-tr2zQVbtrmkH4rCCAXoXFt8KwAWo4YFpK', [123, 168, 235, 94, 113, 233, 190, 213]],
['OQlCpJOLmsouyme1', 'aRk9nyHhXlad-TpIemD2VTRiHVlzSysY7uKof9ApR5DejFjT-Bmdzl_z', [89, 201, 222, 238, 50, 99, 249, 215]],
['t6Wl3FKDhr9FAMzz', 'BLu17bk_iQtpGv1N4A', [80, 7, 121, 129, 115, 84, 153, 140]],
['XU5km7La0ujNVvlV', 'OUEAH4yu6SXQ4I8zjn07NuB_AudmoewXc39HqgN8rc', [220, 180, 100, 142, 210, 176, 72, 108]],
['zDKBNpM2cdf0HwkK', 'dEqgpqTRc', [221, 42, 57, 242, 197, 147, 27, 81]],
['yZGrKEShM0z7Vvns', 'sgUtgxRQpMl_o6iuZqomKhJxaSBCD_NBHa2lqX3cWfq8byu', [211, 179, 114, 59, 129, 223, 168, 65]],
['4-wM8GXg1a7hyerE', 'djJ3-b2', [157, 165, 254, 119, 109, 239, 114, 115]],
['jD3Y4PgdExHU2JaY', 'uQC59dKTf3unOGu-Lg9IgmC8MTSg-BcH-', [249, 179, 174, 181, 118, 232, 40, 255]],
['dZhRW8ubIZovieQg', 'GCbxph1HICSKgHLafk_8TRjGdZa7jnJOu', [73, 24, 76, 226, 201, 86, 43, 223]],
['P9hudzT3H87QzC9E', 'Vfeo26fUa3sLk6BNM', [31, 150, 174, 223, 224, 214, 127, 107]],
['ocfdt04Np8Bs5hn9', 'dQiaUqksbXOWmBPt2kBn0ARiVkr3r4mBwypQq', [203, 253, 155, 6, 148, 92, 81, 212]],
['UuQ68x330IdojsLI', 'pb6-OdmVdQ1gLP8E1szvlf0T6aOQp-EQHPW-tAKQ8Xj', [23, 158, 11, 26, 216, 251, 17, 229]],
['T4ec6Q68QKiuIARL', 'BeLjFIoODtDg5vLMLBN1Sae', [250, 103, 43, 65, 80, 229, 66, 116]],
['xmZBUpwjJwnXZAp6', 'WS2F3Nzg2s7TqVIygm8W1tQyNc6DFy', [186, 206, 177, 250, 182, 139, 138, 19]],
['4qB6m0d_ryzb3w6q', '2Nr1sd1phWDB9gnuYOLUsjvX9jxntScWyRlX3Nj_xs8MV10LGgSgfRBKVGnO', [97, 101, 207, 79, 55, 205, 142, 253]],
['SmVONU3BEODnkbdM', 'G4WIU3UrBqbN6_nccFrIyx_TdXx-W80YzWw', [33, 147, 134, 20, 73, 169, 2, 107]],
['zseM9_-0y7B9URxM', 'us8B1DmHxOF10ue3jm2VfoJ250h364zRd2U8VIm2Lbkf3OWprSUpLF4ePjdj5aS', [80, 47, 98, 151, 139, 175, 78, 166]],
['WY_sEWLFAybHSwX4', 'vLJyXNkHCYGHWsvhXcU2sWYzgFYlWF7A_ZjFg8kJ4wwuJ', [132, 67, 168, 204, 90, 10, 169, 235]],
['maWrEov1bBjSq2Zn', 'sCP9zPakZ_wZ8hcQu-G6nN', [136, 204, 107, 221, 66, 198, 31, 201]],
['tXInZHO-x4AWxKTp', 'JQUM_O-E4-YI6dhxo', [36, 245, 166, 183, 31, 222, 192, 96]],
['OqaQt_b1hvU-atC3', 'X7Ou8cKo17xHlq_5gwM56GZrCSJBReeA60pDj2hUer6', [169, 107, 175, 79, 116, 24, 153, 93]],
['nHdnXHGmGknC8FfC', 'cRupnAESNmU', [18, 200, 205, 81, 7, 32, 8, 213]],
['59n9lAJdrxIz3joe', 'WBPr', [75, 153, 152, 122, 242, 233, 165, 255]],
['q-PAAgkE9z2xed85', 'AFOQD_H7MO3q3cxLa7TOUd89kpH03SpjpqmzY6AX16-uZFYcZZBb8D', [45, 4, 101, 133, 174, 99, 42, 4]],
['tBzStZxn2ZqlQfBf', 'nZdIaI7-bdqqh6aU7w4HfDCByX-x4_3q9Jf', [253, 49, 199, 224, 50, 253, 75, 144]],
['rH8Nn75LyYC0hjVG', 'IrDPpL-dkoh6VTy7pOtKKdAD9dLwUnE-', [76, 2, 97, 127, 190, 74, 74, 5]],
['F-pI7AhpS1V-48eT', 'Ao7hV41P08Zq4C1szyOVN7K1iWW8z', [121, 76, 85, 13, 162, 105, 174, 114]],
['Khje_RmXXmJ3CAb1', 'TvMx3ISTfIQ', [237, 102, 92, 182, 242, 45, 27, 178]],
['G1KRzk-KMqCk-kbD', 'imHZWdBz01lGR3m1zuO74berNn68uFZR3kcoWEaMhVjJ1g', [165, 3, 34, 126, 199, 101, 203, 184]],
['wJhnTtBLcy_1rZay', 'qbZ6oK0a4eWf2ud1sEnKLeguOmYsbG4aOTdlMdrf', [226, 169, 14, 147, 180, 88, 90, 132]],
['vVl9fhjkwASu2WXe', '8-CjQylw18IKWgAL2mMxo', [30, 193, 202, 34, 74, 172, 72, 42]],
['m2Qx2Dtbvwv3qjNJ', 'WrIqIIsHqbgm3Qfg03QvaVG9G6fz2zxjnfNZUVuX8XUtjz4LQuj3VZNh', [237, 163, 64, 58, 187, 234, 117, 106]],
['5R1maUgHiPQ0ZoaD', 'SZJ6uMXnMuLll2xOfHcy_DE', [209, 26, 182, 131, 19, 180, 5, 55]],
['dDBufcmObAK1dKYw', 'ayjd0F5mqWsVF0MtUNJYo8S8GhuCsMCnEU6k3H9z0f8', [126, 244, 206, 245, 56, 4, 39, 63]],
['o_YPVOjQ7Xw0G9OD', 'UPF-HW1hJukwdVvhCl7IZJzy7a', [30, 211, 48, 214, 88, 189, 59, 33]],
['oule-vFYlFJfsXU3', '8ORL7DUv28-yVfUw_cJ3imWP-iXrQRmzZRp0jtspwW_qm-rXmc1aBsbvbAut8', [66, 62, 243, 87, 153, 23, 230, 113]],
['kEPlQxhC27GQcJeb', 'wL-dAWvwZapITZZvgW46', [153, 83, 52, 252, 33, 23, 48, 216]],
['GFilE6NpBPWE25uB', 'RzoQCcd5NVeDbd2cx', [144, 101, 221, 104, 142, 244, 87, 216]],
['sENqlFHs0NvkY28u', 'Gm2ojB-BJBdL', [75, 226, 42, 7, 94, 14, 215, 52]],
['mxiOr15qouOEhzHS', 'SChjLg6SXpEb9', [174, 64, 56, 79, 211, 158, 21, 229]],
['pFL_Sbx5RW0fuPHO', 'hdb8HqaxEN99N4V1STTpnR4kr9F-lONwKp2TcOCopBFnDrjITz3jHPM4WKIYyw59US', [108, 66, 228, 165, 111, 142, 78, 201]],
['sMgAXpCtVqeFm14R', 'dNPnh6shnGYEZuN0id', [101, 147, 101, 20, 126, 33, 84, 255]],
['nTu9mRGqYc1SOPk7', 'ogL8VEqgoMkh6YNgTzvF4f87wHvmRhzncGPunN2ZJ5p3qUqZeJ3', [253, 16, 23, 144, 34, 207, 28, 82]],
['d5jDH8Ppk82zj_vd', '5sfq9Q_0P0H', [197, 245, 4, 89, 247, 26, 240, 77]],
['bEEUPVwdHlYwYL6o', 'AGoiVTE9foWm2MZqsn3dfS1XQiQW0QJwLXi6oXR2L9nMnPCPG_oF', [186, 203, 217, 87, 4, 177, 20, 242]],
['JbKhWuTfRMWb4hFD', 'NTNhYIahQ769TsCDwFyfOYZ8x6np58jg9hMAHFH-BMv7hBwESi596D4aDuyPabFGbqcG', [60, 79, 166, 97, 146, 213, 223, 59]],
['hvCtw1q_GJUBFW_X', 'uL5zgFM9WUTyO25dzVCmSVOxbpV70ZPurKK-CPUAmP', [127, 4, 233, 105, 7, 183, 123, 61]],
['hWxh0P6EXlm4yYKA', 'NUgrOoTOfqaB6JDZj', [96, 255, 249, 149, 117, 178, 189, 183]],
['TLHDMak8qeH3ABaV', 'HW-7PPunyMCinXt8QjQUuJUzZZQs1-T9ADR-6y', [46, 167, 85, 216, 34, 240, 131, 74]],
['uE4OfzzqHVDH8lbd', '8KCUyGtkcG-T8gA3lpplC13LsnFZ', [18, 9, 33, 96, 47, 132, 243, 76]],
['ocjA0Quge9vdCDbH', 'tLlU03I9CDBbP1Pnl6KM3MW34TNzuuZYv0u-uU-l7RtFF0OmGoySyg_yc7vWswGkz', [124, 174, 227, 126, 197, 91, 232, 11]],
['TDVmxGeyDULfxyrz', 'A57Y0_L6K4TTzQx1-Yr1E6fVAZi31RyipeK0Q4uqwXXfRLo4tz2a5PSqN3-bdQ4f2', [53, 212, 137, 227, 12, 85, 50, 251]],
['8OhqW3sA7s1vqEDr', 'jlFquRWvL07TyLjW9ZNk81gxkvs4u1WLkNhOQVLOjFjw3iecMjun5Yk0xcruo', [147, 130, 134, 67, 235, 29, 115, 34]],
['9kPcY6rfhPzSzEGn', 'nS1kAxpsghzJJXiCzhNycDk2_EJ_yIT97fV2kxXTtfZ9p0', [178, 109, 176, 237, 184, 79, 209, 89]],
['AJJ_yoEL8WyEtA1U', 'vFNErhfCk1TZiTFMA6J8D', [26, 63, 142, 247, 30, 50, 167, 102]],
['PBr4drRAJTaWv5Um', '5quc8Vd2rHVNk2NoDxk3TL', [150, 113, 209, 153, 101, 74, 42, 2]],
['MnODoRJI2FgZrvLs', 'gqJ_7HnrfiqYkenyvhe53SB1vTBgMiMB3kxF5', [205, 11, 216, 157, 130, 39, 60, 161]],
['iSxQPJpp_s0ws-4b', 'K-J', [46, 78, 209, 241, 112, 90, 91, 181]],
['ZMm2tCGDJ04A3I_6', 'gw-wcFYO1G2KEqJagWAic2l2d1FoTVXVT', [22, 60, 166, 216, 76, 146, 36, 22]],
['Hxf6qsSIV6blPdB1', 'GTWOerCQdUMkL6it6hEEPKBcOe_9f_B618ivjeM3BKfjzRQ8rvcGjUUJnsljerca6', [122, 74, 100, 36, 79, 173, 4, 91]],
['U5gXdMrRYUdxuDjK', 'siy9CxY2BbhazTqBWwFrtBLh', [79, 92, 248, 231, 189, 215, 27, 51]],
['YJiK_B-TENJsVnd_', 'Ohyz8XU06XWewcgTX-PffLVdatU3UFl6CYe', [22, 147, 91, 237, 188, 184, 70, 223]],
['J7wVNfLdkCCtndH5', '1Vw163YqXwP8cPXIy5dSkcIoClBep7gWb0qGJzHM8h_hzk2GFtZyLKk', [123, 221, 220, 145, 75, 144, 103, 74]],
['elId3b7ZyOg6HVif', 'N89kQR7VMUgF4DyWhpTo_ZW2lERbNqFa1RdXjaUctO1FdevDAZaA', [39, 244, 17, 57, 240, 193, 34, 112]],
['ydBueYO29jaUsEVU', 'HMcnfvYjjz8Uf8bUhxXlAYHcyO7x5NHE_gc3bcWSMWJD2JdryrUBBdYj1', [252, 15, 32, 244, 143, 126, 130, 34]],
['fVprx-PzTSx6CUcX', 'Q', [253, 22, 240, 135, 62, 55, 219, 1]],
['9ORMwecQjlob9aTT', '2cpq2XTWPk5sVLlN4OR5y6X_rTRFNUURgrwnWDg76u927cYud6PS-17UTgd3TO9g3K4', [15, 124, 108, 136, 56, 254, 85, 250]],
['-V3BEGXuTWtFOMv4', '8l6qcZXfG9iSywi1IgwJ_PkZh0Bg2iR1cbGps_sWPdKXbIvDDX-3IeTTg', [111, 8, 18, 99, 6, 72, 56, 232]],
['Cbvx4_KdboiNHs6P', 'nzUo0UnqKn05adw5g0jtBN703bUgb8UxywfC93I7KN', [85, 17, 95, 157, 77, 25, 206, 45]],
['SDPzfgeqkvmi62JH', 'Z6kJuDD-8FSz1VwOuPeoSJ6X-4hpib563UjYxtFcB4SvhQr-Hstg5OhMi4iZZ', [153, 35, 172, 58, 141, 180, 95, 97]],
['mBJlhP6D3M2raEjD', 'ogtg66jr2KLCFO2RvodOXw0mt4XS6BOnLhBI_gDV0', [85, 231, 198, 97, 240, 108, 230, 150]],
['Sz-mxKc7KGM7SDaf', 'ecQ-7-3VddOdMSeKUbZE1t6Aa67pYGXjQeOckq1l50GkvfomFr', [18, 241, 24, 133, 142, 74, 218, 178]],
['_5ck5scojT4oyJEq', '43oLkeixGHShTMUhtI', [35, 190, 107, 33, 2, 165, 11, 34]],
['48ulC82W4qv49InN', '8HQyT55TtmGahy6w', [2, 70, 28, 124, 164, 101, 100, 185]],
['-exgd5coAHqBu3ga', 'vRfqYthbUNh', [48, 188, 141, 96, 138, 114, 132, 143]],
['hJEBugObOX06pplH', 'oYYZ-v', [153, 112, 89, 5, 46, 138, 209, 254]],
['eSDsC63oTtVfi_F7', 'BVmyPas409CmRHiRRiTPjJL87KgJefuDK6lEh5isghLl7l3a4Xmxa', [21, 198, 30, 251, 173, 36, 165, 82]],
['KZtUPWMUr469RWL8', 'F9K6TUd6j7Dm25rAS7cqOKDtSnnxj0hYKVTMFQ6CfA5218gPeZo', [203, 233, 183, 39, 57, 54, 60, 173]],
['0TeBxGk-V7RPSZML', 'kmL1fKqHwAoxI1b_ap8I9fGZMmcx3gIMiglxLLPFWOoDNUGe', [193, 7, 13, 148, 71, 231, 166, 135]],
['PWYY82PNqwshPHiv', 'Ya4LyHqxIxK8GaND9FIzqugleh-QELha_ntbRJixl6hZI5m3RfdrcntjiPJ', [27, 177, 64, 55, 129, 165, 132, 108]],
['PtCub86vGwNj1tcv', 'qR08eqAeNrrUYDl18C-wttqMDk', [66, 134, 247, 100, 38, 3, 7, 125]],
['3eqQxzhNdv2kJqy5', '0wxAd9NT-Z8xFzomFwgMqMVbaUg', [36, 191, 165, 105, 211, 159, 155, 13]],
['MgEjpTNPFFwes6Sm', '7SCVGNJYZhtnbiLZAE5TrsL5K1X', [208, 79, 201, 49, 48, 3, 227, 199]],
['vSofRAYxXUU1qjhl', 'HATE-YsASxySRkK5aJR4yV0mxx1YAuEgM5tUqyJDc7cLL', [61, 205, 183, 24, 68, 135, 7, 74]],
['kIUe96sZ6LV464T_', 'rjwrCOQAzLFbIM_3M7KfDQ1A6r3nkebk-dgqORG0Uy-n89_apYNLVTbdr3yuzXKOTfkRh', [83, 214, 143, 126, 145, 218, 225, 186]],
['8wao85IcCu1mC-Rc', 'AdVncBX6wkLXqMQPol3tNDPd5HJ', [161, 223, 243, 36, 219, 75, 215, 63]],
['NRVNeO5wysG3DRuU', 'Mr8vhiVPo5GpI6sho4R09k8D-vFgcghF3-kF', [246, 119, 57, 225, 254, 189, 182, 180]],
['VHJZOECxfyxVyufk', 'TMB3UMDEIs-vj_9aDBNDzT6HkHcwQQhr4EnG6A1AD9JkHENVAAQnS7s', [117, 85, 69, 116, 56, 27, 123, 62]],
['TUfnTd3pmaJzSdD4', 'VoRGCJgaGEhPSGRl0EPKWIzN7CRpD49CiyjC7y_4xRpppMNlR4v', [3, 116, 140, 4, 113, 208, 78, 186]],
['-I1YgwmWxehyB6kv', 'IplQLxea3JGywQn3XMNWrqVbE', [137, 251, 109, 201, 11, 101, 132, 97]],
['4ic5nM5lbfMOXDRR', 'TfVtpOoAQt1IxL0qJtAQoCJJThyxncIagOvKSpxjD7RDmh7YQBHWPkuv5lpSzpN', [192, 203, 84, 99, 85, 184, 122, 44]],
['NYOq6hIu2C-aZPhE', 'QQa0EWIHXqbrkq3nBeXt6yEj12z', [40, 199, 197, 21, 82, 53, 100, 58]],
['nC93tajnfzk6bMtM', 'p9gbEB4nMHXDqmOC413rI4Z', [200, 140, 102, 143, 89, 170, 219, 32]],
['ZCCkYIbGOzXa5GRO', '2f9VGQeb4AtW6SwPjAGxxjyHNw3-MZj2BfxttNLxM0Tv_rpXO8TUH4YASb', [0, 174, 100, 194, 149, 35, 81, 12]],
['oapO2W6hces4Pfkc', 'oEyf5eqpM-N7LBp3C5vejvO7M87OzT4MHdwJz', [140, 195, 199, 20, 207, 60, 104, 240]],
['__daPiDXrnPpS7eO', '1_tnhApr6nZbWIEPja0jAJ6LbTvD6oAEvPyrLYQ', [255, 244, 76, 119, 124, 124, 146, 214]],
['5iIExqPt5W-ZpudD', 'jNbLiDmQdN5X7HEOfgnAi5A7s1pGXwP41hX1Z', [149, 68, 125, 203, 174, 150, 66, 31]],
['gD_J-R8tOb977BtL', 'f7A81Qbh8gQhfRpOmtz5-ZJqBxiQJ6myBhGfqK7BVaGBL_W2MvfB', [106, 38, 140, 196, 141, 190, 232, 110]],
['ZxHO4JJ8p45jTUXU', 'fs4Oy8mPZS6919SZ7gDyKIILDkXnPt8SsXkfBd-Mnm4wO6alw-veQD9', [209, 53, 104, 100, 102, 136, 84, 134]],
['2bVzT0moojGNQgIX', 'nuyb-AgYY-rsmhtdav3LC7meSPy1dCosjSw0YAvgP', [1, 201, 247, 25, 104, 147, 148, 252]],
['FicyyNT0BRua05i9', 'TG4leSS_mcrZ_L68GKFdxc4-McFCCtdG7QpbPu_MolD5luE6n3dKlPzb9MvfvkiZKi', [136, 150, 66, 224, 178, 235, 114, 238]],
['g5Qaf7mQAIxuHR0O', 'A6u5gtb1yMSiGlWVt3exYsRS', [169, 20, 115, 32, 43, 71, 21, 193]],
['aOACI6GP6u4WFyxp', '1eEx55L3E9MZga7l1WzpnKfI', [177, 26, 15, 27, 217, 101, 69, 195]],
['Rr2jLg-asIQrlaRJ', 'rgALEbs', [163, 103, 250, 90, 4, 46, 69, 32]],
['p8qW0oYzj5zi55s5', 'V1ZCoK73ifwcnzPjQEN7Q79MtZCskcpqiE3gfbqYPYRmy-q0lPxopkZZp2lNWKkpL_q5z', [29, 121, 240, 174, 51, 38, 238, 123]],
['wA0cNUJOhIMpiopE', 'U2RE2L2zZysyOTcsj5_JosVDaMRtUxkRWVCeBH0AeodMvYGBcHizhxc2QM89', [40, 230, 148, 164, 7, 168, 3, 46]],
['zBCN1w4ypWCEfpwC', 'VRcTwONsyRQIy2ymVniMmry', [184, 177, 56, 54, 152, 189, 120, 222]],
['i8cumEDwOxSXT0gL', 'ifKav', [53, 190, 193, 228, 179, 41, 246, 171]],
['g3EswbaCSNMsegzm', 'rTFnEuEDlwBB0Dw_q3-FUSaTCEjWe0pOPZDIWD35Us08Qa-nulc57YjDoGphUfBamq', [157, 64, 119, 179, 60, 147, 48, 17]],
['iYsckWoQTk5ap8YO', 'wIyTqa43-_GiZlHJ8UXcD_tnqKikH5DZUWxdQ1xjYMyzCr2JvKKRBm8BbcDl_Q8p', [96, 237, 170, 183, 48, 45, 116, 106]],
['Iyk5MoAjoWq4n8bG', 'IV2N5MC6kvk95ykEzb3jj0A7Sv0jjif45SR1avc0bRWot2aW', [99, 23, 149, 225, 242, 204, 47, 7]],
['NfzdRXCegRRsHHYj', '5uLBPbyFQqiv', [136, 45, 110, 192, 36, 204, 171, 218]],
['YiJTXegVwaNDtlpl', 'DbwKoF3CI5kd2JRKwfyuLpeGd6sFhqI0t43C2ph', [188, 126, 147, 191, 9, 114, 107, 60]],
['ZuUlFM-yEzZ9XHKj', 'errecd71', [158, 231, 84, 47, 149, 227, 92, 111]],
['EtEXELa6V_NSjvEh', 'yrTjrRuW8mJc3utw2JUH7iIW-J5vF3t9GC1-ZvRmO8UXNsG8-I3Iqgtinzoabqqbs1yvR', [186, 52, 144, 215, 104, 246, 174, 71]],
['q2uA_VwMnaBtAgTx', 'uJOymuDgBBS9Ec56JRGmKYsMHoGLCKA5wzwhtYf-g8-IT7UsAX1JHFGSV0EF', [176, 65, 188, 134, 212, 6, 97, 186]],
['4RmqR10QiIZDDKNO', 'oWY0Aj2CDCWuEFhdNHq2RFcGJD0sSRxK5K', [114, 28, 238, 228, 122, 40, 82, 13]],
['a9DfUPCLyQ_yrNIa', '5G-6AVe7CBJl-NuuUN_7TN', [95, 206, 124, 185, 194, 207, 227, 111]],
['8oB5yG87C2v5j0_4', '1S-aiUNRJ2c', [123, 42, 242, 79, 90, 36, 208, 81]],
['ZA2ZT22NXwD_UvTM', 'UpV3pLYniWPm-PnWUAbBNeO4V-zuuw6IZQ1ZprLsC_LjGdSJP7rZCnoPz', [189, 209, 102, 128, 246, 141, 212, 109]],
['ycz6aiuQFGKxZVsM', 'fBuJp4_A_hiq--4uBhxjXfT3nRaYEJ8azW2_FKooXdSVRv2Y03VoWzPzG', [241, 127, 162, 199, 73, 10, 75, 24]],
['eAmt0pClMyL8Sk69', 'JFzXjfJhEMUCYEDrBKRM9OFFK0PSX', [176, 167, 43, 60, 16, 69, 194, 2]],
['CTFnU2nwy9s1_kBj', 'hEHqR0idFTzbvG193aLYj6y2DFPi2UKQut_A--43PdN1XF', [6, 84, 156, 248, 125, 55, 230, 121]],
['CAhom0f872WEDXP6', 'dmX', [203, 98, 175, 172, 19, 3, 244, 177]],
['aON1dHrq90SbG8Hx', 'v7LyiwuCrB7EgAibPve6Yg2gLmggxE6j7ocR37EudrH_P9XX2rQK', [147, 73, 50, 63, 71, 98, 203, 42]]
]
test('crypto_shorthash', function (t) {
const out = Buffer.alloc(sodium.crypto_shorthash_BYTES)
const inp = Buffer.from('Hej, Verden!')
const key = Buffer.alloc(sodium.crypto_shorthash_KEYBYTES)
t.exception.all(function () {
sodium.crypto_shorthash(Buffer.alloc(0), inp)
}, 'throws on bad input')
sodium.crypto_shorthash(out, inp, key)
const result = '6a29984f782e684e'
t.alike(out.toString('hex'), result, 'hashed the string')
})
test('constants', function (assert) {
assert.ok(sodium.crypto_shorthash_PRIMITIVE)
assert.ok(sodium.crypto_shorthash_KEYBYTES > 0)
assert.ok(sodium.crypto_shorthash_BYTES > 0)
assert.end()
})
test('crypto_shorthash fixtures', function (assert) {
run(assert)
})
test('crypto_shorthash fixtures (wasm)', function (assert) {
if (!sodium.crypto_shorthash_WASM_SUPPORTED) {
assert.pass('wasm not supported')
assert.end()
return
}
assert.ok(sodium.crypto_shorthash_WASM_LOADED)
run(assert)
})
function run (assert) {
for (let i = 0; i < vectors.length; i++) {
const v = vectors[i]
const key = Buffer.from(v[0])
const message = Buffer.from(v[1])
const expected = Buffer.from(v[2])
const out = Buffer.alloc(sodium.crypto_shorthash_BYTES)
sodium.crypto_shorthash(out, message, key)
if (Buffer.compare(out, expected) !== 0) {
assert.fail('Failed on fixture #' + i)
assert.end()
return
}
}
assert.pass('Passed all fixtures')
assert.end()
}

334
test/crypto_sign.js Normal file
View File

@ -0,0 +1,334 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
const fixtures = require('./fixtures/crypto_sign.json')
test('crypto_sign_ed25519_sk_to_pk', function (t) {
const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES)
const pke = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES)
const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES)
sodium.crypto_sign_keypair(pk, sk)
sodium.crypto_sign_ed25519_sk_to_pk(pke, sk)
t.ok(pk.equals(pke))
})
test('crypto_sign_seed_keypair', function (t) {
const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES)
const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES)
const seed = Buffer.alloc(sodium.crypto_sign_SEEDBYTES, 'lo')
t.exception.all(function () {
sodium.crypto_sign_seed_keypair()
}, 'should validate input')
t.exception.all(function () {
sodium.crypto_sign_seed_keypair(Buffer.alloc(0), Buffer.alloc(0), Buffer.alloc(0))
}, 'should validate input length')
sodium.crypto_sign_seed_keypair(pk, sk, seed)
const eSk = '6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f41eb5b4dba29b19e391d9a4d1a4a879b27958ff3734e10cfbf1f46d68f4d3038'
const ePk = '41eb5b4dba29b19e391d9a4d1a4a879b27958ff3734e10cfbf1f46d68f4d3038'
t.alike(pk.toString('hex'), ePk, 'seeded public key')
t.alike(sk.toString('hex'), eSk, 'seeded secret key')
})
test('crypto_sign_keypair', function (t) {
const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES)
const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES)
sodium.crypto_sign_keypair(pk, sk)
t.not(pk, Buffer.alloc(pk.length), 'made public key')
t.not(sk, Buffer.alloc(sk.length), 'made secret key')
t.exception.all(function () {
sodium.crypto_sign_keypair()
}, 'should validate input')
t.exception.all(function () {
sodium.crypto_sign_keypair(Buffer.alloc(0), Buffer.alloc(0))
}, 'should validate input length')
})
test('crypto_sign', function (t) {
const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES)
const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES)
sodium.crypto_sign_keypair(pk, sk)
const message = Buffer.from('Hello, World!')
const signedMessage = Buffer.alloc(message.length + sodium.crypto_sign_BYTES)
sodium.crypto_sign(signedMessage, message, sk)
t.alike(signedMessage.slice(-message.length), message, 'contains message')
const output = Buffer.alloc(message.length)
t.absent(sodium.crypto_sign_open(output, Buffer.alloc(signedMessage.length), pk), 'was not signed')
t.ok(sodium.crypto_sign_open(output, signedMessage, pk), 'was signed')
t.alike(output, message, 'same message')
})
test('crypto_sign_detached', function (t) {
const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES)
const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES)
sodium.crypto_sign_keypair(pk, sk)
const message = Buffer.from('Hello, World!')
const signature = Buffer.alloc(sodium.crypto_sign_BYTES)
sodium.crypto_sign_detached(signature, message, sk)
t.absent(sodium.crypto_sign_verify_detached(Buffer.concat([Buffer.alloc(1), signature]), message, pk), 'was not signed')
t.ok(sodium.crypto_sign_verify_detached(signature, message, pk), 'was signed')
})
test('crypto_sign_open fixtures', function (t) {
for (let i = 0; i < fixtures.length; i++) {
const publicKey = new Uint8Array(fixtures[i][1])
const message = new Uint8Array(fixtures[i][3])
const signed = new Uint8Array([].concat(fixtures[i][2], fixtures[i][3]))
if (!sodium.crypto_sign_open(message, signed, publicKey)) {
t.fail('Failed on fixture #' + i)
t.end()
return
}
}
t.pass('Passed all fixtures')
t.end()
})
test('crypto_sign fixtures', function (t) {
const fixtures = require('./fixtures/crypto_sign.json')
for (let i = 0; i < fixtures.length; i++) {
const secretKey = new Uint8Array([].concat(fixtures[i][0], fixtures[i][1]))
const message = new Uint8Array(fixtures[i][3])
const expected = new Uint8Array([].concat(fixtures[i][2], fixtures[i][3]))
const actual = new Uint8Array(sodium.crypto_sign_BYTES + message.length)
sodium.crypto_sign(actual, message, secretKey)
if (Buffer.compare(actual, expected) !== 0) {
t.fail('Failed on fixture #' + i)
t.end()
return
}
}
t.pass('Passed all fixtures')
t.end()
})
test('crypto_sign_verify_detached fixtures', function (t) {
const fixtures = require('./fixtures/crypto_sign.json')
for (let i = 0; i < fixtures.length; i++) {
const publicKey = new Uint8Array(fixtures[i][1])
const message = new Uint8Array(fixtures[i][3])
const signature = new Uint8Array(fixtures[i][2])
if (!sodium.crypto_sign_verify_detached(signature, message, publicKey)) {
t.fail('Failed on fixture #' + i)
t.end()
return
}
}
t.pass('Passed all fixtures')
t.end()
})
test('crypto_sign_detached fixtures', function (t) {
const fixtures = require('./fixtures/crypto_sign.json')
for (let i = 0; i < fixtures.length; i++) {
const secretKey = new Uint8Array([].concat(fixtures[i][0], fixtures[i][1]))
const message = new Uint8Array(fixtures[i][3])
const expected = new Uint8Array(fixtures[i][2])
const actual = new Uint8Array(sodium.crypto_sign_BYTES)
sodium.crypto_sign_detached(actual, message, secretKey)
if (Buffer.compare(actual, expected) !== 0) {
t.fail('Failed on fixture #' + i)
t.end()
return
}
}
t.pass('Passed all fixtures')
t.end()
})
/* eslint-disable camelcase */
test('libsodium', function (t) {
const sig = new Uint8Array(sodium.crypto_sign_BYTES)
const sm = new Uint8Array(1024 + sodium.crypto_sign_BYTES)
const skpk = new Uint8Array(sodium.crypto_sign_SECRETKEYBYTES)
const pk = new Uint8Array(sodium.crypto_sign_PUBLICKEYBYTES)
const sk = new Uint8Array(sodium.crypto_sign_SECRETKEYBYTES)
let smlen
let i
let test
sig.fill(0)
let pass = true
for (i = 0; i < fixtures.length; i++) {
test = parseTest(fixtures[i])
skpk.set(test.sk)
skpk.set(test.pk, sodium.crypto_sign_SEEDBYTES)
smlen = sodium.crypto_sign_BYTES + test.m.byteLength
sodium.crypto_sign(sm.subarray(0, test.m.byteLength + sodium.crypto_sign_BYTES), test.m, skpk)
pass &= Buffer.compare(test.sig, sm.subarray(0, 64)) === 0
pass &= sodium.crypto_sign_open(test.m, sm.subarray(0, smlen), test.pk)
sodium.crypto_sign_detached(sig, test.m, skpk)
pass &= sig.byteLength !== 0 && sig.byteLength <= sodium.crypto_sign_BYTES
pass &= Buffer.compare(test.sig, sig) === 0
pass &= sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), test.pk)
if (!pass) t.fail('failed on fixture #' + i)
}
t.pass('passed all fixtures')
for (let j = 1; j < 8; j++) {
sig[63] ^= (j << 5)
t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), test.pk))
sig[63] ^= (j << 5)
}
pk.fill(0)
t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk))
sig.subarray(0, 32).fill(0xff)
sig[0] = 0xdb
t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk))
sodium.crypto_sign_detached(sig, test.m.subarray(0, i), skpk)
hex2bin(pk, '3eee494fb9eac773144e34b0c755affaf33ea782c0722e5ea8b150e61209ab36')
t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk))
hex2bin(pk, '0200000000000000000000000000000000000000000000000000000000000000')
t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk))
hex2bin(pk, '0500000000000000000000000000000000000000000000000000000000000000')
t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk))
const keypair_seed = new Uint8Array([
0x42, 0x11, 0x51, 0xa4, 0x59, 0xfa, 0xea, 0xde, 0x3d, 0x24, 0x71,
0x15, 0xf9, 0x4a, 0xed, 0xae, 0x42, 0x31, 0x81, 0x24, 0x09, 0x5a,
0xfa, 0xbe, 0x4d, 0x14, 0x51, 0xa5, 0x59, 0xfa, 0xed, 0xee
])
t.execution(() => sodium.crypto_sign_seed_keypair(pk, sk, keypair_seed))
t.execution(() => sodium.crypto_sign_keypair(pk, sk))
t.ok(sodium.crypto_sign_BYTES > 0)
t.ok(sodium.crypto_sign_SEEDBYTES > 0)
t.ok(sodium.crypto_sign_PUBLICKEYBYTES > 0)
t.ok(sodium.crypto_sign_SECRETKEYBYTES > 0)
t.is(sodium.crypto_sign_BYTES, 64)
t.is(sodium.crypto_sign_SEEDBYTES, 32)
t.is(sodium.crypto_sign_PUBLICKEYBYTES, 32)
t.is(sodium.crypto_sign_SECRETKEYBYTES, 64)
t.end()
})
test('ed25519 convert', function (t) {
const keypair_seed = new Uint8Array([
0x42, 0x11, 0x51, 0xa4, 0x59, 0xfa, 0xea, 0xde, 0x3d, 0x24, 0x71,
0x15, 0xf9, 0x4a, 0xed, 0xae, 0x42, 0x31, 0x81, 0x24, 0x09, 0x5a,
0xfa, 0xbe, 0x4d, 0x14, 0x51, 0xa5, 0x59, 0xfa, 0xed, 0xee
])
const ed25519_pk = new Uint8Array(sodium.crypto_sign_PUBLICKEYBYTES)
const ed25519_skpk = new Uint8Array(sodium.crypto_sign_SECRETKEYBYTES)
const curve25519_pk = new Uint8Array(sodium.crypto_scalarmult_BYTES)
const curve25519_pk2 = new Uint8Array(sodium.crypto_scalarmult_BYTES)
const curve25519_sk = new Uint8Array(sodium.crypto_scalarmult_BYTES)
t.ok(sodium.crypto_sign_SEEDBYTES <= sodium.crypto_hash_sha512_BYTES)
sodium.crypto_sign_seed_keypair(ed25519_pk, ed25519_skpk, keypair_seed)
sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk)
sodium.crypto_sign_ed25519_sk_to_curve25519(curve25519_sk, ed25519_skpk)
const expected_pk = new Uint8Array([
0xf1, 0x81, 0x4f, 0x0e, 0x8f, 0xf1, 0x04, 0x3d, 0x8a, 0x44, 0xd2, 0x5b,
0xab, 0xff, 0x3c, 0xed, 0xca, 0xe6, 0xc2, 0x2c, 0x3e, 0xda, 0xa4, 0x8f,
0x85, 0x7a, 0xe7, 0x0d, 0xe2, 0xba, 0xae, 0x50
])
const expected_sk = new Uint8Array([
0x80, 0x52, 0x03, 0x03, 0x76, 0xd4, 0x71, 0x12, 0xbe, 0x7f, 0x73, 0xed,
0x7a, 0x01, 0x92, 0x93, 0xdd, 0x12, 0xad, 0x91, 0x0b, 0x65, 0x44, 0x55,
0x79, 0x8b, 0x46, 0x67, 0xd7, 0x3d, 0xe1, 0x66
])
t.alike(curve25519_pk, expected_pk)
t.alike(curve25519_sk, expected_sk)
for (let i = 0; i < 500; i++) {
sodium.crypto_sign_keypair(ed25519_pk, ed25519_skpk)
sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk)
sodium.crypto_sign_ed25519_sk_to_curve25519(curve25519_sk, ed25519_skpk)
sodium.crypto_scalarmult_base(curve25519_pk2, curve25519_sk)
if (Buffer.compare(curve25519_pk, curve25519_pk2) !== 0) t.fail()
}
t.pass('passed all cases')
ed25519_pk.fill(0)
t.exception(() => {
sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk)
})
t.exception(() => {
ed25519_pk[0] = 2
sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk)
})
t.exception(() => {
ed25519_pk[0] = 5
sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk)
})
t.end()
})
function parseTest (t) {
return {
sk: new Uint8Array(t[0]),
pk: new Uint8Array(t[1]),
sig: new Uint8Array(t[2]),
m: new Uint8Array(t[3])
}
}
function hex2bin (buf, hex) {
for (let i = 0; i < hex.length / 2; i++) {
buf[i] = Number('0x' + hex.slice(2 * i, 2 * i + 1))
}
}

213
test/crypto_stream.js Normal file
View File

@ -0,0 +1,213 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('crypto_stream', function (t) {
const buf = Buffer.alloc(50)
const nonce = random(sodium.crypto_stream_NONCEBYTES)
const key = random(sodium.crypto_stream_KEYBYTES)
sodium.crypto_stream(buf, nonce, key)
t.not(buf, Buffer.alloc(50), 'contains noise now')
const copy = Buffer.from(buf.toString('hex'), 'hex')
sodium.crypto_stream(buf, nonce, key)
t.alike(buf, copy, 'predictable from nonce, key')
})
test('crypto_stream_xor', function (t) {
const message = Buffer.from('Hello, World!')
const nonce = random(sodium.crypto_stream_NONCEBYTES)
const key = random(sodium.crypto_stream_KEYBYTES)
sodium.crypto_stream_xor(message, message, nonce, key)
t.not(message, Buffer.from('Hello, World!'), 'encrypted')
sodium.crypto_stream_xor(message, message, nonce, key)
t.alike(message, Buffer.from('Hello, World!'), 'decrypted')
})
test.skip('crypto_stream_xor state', function (t) {
const message = Buffer.from('Hello, world!')
const nonce = random(sodium.crypto_stream_NONCEBYTES)
const key = random(sodium.crypto_stream_KEYBYTES)
const out = Buffer.alloc(message.length)
const state = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES)
sodium.crypto_stream_xor_init(state, nonce, key)
for (let i = 0; i < message.length; i++) {
sodium.crypto_stream_xor_update(state, out.slice(i, i + 1), message.slice(i, i + 1))
}
sodium.crypto_stream_xor_final(state)
sodium.crypto_stream_xor(out, out, nonce, key)
t.alike(out, message, 'decrypted')
})
test.skip('crypto_stream_xor state with empty buffers', function (t) {
const message = Buffer.from('Hello, world!')
const nonce = random(sodium.crypto_stream_NONCEBYTES)
const key = random(sodium.crypto_stream_KEYBYTES)
const out = Buffer.alloc(message.length)
const state = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES)
sodium.crypto_stream_xor_init(state, nonce, key)
sodium.crypto_stream_xor_update(state, Buffer.alloc(0), Buffer.alloc(0))
for (let i = 0; i < message.length; i++) {
sodium.crypto_stream_xor_update(state, out.slice(i, i + 1), message.slice(i, i + 1))
sodium.crypto_stream_xor_update(state, Buffer.alloc(0), Buffer.alloc(0))
}
sodium.crypto_stream_xor_final(state)
sodium.crypto_stream_xor(out, out, nonce, key)
t.alike(out, message, 'decrypted')
})
test.skip('crypto_stream_xor state long stream', function (t) {
const nonce = random(sodium.crypto_stream_NONCEBYTES)
const key = random(sodium.crypto_stream_KEYBYTES)
const encState = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES)
const decState = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES)
sodium.crypto_stream_xor_init(encState, nonce, key)
sodium.crypto_stream_xor_init(decState, nonce, key)
const plain = []
const encrypted = []
const decrypted = []
for (let i = 0; i < 1000; i++) {
const next = random(61)
plain.push(next)
const enc = Buffer.alloc(61)
sodium.crypto_stream_xor_update(encState, enc, next)
encrypted.push(enc)
const dec = Buffer.alloc(61)
sodium.crypto_stream_xor_update(decState, dec, enc)
decrypted.push(dec)
}
const enc2 = Buffer.alloc(1000 * 61)
sodium.crypto_stream_xor(enc2, Buffer.concat(plain), nonce, key)
t.alike(Buffer.concat(encrypted), enc2, 'same as encrypting all at once')
t.alike(Buffer.concat(decrypted), Buffer.concat(plain), 'decrypts')
})
test.skip('crypto_stream_xor state long stream (random chunks)', function (t) {
const nonce = random(sodium.crypto_stream_NONCEBYTES)
const key = random(sodium.crypto_stream_KEYBYTES)
const encState = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES)
const decState = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES)
sodium.crypto_stream_xor_init(encState, nonce, key)
sodium.crypto_stream_xor_init(decState, nonce, key)
const plain = []
const encrypted = []
const decrypted = []
for (let i = 0; i < 10000; i++) {
const len = Math.floor(Math.random() * 256)
const next = random(len)
plain.push(next)
const enc = Buffer.alloc(len)
sodium.crypto_stream_xor_update(encState, enc, next)
encrypted.push(enc)
const dec = Buffer.alloc(len)
sodium.crypto_stream_xor_update(decState, dec, enc)
decrypted.push(dec)
}
const enc2 = Buffer.alloc(Buffer.concat(plain).length)
sodium.crypto_stream_xor(enc2, Buffer.concat(plain), nonce, key)
t.alike(Buffer.concat(encrypted), enc2, 'same as encrypting all at once')
t.alike(Buffer.concat(decrypted), Buffer.concat(plain), 'decrypts')
})
test.skip('crypto_stream_xor state long stream (random chunks) with empty buffers', function (t) {
const nonce = random(sodium.crypto_stream_NONCEBYTES)
const key = random(sodium.crypto_stream_KEYBYTES)
const encState = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES)
const decState = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES)
sodium.crypto_stream_xor_init(encState, nonce, key)
sodium.crypto_stream_xor_init(decState, nonce, key)
const plain = []
const encrypted = []
const decrypted = []
for (let i = 0; i < 10000; i++) {
const len = Math.floor(Math.random() * 256)
const next = random(len)
plain.push(next)
sodium.crypto_stream_xor_update(encState, Buffer.alloc(0), Buffer.alloc(0))
const enc = Buffer.alloc(len)
sodium.crypto_stream_xor_update(encState, enc, next)
encrypted.push(enc)
const dec = Buffer.alloc(len)
sodium.crypto_stream_xor_update(decState, dec, enc)
decrypted.push(dec)
sodium.crypto_stream_xor_update(decState, Buffer.alloc(0), Buffer.alloc(0))
}
const enc2 = Buffer.alloc(Buffer.concat(plain).length)
sodium.crypto_stream_xor(enc2, Buffer.concat(plain), nonce, key)
t.alike(Buffer.concat(encrypted), enc2, 'same as encrypting all at once')
t.alike(Buffer.concat(decrypted), Buffer.concat(plain), 'decrypts')
})
test.skip('crypto_stream_xor state after GC', function (t) {
const message = Buffer.from('Hello, world!')
let nonce = random(sodium.crypto_stream_NONCEBYTES)
let key = random(sodium.crypto_stream_KEYBYTES)
const out = Buffer.alloc(message.length)
const state = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES)
sodium.crypto_stream_xor_init(state, nonce, key)
const nonceCopy = Buffer.from(nonce.toString('hex'), 'hex')
const keyCopy = Buffer.from(key.toString('hex'), 'hex')
nonce = null
key = null
forceGC()
for (let i = 0; i < message.length; i++) {
sodium.crypto_stream_xor_update(state, out.slice(i, i + 1), message.slice(i, i + 1))
}
sodium.crypto_stream_xor_final(state)
sodium.crypto_stream_xor(out, out, nonceCopy, keyCopy)
t.alike(out, message, 'decrypted')
})
function random (n) {
const buf = Buffer.alloc(n)
sodium.randombytes_buf(buf)
return buf
}
function forceGC () {
require('v8').setFlagsFromString('--expose-gc')
require('vm').runInNewContext('gc')()
}

View File

@ -0,0 +1,284 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
const tests = [
['0000000000000000000000000000000000000000000000000000000000000000', '0000000000000000', '76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee65869f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32ee7aed29b721769ce64e43d57133b074d839d531ed1f28510afb45ace10a1f4b794d6f2d09a0e663266ce1ae7ed1081968a0758e718e997bd362c6b0c34634a9a0b35d'],
['0000000000000000000000000000000000000000000000000000000000000001', '0000000000000000', '4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d792b1c43fea817e9ad275ae5469633aeb5224ecf849929b9d828db1ced4dd832025e8018b8160b82284f3c949aa5a8eca00bbb4a73bdad192b5c42f73f2fd4e273644c8b36125a64addeb006c13a096d68b9ff7b57e7090f880392effd5b297a83bbaf2fbe8cf5d4618965e3dc776'],
['0000000000000000000000000000000000000000000000000000000000000000', '0000000000000001', 'de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df137821031e85a050278a7084527214f73efc7fa5b5277062eb7a0433e445f41e31afab757283547e3d3d30ee0371c1e6025ff4c91b794a291cf7568d48ff84b37329e2730b12738a072a2b2c7169e326fe4893a7b2421bb910b79599a7ce4fbaee86be427c5ee0e8225eb6f48231fd504939d59eac8bd106cc138779b893c54da8758f62a'],
['0000000000000000000000000000000000000000000000000000000000000000', '0100000000000000', 'ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111e4caf237ee53ca8ad6426194a88545ddc497a0b466e7d6bbdb0041b2f586b5305e5e44aff19b235936144675efbe4409eb7e8e5f1430f5f5836aeb49bb5328b017c4b9dc11f8a03863fa803dc71d5726b2b6b31aa32708afe5af1d6b690584d58792b271e5fdb92c486051c48b79a4d48a109bb2d0477956e74c25e93c3c2'],
['000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', '0001020304050607', 'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5a97a5f576fe064025']
]
const vectors = [
'f7010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101',
'f798a189040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404',
'f798a189f195e6070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707',
'f798a189f195e66982100a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a',
'f798a189f195e66982105ffb640d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d',
'f798a189f195e66982105ffb640bb775101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010',
'f798a189f195e66982105ffb640bb7757f579d131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313',
'f798a189f195e66982105ffb640bb7757f579da31602161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac561c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac31f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b73252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b4641282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c92b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c94400492e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f159163a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f15916155c2b3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d',
'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f15916155c2be8241a404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040'
]
test('constants', function (t) {
t.ok(sodium.crypto_stream_chacha20_KEYBYTES > 0)
t.ok(sodium.crypto_stream_chacha20_NONCEBYTES > 0)
t.ok(sodium.crypto_stream_chacha20_MESSAGEBYTES_MAX > 0)
})
test('libsodium crypto_stream_chacha20', function (t) {
const key = Buffer.alloc(sodium.crypto_stream_chacha20_KEYBYTES)
const nonce = Buffer.alloc(sodium.crypto_stream_chacha20_NONCEBYTES)
const out = Buffer.alloc(160)
for (let i = 0; i < tests.length; i++) {
key.write(tests[i][0], 0, key.byteLength, 'hex')
nonce.write(tests[i][1], 0, nonce.byteLength, 'hex')
sodium.crypto_stream_chacha20(out, nonce, key)
t.alike(out, Buffer.from(tests[i][2], 'hex'))
for (let plen = 0; plen < out.byteLength; plen++) {
const part = Buffer.alloc(plen)
sodium.crypto_stream_chacha20_xor(part, out.subarray(0, plen), nonce, key)
if (part.every(b => b === 0) === false) return t.fail()
}
}
for (let plen = 1, i = 0; plen < 66; plen += 3, i++) {
out.fill(plen & 0xff)
sodium.crypto_stream_chacha20(out.subarray(0, plen), nonce, key)
if (out.equals(Buffer.from(vectors[i], 'hex')) === false) return t.fail()
}
sodium.randombytes_buf(out)
sodium.crypto_stream_chacha20(out, nonce, key)
t.alike(out, Buffer.from('f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5a97a5f576fe064025', 'hex'))
t.execution(() => sodium.crypto_stream_chacha20(out.subarray(0, 0), nonce, key))
t.execution(() => sodium.crypto_stream_chacha20_xor(out.subarray(0, 0), Buffer.alloc(0), nonce, key))
t.execution(() => sodium.crypto_stream_chacha20_xor(out.subarray(0, 0), Buffer.alloc(0), nonce, key))
t.execution(() => sodium.crypto_stream_chacha20_xor_ic(out.subarray(0, 0), Buffer.alloc(0), nonce, 1, key))
out.fill(0x42)
sodium.crypto_stream_chacha20_xor(out, out, nonce, key)
t.alike(out, Buffer.from('b5dae3cbb3d7a42bc0521db92649f5373d15dfe15440bed1ae43ee14ba18818376e616393179040372008b06420b552b4791fc1ba85e11b31b54571e69aa66587a42c9d864fe77d65c6606553ec89c24cb9cd7640bc49b1acbb922aa046b8bffd818895e835afc147cfbf1e6e630ba6c4be5a53a0b69146cb5514cca9da27385dffb96b585eadb5759d8051270f47d81c7661da216a19f18d5e7b734bc440267', 'hex'))
sodium.crypto_stream_chacha20_xor_ic(out, out, nonce, 0, key)
t.alike(out, Buffer.from('42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242', 'hex'))
sodium.crypto_stream_chacha20_xor_ic(out, out, nonce, 1, key)
t.alike(out, Buffer.from('7a42c9d864fe77d65c6606553ec89c24cb9cd7640bc49b1acbb922aa046b8bffd818895e835afc147cfbf1e6e630ba6c4be5a53a0b69146cb5514cca9da27385dffb96b585eadb5759d8051270f47d81c7661da216a19f18d5e7b734bc440267918c466e1428f08745f37a99c77c7f2b1b244bd4162e8b86e4a8bf85358202954ced04b52fef7b3ba787744e715554285ecb0ed6e133c528d69d346abc0ce8b0', 'hex'))
})
test('crypto_stream_chacha20', function (t) {
const buf = Buffer.alloc(50)
const nonce = random(sodium.crypto_stream_chacha20_NONCEBYTES)
const key = random(sodium.crypto_stream_chacha20_KEYBYTES)
sodium.crypto_stream_chacha20(buf, nonce, key)
t.unlike(buf, Buffer.alloc(50), 'contains noise now')
const copy = Buffer.from(buf.toString('hex'), 'hex')
sodium.crypto_stream_chacha20(buf, nonce, key)
t.alike(buf, copy, 'predictable from nonce, key')
t.end()
})
test.skip('crypto_stream_chacha20_xor state', function (t) {
const message = Buffer.from('Hello, world!')
const nonce = random(sodium.crypto_stream_chacha20_NONCEBYTES)
const key = random(sodium.crypto_stream_chacha20_KEYBYTES)
const out = Buffer.alloc(message.length)
const state = Buffer.alloc(sodium.crypto_stream_chacha20_xor_STATEBYTES)
sodium.crypto_stream_chacha20_xor_init(state, nonce, key)
for (let i = 0; i < message.length; i++) {
sodium.crypto_stream_chacha20_xor_update(state, out.slice(i, i + 1), message.slice(i, i + 1))
}
sodium.crypto_stream_chacha20_xor_final(state)
sodium.crypto_stream_chacha20_xor(out, out, nonce, key)
t.alike(out, message, 'decrypted')
})
test.skip('crypto_stream_chacha20_xor state with empty buffers', function (t) {
const message = Buffer.from('Hello, world!')
const nonce = random(sodium.crypto_stream_chacha20_NONCEBYTES)
const key = random(sodium.crypto_stream_chacha20_KEYBYTES)
const out = Buffer.alloc(message.length)
const state = Buffer.alloc(sodium.crypto_stream_chacha20_xor_STATEBYTES)
sodium.crypto_stream_chacha20_xor_init(state, nonce, key)
sodium.crypto_stream_chacha20_xor_update(state, Buffer.alloc(0), Buffer.alloc(0))
for (let i = 0; i < message.length; i++) {
sodium.crypto_stream_chacha20_xor_update(state, out.slice(i, i + 1), message.slice(i, i + 1))
sodium.crypto_stream_chacha20_xor_update(state, Buffer.alloc(0), Buffer.alloc(0))
}
sodium.crypto_stream_chacha20_xor_final(state)
sodium.crypto_stream_chacha20_xor(out, out, nonce, key)
t.alike(out, message, 'decrypted')
})
test.skip('crypto_stream_chacha20_xor state long stream', function (t) {
const nonce = random(sodium.crypto_stream_chacha20_NONCEBYTES)
const key = random(sodium.crypto_stream_chacha20_KEYBYTES)
const encState = Buffer.alloc(sodium.crypto_stream_chacha20_xor_STATEBYTES)
const decState = Buffer.alloc(sodium.crypto_stream_chacha20_xor_STATEBYTES)
sodium.crypto_stream_chacha20_xor_init(encState, nonce, key)
sodium.crypto_stream_chacha20_xor_init(decState, nonce, key)
const plain = []
const encrypted = []
const decrypted = []
for (let i = 0; i < 1000; i++) {
const next = random(61)
plain.push(next)
const enc = Buffer.alloc(61)
sodium.crypto_stream_chacha20_xor_update(encState, enc, next)
encrypted.push(enc)
const dec = Buffer.alloc(61)
sodium.crypto_stream_chacha20_xor_update(decState, dec, enc)
decrypted.push(dec)
}
const enc2 = Buffer.alloc(1000 * 61)
sodium.crypto_stream_chacha20_xor(enc2, Buffer.concat(plain), nonce, key)
t.alike(Buffer.concat(encrypted), enc2, 'same as encrypting all at once')
t.alike(Buffer.concat(decrypted), Buffer.concat(plain), 'decrypts')
})
test.skip('crypto_stream_chacha20_xor state long stream (random chunks)', function (t) {
const nonce = random(sodium.crypto_stream_chacha20_NONCEBYTES)
const key = random(sodium.crypto_stream_chacha20_KEYBYTES)
const encState = Buffer.alloc(sodium.crypto_stream_chacha20_xor_STATEBYTES)
const decState = Buffer.alloc(sodium.crypto_stream_chacha20_xor_STATEBYTES)
sodium.crypto_stream_chacha20_xor_init(encState, nonce, key)
sodium.crypto_stream_chacha20_xor_init(decState, nonce, key)
const plain = []
const encrypted = []
const decrypted = []
for (let i = 0; i < 10000; i++) {
const len = Math.floor(Math.random() * 256)
const next = random(len)
plain.push(next)
const enc = Buffer.alloc(len)
sodium.crypto_stream_chacha20_xor_update(encState, enc, next)
encrypted.push(enc)
const dec = Buffer.alloc(len)
sodium.crypto_stream_chacha20_xor_update(decState, dec, enc)
decrypted.push(dec)
}
const enc2 = Buffer.alloc(Buffer.concat(plain).length)
sodium.crypto_stream_chacha20_xor(enc2, Buffer.concat(plain), nonce, key)
t.alike(Buffer.concat(encrypted), enc2, 'same as encrypting all at once')
t.alike(Buffer.concat(decrypted), Buffer.concat(plain), 'decrypts')
})
test.skip('crypto_stream_chacha20_xor state long stream (random chunks) with empty buffers', function (t) {
const nonce = random(sodium.crypto_stream_chacha20_NONCEBYTES)
const key = random(sodium.crypto_stream_chacha20_KEYBYTES)
const encState = Buffer.alloc(sodium.crypto_stream_chacha20_xor_STATEBYTES)
const decState = Buffer.alloc(sodium.crypto_stream_chacha20_xor_STATEBYTES)
sodium.crypto_stream_chacha20_xor_init(encState, nonce, key)
sodium.crypto_stream_chacha20_xor_init(decState, nonce, key)
const plain = []
const encrypted = []
const decrypted = []
for (let i = 0; i < 10000; i++) {
const len = Math.floor(Math.random() * 256)
const next = random(len)
plain.push(next)
sodium.crypto_stream_chacha20_xor_update(encState, Buffer.alloc(0), Buffer.alloc(0))
const enc = Buffer.alloc(len)
sodium.crypto_stream_chacha20_xor_update(encState, enc, next)
encrypted.push(enc)
const dec = Buffer.alloc(len)
sodium.crypto_stream_chacha20_xor_update(decState, dec, enc)
decrypted.push(dec)
sodium.crypto_stream_chacha20_xor_update(decState, Buffer.alloc(0), Buffer.alloc(0))
}
const enc2 = Buffer.alloc(Buffer.concat(plain).length)
sodium.crypto_stream_chacha20_xor(enc2, Buffer.concat(plain), nonce, key)
t.alike(Buffer.concat(encrypted), enc2, 'same as encrypting all at once')
t.alike(Buffer.concat(decrypted), Buffer.concat(plain), 'decrypts')
})
test.skip('crypto_stream_chacha20_xor state after GC', function (t) {
const message = Buffer.from('Hello, world!')
let nonce = random(sodium.crypto_stream_chacha20_NONCEBYTES)
let key = random(sodium.crypto_stream_chacha20_KEYBYTES)
const out = Buffer.alloc(message.length)
const state = Buffer.alloc(sodium.crypto_stream_chacha20_xor_STATEBYTES)
sodium.crypto_stream_chacha20_xor_init(state, nonce, key)
const nonceCopy = Buffer.from(nonce.toString('hex'), 'hex')
const keyCopy = Buffer.from(key.toString('hex'), 'hex')
nonce = null
key = null
forceGC()
for (let i = 0; i < message.length; i++) {
sodium.crypto_stream_chacha20_xor_update(state, out.slice(i, i + 1), message.slice(i, i + 1))
}
sodium.crypto_stream_chacha20_xor_final(state)
sodium.crypto_stream_chacha20_xor(out, out, nonceCopy, keyCopy)
t.alike(out, message, 'decrypted')
})
function random (n) {
const buf = Buffer.alloc(n)
sodium.randombytes_buf(buf)
return buf
}
function forceGC () {
require('v8').setFlagsFromString('--expose-gc')
require('vm').runInNewContext('gc')()
}

View File

@ -0,0 +1,303 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
const tests = [
['0000000000000000000000000000000000000000000000000000000000000000', '000000000000000000000000', 0, '76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee65869f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32ee7aed29b721769ce64e43d57133b074d839d531ed1f28510afb45ace10a1f4b794d6f2d09a0e663266ce1ae7ed1081968a0758e718e997bd362c6b0c34634a9a0b35d'],
['0000000000000000000000000000000000000000000000000000000000000000', '000000000000000000000000', 1, '9f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32ee7aed29b721769ce64e43d57133b074d839d531ed1f28510afb45ace10a1f4b794d6f2d09a0e663266ce1ae7ed1081968a0758e718e997bd362c6b0c34634a9a0b35d012737681f7b5d0f281e3afde458bc1e73d2d313c9cf94c05ff3716240a248f21320a058d7b3566bd520daaa3ed2bf0ac5b8b120fb852773c3639734b45c91a4'],
['0000000000000000000000000000000000000000000000000000000000000001', '000000000000000000000000', 1, '3aeb5224ecf849929b9d828db1ced4dd832025e8018b8160b82284f3c949aa5a8eca00bbb4a73bdad192b5c42f73f2fd4e273644c8b36125a64addeb006c13a096d68b9ff7b57e7090f880392effd5b297a83bbaf2fbe8cf5d4618965e3dc776cd430d9b4e7eda8a767fb0e860319aadb5fd96a855de1fbfc92cb0489190cfdd87da6dbf1f736a2d499941ca097e5170bd685578611323120cebf296181ed4f5'],
['00ff000000000000000000000000000000000000000000000000000000000000', '000000000000000000000000', 2, '72d54dfbf12ec44b362692df94137f328fea8da73990265ec1bbbea1ae9af0ca13b25aa26cb4a648cb9b9d1be65b2c0924a66c54d545ec1b7374f4872e99f096bf74dbd52cc4fc95ceb6097fe5e65358c9dbc0a5ecbf7894a132a9a54ae3e951f2e9f209aa9c3d9a877ac9dab62433d2961a17d103e455dfb7337c90f6857aad233065955a212b5c7a8eab4dc8a629e5b6b8ba914afd06de7177054b33d21c96'],
['0000000000000000000000000000000000000000000000000000000000000000', '000000000000000000000002', 0, 'c2c64d378cd536374ae204b9ef933fcd1a8b2288b3dfa49672ab765b54ee27c78a970e0e955c14f3a88e741b97c286f75f8fc299e8148362fa198a39531bed6d1a91288c874ec254f322c2a197340c55bb3e9b3998f7de2309486a0bb494abd20c9c5ef99c1370d61e77f408ac5514f49202bcc6828d45409d2d1416f8ae106b06ebd2541256264fa415bd54cb12e1d4449ed85299a1b7a249b75ff6c89b2e3f'],
['000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', '000000090000004a00000000', 1, '10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4ed2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e0a88837739d7bf4ef8ccacb0ea2bb9d69d56c394aa351dfda5bf459f0a2e9fe8e721f89255f9c486bf21679c683d4f9c5cf2fa27865526005b06ca374c86af3bdcbfbdcb83be65862ed5c20eae5a43241d6a92da6dca9a156be25297f51c2718'],
['000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', '000000090000004a00000000', 0xfeffffff, '75924bad7831b25662dbac54b46827990b6168ae990e7bd7e1fd2ad282bf23ef052c7d1a0a6c1ef862070943a0d4da24705fbc006dfb85e2af18c0a264d772a44c70fbedac9d6a6867ff6be0a32826507f2c784101583211c9e2453d4cc8b283d5e86682bd4bf511271b91dbd351415f5a009d1f78b64085a9a4341be7d42e2679d57e2747097f0129950e2c9e9ca1356022d45da252af71ac37f351a2e77911']
]
const vectors = [
'8a010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101',
'8adc91fd040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404',
'8adc91fd9ff4f0070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707',
'8adc91fd9ff4f0f51b0f0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a',
'8adc91fd9ff4f0f51b0fad50ff0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d',
'8adc91fd9ff4f0f51b0fad50ff15d637101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efd131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a742001c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a74200503c151f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a74200503c1582cd98222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a74200503c1582cd9833367d252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525252525',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a74200503c1582cd9833367d0a54d5282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a74200503c1582cd9833367d0a54d57d3c9e2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a74200503c1582cd9833367d0a54d57d3c9e998f492e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a74200503c1582cd9833367d0a54d57d3c9e998f490ee69c313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131313131',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a74200503c1582cd9833367d0a54d57d3c9e998f490ee69ca34c1f343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a74200503c1582cd9833367d0a54d57d3c9e998f490ee69ca34c1ff9e939373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a74200503c1582cd9833367d0a54d57d3c9e998f490ee69ca34c1ff9e939a755843a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a74200503c1582cd9833367d0a54d57d3c9e998f490ee69ca34c1ff9e939a75584c52d693d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d',
'8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a74200503c1582cd9833367d0a54d57d3c9e998f490ee69ca34c1ff9e939a75584c52d690a35d4404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040'
]
test('constants', function (t) {
t.ok(sodium.crypto_stream_chacha20_ietf_KEYBYTES > 0)
t.ok(sodium.crypto_stream_chacha20_ietf_NONCEBYTES > 0)
t.ok(sodium.crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX > 0)
})
test('libsodium crypto_stream_chacha20_ietf', function (t) {
const key = Buffer.alloc(sodium.crypto_stream_chacha20_ietf_KEYBYTES)
const nonce = Buffer.alloc(sodium.crypto_stream_chacha20_ietf_NONCEBYTES)
const out = Buffer.alloc(160)
for (let i = 0; i < tests.length; i++) {
key.write(tests[i][0], 0, key.byteLength, 'hex')
nonce.write(tests[i][1], 0, nonce.byteLength, 'hex')
out.fill(0)
sodium.crypto_stream_chacha20_ietf_xor_ic(out, out, nonce, tests[i][2], key)
t.alike(out, Buffer.from(tests[i][3], 'hex'), 'crypto_stream_chacha20_ietf_xor_ic vector ' + i)
for (let plen = 0; plen < out.byteLength; plen++) {
const part = Buffer.alloc(plen)
sodium.crypto_stream_chacha20_ietf_xor_ic(part, out.subarray(0, plen), nonce, tests[i][2], key)
if (part.every(b => b === 0) === false) return t.fail()
}
}
for (let plen = 1, i = 0; plen < 66; plen += 3, i++) {
out.fill(plen & 0xff)
sodium.crypto_stream_chacha20_ietf(out.subarray(0, plen), nonce, key)
if (out.equals(Buffer.from(vectors[i], 'hex')) === false) return t.fail()
}
sodium.randombytes_buf(out)
sodium.crypto_stream_chacha20_ietf(out, nonce, key)
t.alike(out, Buffer.from('8adc91fd9ff4f0f51b0fad50ff15d637e40efda206cc52c783a74200503c1582cd9833367d0a54d57d3c9e998f490ee69ca34c1ff9e939a75584c52d690a35d410f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4ed2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e0a88837739d7bf4ef8ccacb0ea2bb9d69d56c394aa351dfda5bf459f0a2e9fe8', 'hex'))
t.execution(() => sodium.crypto_stream_chacha20_ietf(out.subarray(0, 0), nonce, key))
t.execution(() => sodium.crypto_stream_chacha20_ietf_xor(out.subarray(0, 0), Buffer.alloc(0), nonce, key))
t.execution(() => sodium.crypto_stream_chacha20_ietf_xor(out.subarray(0, 0), Buffer.alloc(0), nonce, key))
t.execution(() => sodium.crypto_stream_chacha20_ietf_xor_ic(out.subarray(0, 0), Buffer.alloc(0), nonce, 1, key))
out.fill(0x42)
sodium.crypto_stream_chacha20_ietf_xor(out, out, nonce, key)
t.alike(out, Buffer.from('c89ed3bfddb6b2b7594def12bd579475a64cbfe0448e1085c1e50042127e57c08fda71743f4816973f7edcdbcd0b4ca4dee10e5dbbab7be517c6876f2b48779652b3a5a693791b57124d9f5de16233868593b68571822a414660e8d881962e0c90c0260445dde84b568095479bc940e0f750de939c540cfb8992c1aae0127e0c48cac1357b95fd0cba8eeef2a869fb94df1481d6e8775fbfe7fd07dd486cddaa', 'hex'))
sodium.crypto_stream_chacha20_ietf_xor_ic(out, out, nonce, 0, key)
t.alike(out, Buffer.from('42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242', 'hex'))
sodium.crypto_stream_chacha20_ietf_xor_ic(out, out, nonce, 1, key)
t.alike(out, Buffer.from('52b3a5a693791b57124d9f5de16233868593b68571822a414660e8d881962e0c90c0260445dde84b568095479bc940e0f750de939c540cfb8992c1aae0127e0c48cac1357b95fd0cba8eeef2a869fb94df1481d6e8775fbfe7fd07dd486cddaaa563bad017bb86c4fd6325de2a7f0dde1eb0b865c4176442194488750ec4ed799efdff89c1fc27c46c97804cec1801665f28d0982f88d85729a010d5b75e655a', 'hex'))
})
test('crypto_stream_chacha20_ietf', function (t) {
const buf = Buffer.alloc(50)
const nonce = random(sodium.crypto_stream_chacha20_ietf_NONCEBYTES)
const key = random(sodium.crypto_stream_chacha20_ietf_KEYBYTES)
sodium.crypto_stream_chacha20_ietf(buf, nonce, key)
t.unlike(buf, Buffer.alloc(50), 'contains noise now')
const copy = Buffer.from(buf.toString('hex'), 'hex')
sodium.crypto_stream_chacha20_ietf(buf, nonce, key)
t.alike(buf, copy, 'predictable from nonce, key')
t.end()
})
test('crypto_stream_chacha20_ietf_xor', function (t) {
const message = Buffer.from('Hello, World!')
const nonce = random(sodium.crypto_stream_chacha20_ietf_NONCEBYTES)
const key = random(sodium.crypto_stream_chacha20_ietf_KEYBYTES)
sodium.crypto_stream_chacha20_ietf_xor(message, message, nonce, key)
t.unlike(message, Buffer.from('Hello, World!'), 'encrypted')
sodium.crypto_stream_chacha20_ietf_xor(message, message, nonce, key)
t.alike(message, Buffer.from('Hello, World!'), 'decrypted')
t.end()
})
test.skip('crypto_stream_chacha20_ietf_xor state', function (t) {
const message = Buffer.from('Hello, world!')
const nonce = random(sodium.crypto_stream_chacha20_ietf_NONCEBYTES)
const key = random(sodium.crypto_stream_chacha20_ietf_KEYBYTES)
const out = Buffer.alloc(message.length)
const state = Buffer.alloc(sodium.crypto_stream_chacha20_ietf_xor_STATEBYTES)
sodium.crypto_stream_chacha20_ietf_xor_init(state, nonce, key)
for (let i = 0; i < message.length; i++) {
sodium.crypto_stream_chacha20_ietf_xor_update(state, out.slice(i, i + 1), message.slice(i, i + 1))
}
sodium.crypto_stream_chacha20_ietf_xor_final(state)
sodium.crypto_stream_chacha20_ietf_xor(out, out, nonce, key)
t.alike(out, message, 'decrypted')
})
test.skip('crypto_stream_chacha20_ietf_xor state with empty buffers', function (t) {
const message = Buffer.from('Hello, world!')
const nonce = random(sodium.crypto_stream_chacha20_ietf_NONCEBYTES)
const key = random(sodium.crypto_stream_chacha20_ietf_KEYBYTES)
const out = Buffer.alloc(message.length)
const state = Buffer.alloc(sodium.crypto_stream_chacha20_ietf_xor_STATEBYTES)
sodium.crypto_stream_chacha20_ietf_xor_init(state, nonce, key)
sodium.crypto_stream_chacha20_ietf_xor_update(state, Buffer.alloc(0), Buffer.alloc(0))
for (let i = 0; i < message.length; i++) {
sodium.crypto_stream_chacha20_ietf_xor_update(state, out.slice(i, i + 1), message.slice(i, i + 1))
sodium.crypto_stream_chacha20_ietf_xor_update(state, Buffer.alloc(0), Buffer.alloc(0))
}
sodium.crypto_stream_chacha20_ietf_xor_final(state)
sodium.crypto_stream_chacha20_ietf_xor(out, out, nonce, key)
t.alike(out, message, 'decrypted')
})
test.skip('crypto_stream_chacha20_ietf_xor state long stream', function (t) {
const nonce = random(sodium.crypto_stream_chacha20_ietf_NONCEBYTES)
const key = random(sodium.crypto_stream_chacha20_ietf_KEYBYTES)
const encState = Buffer.alloc(sodium.crypto_stream_chacha20_ietf_xor_STATEBYTES)
const decState = Buffer.alloc(sodium.crypto_stream_chacha20_ietf_xor_STATEBYTES)
sodium.crypto_stream_chacha20_ietf_xor_init(encState, nonce, key)
sodium.crypto_stream_chacha20_ietf_xor_init(decState, nonce, key)
const plain = []
const encrypted = []
const decrypted = []
for (let i = 0; i < 1000; i++) {
const next = random(61)
plain.push(next)
const enc = Buffer.alloc(61)
sodium.crypto_stream_chacha20_ietf_xor_update(encState, enc, next)
encrypted.push(enc)
const dec = Buffer.alloc(61)
sodium.crypto_stream_chacha20_ietf_xor_update(decState, dec, enc)
decrypted.push(dec)
}
const enc2 = Buffer.alloc(1000 * 61)
sodium.crypto_stream_chacha20_ietf_xor(enc2, Buffer.concat(plain), nonce, key)
t.alike(Buffer.concat(encrypted), enc2, 'same as encrypting all at once')
t.alike(Buffer.concat(decrypted), Buffer.concat(plain), 'decrypts')
})
test.skip('crypto_stream_chacha20_ietf_xor state long stream (random chunks)', function (t) {
const nonce = random(sodium.crypto_stream_chacha20_ietf_NONCEBYTES)
const key = random(sodium.crypto_stream_chacha20_ietf_KEYBYTES)
const encState = Buffer.alloc(sodium.crypto_stream_chacha20_ietf_xor_STATEBYTES)
const decState = Buffer.alloc(sodium.crypto_stream_chacha20_ietf_xor_STATEBYTES)
sodium.crypto_stream_chacha20_ietf_xor_init(encState, nonce, key)
sodium.crypto_stream_chacha20_ietf_xor_init(decState, nonce, key)
const plain = []
const encrypted = []
const decrypted = []
for (let i = 0; i < 10000; i++) {
const len = Math.floor(Math.random() * 256)
const next = random(len)
plain.push(next)
const enc = Buffer.alloc(len)
sodium.crypto_stream_chacha20_ietf_xor_update(encState, enc, next)
encrypted.push(enc)
const dec = Buffer.alloc(len)
sodium.crypto_stream_chacha20_ietf_xor_update(decState, dec, enc)
decrypted.push(dec)
}
const enc2 = Buffer.alloc(Buffer.concat(plain).length)
sodium.crypto_stream_chacha20_ietf_xor(enc2, Buffer.concat(plain), nonce, key)
t.alike(Buffer.concat(encrypted), enc2, 'same as encrypting all at once')
t.alike(Buffer.concat(decrypted), Buffer.concat(plain), 'decrypts')
})
test.skip('crypto_stream_chacha20_ietf_xor state long stream (random chunks) with empty buffers', function (t) {
const nonce = random(sodium.crypto_stream_chacha20_ietf_NONCEBYTES)
const key = random(sodium.crypto_stream_chacha20_ietf_KEYBYTES)
const encState = Buffer.alloc(sodium.crypto_stream_chacha20_ietf_xor_STATEBYTES)
const decState = Buffer.alloc(sodium.crypto_stream_chacha20_ietf_xor_STATEBYTES)
sodium.crypto_stream_chacha20_ietf_xor_init(encState, nonce, key)
sodium.crypto_stream_chacha20_ietf_xor_init(decState, nonce, key)
const plain = []
const encrypted = []
const decrypted = []
for (let i = 0; i < 10000; i++) {
const len = Math.floor(Math.random() * 256)
const next = random(len)
plain.push(next)
sodium.crypto_stream_chacha20_ietf_xor_update(encState, Buffer.alloc(0), Buffer.alloc(0))
const enc = Buffer.alloc(len)
sodium.crypto_stream_chacha20_ietf_xor_update(encState, enc, next)
encrypted.push(enc)
const dec = Buffer.alloc(len)
sodium.crypto_stream_chacha20_ietf_xor_update(decState, dec, enc)
decrypted.push(dec)
sodium.crypto_stream_chacha20_ietf_xor_update(decState, Buffer.alloc(0), Buffer.alloc(0))
}
const enc2 = Buffer.alloc(Buffer.concat(plain).length)
sodium.crypto_stream_chacha20_ietf_xor(enc2, Buffer.concat(plain), nonce, key)
t.alike(Buffer.concat(encrypted), enc2, 'same as encrypting all at once')
t.alike(Buffer.concat(decrypted), Buffer.concat(plain), 'decrypts')
})
test.skip('crypto_stream_chacha20_xor state after GC', function (t) {
const message = Buffer.from('Hello, world!')
let nonce = random(sodium.crypto_stream_chacha20_ietf_NONCEBYTES)
let key = random(sodium.crypto_stream_chacha20_ietf_KEYBYTES)
const out = Buffer.alloc(message.length)
const state = Buffer.alloc(sodium.crypto_stream_chacha20_ietf_xor_STATEBYTES)
sodium.crypto_stream_chacha20_ietf_xor_init(state, nonce, key)
const nonceCopy = Buffer.from(nonce.toString('hex'), 'hex')
const keyCopy = Buffer.from(key.toString('hex'), 'hex')
nonce = null
key = null
forceGC()
for (let i = 0; i < message.length; i++) {
sodium.crypto_stream_chacha20_ietf_xor_update(state, out.slice(i, i + 1), message.slice(i, i + 1))
}
sodium.crypto_stream_chacha20_ietf_xor_final(state)
sodium.crypto_stream_chacha20_ietf_xor(out, out, nonceCopy, keyCopy)
t.alike(out, message, 'decrypted')
})
function random (n) {
const buf = Buffer.alloc(n)
sodium.randombytes_buf(buf)
return buf
}
function forceGC () {
require('v8').setFlagsFromString('--expose-gc')
require('vm').runInNewContext('gc')()
}

78
test/fixtures/crypto_kdf.json vendored Normal file
View File

@ -0,0 +1,78 @@
[
{"error": false, "id":0, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"a0c724404728c8bb95e5433eb6a9716171144d61efb23e74b873fcbeda51d8071b5d70aae12066dfc94ce943f145aa176c055040c3dd73b0a15e36254d450614"},
{"error": false, "id":1, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"02507f144fa9bf19010bf7c70b235b4c2663cc00e074f929602a5e2c10a780757d2a3993d06debc378a90efdac196dd841817b977d67b786804f6d3cd585bab5"},
{"error": false, "id":2, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"1944da61ff18dc2028c3578ac85be904931b83860896598f62468f1cb5471c6a344c945dbc62c9aaf70feb62472d17775ea5db6ed5494c68b7a9a59761f39614"},
{"error": false, "id":3, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"131c0ca1633ed074986215b264f6e0474f362c52b029effc7b0f75977ee89cc95d85c3db87f7e399197a25411592beeeb7e5128a74646a460ecd6deb4994b71e"},
{"error": false, "id":4, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"a7023a0bf9be245d078aed26bcde0465ff0cc0961196a5482a0ff4ff8b4015971e13611f50529cb408f5776b14a90e7c3dd9160a22211db64ff4b5c0b9953680"},
{"error": false, "id":5, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"50f49313f3a05b2e565c13feedb44daa675cafd42c2b2cf9edbce9c949fbfc3f175dcb738671509ae2ea66fb85e552394d479afa7fa3affe8791744796b94176"},
{"error": false, "id":6, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"13b58d6d69780089293862cd59a1a8a4ef79bb850e3f3ba41fb22446a7dd1dc4da4667d37b33bf1225dcf8173c4c349a5d911c5bd2db9c5905ed70c11e809e3b"},
{"error": false, "id":7, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"15d44b4b44ffa006eeceeb508c98a970aaa573d65905687b9e15854dec6d49c612757e149f78268f727660dedf9abce22a9691feb20a01b0525f4b47a3cf19db"},
{"error": false, "id":8, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"9aebba11c5428ae8225716369e30a48943be39159a899f804e9963ef78822e186c21fe95bb0b85e60ef03a6f58d0b9d06e91f79d0ab998450b8810c73ca935b4"},
{"error": false, "id":9, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"70f9b83e463fb441e7a4c43275125cd5b19d8e2e4a5d179a39f5db10bbce745a199104563d308cf8d4c6b27bbb759ded232f5bdb7c367dd632a9677320dfe416"},
{"error": true, "id":0, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":0, "subkey":null},
{"error": true, "id":1, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":1, "subkey":null},
{"error": true, "id":2, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":2, "subkey":null},
{"error": true, "id":3, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":3, "subkey":null},
{"error": true, "id":4, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":4, "subkey":null},
{"error": true, "id":5, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":5, "subkey":null},
{"error": true, "id":6, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":6, "subkey":null},
{"error": true, "id":7, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":7, "subkey":null},
{"error": true, "id":8, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":8, "subkey":null},
{"error": true, "id":9, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":9, "subkey":null},
{"error": true, "id":10, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":10, "subkey":null},
{"error": true, "id":11, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":11, "subkey":null},
{"error": true, "id":12, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":12, "subkey":null},
{"error": true, "id":13, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":13, "subkey":null},
{"error": true, "id":14, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":14, "subkey":null},
{"error": true, "id":15, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":15, "subkey":null},
{"error": false, "id":16, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":16, "subkey":"a529216624ef9161e4cf117272aafff2"},
{"error": false, "id":17, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":17, "subkey":"068bd6940b80c6cc2530a68c31d9f4e323"},
{"error": false, "id":18, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":18, "subkey":"0acf4f6c74a590c8a1c0997ec9a1a3f48b2a"},
{"error": false, "id":19, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":19, "subkey":"ac17a37ce74c0efece75f9337de20795dbadcc"},
{"error": false, "id":20, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":20, "subkey":"268214dc9477a2e3c1022829f934ab992a5a3d84"},
{"error": false, "id":21, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":21, "subkey":"33b76197b4531665e494760909eda1cc570e7da9bb"},
{"error": false, "id":22, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":22, "subkey":"3d4efbc569ca7f858ad4f49c56b820986a406e6eebbc"},
{"error": false, "id":23, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":23, "subkey":"983fea27520f507c40231f9557908f07c095bdf4a4ce5d"},
{"error": false, "id":24, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":24, "subkey":"94d678717625e011995c7355f2092267dee47bf0722dd380"},
{"error": false, "id":25, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":25, "subkey":"198901896c4f51e74ffa8b2805415c6eaba5accfc85a6e6b34"},
{"error": false, "id":26, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":26, "subkey":"4ffabb81d49021f85ef5d2a713ab02ae86bc2e7d1522f5e077fe"},
{"error": false, "id":27, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":27, "subkey":"eebc3d55b3f4fc8b64d2474063254da7db98e7398dfdd510e28075"},
{"error": false, "id":28, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":28, "subkey":"22c134b9d664e1bdb14dc309a936bf1512b19e4f5175642efb1a0df7"},
{"error": false, "id":29, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":29, "subkey":"4b179762bfc8e27a9e575113faa76247b9c046d6f22d5a02e2910a299b"},
{"error": false, "id":30, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":30, "subkey":"abc45eb2b031307b8822c7e59a43f4108850c34a7445936bc848422251c4"},
{"error": false, "id":31, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":31, "subkey":"d6565bd3265b6373f4f6a6b6458e981006da5e9d532ce94ca4737e188995e9"},
{"error": false, "id":32, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":32, "subkey":"154b291f11196737f8b7f491e4ca11764e0227d34f94295408a869f007aa8618"},
{"error": false, "id":33, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":33, "subkey":"e9dd395570e09ebb523ffc6ba098a38b17bc4944f14bd3725bdd7edbd8bcff54fb"},
{"error": false, "id":34, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":34, "subkey":"7248294d37159e85bacde68c7762a673794c91b811e05f4e3b9e3ecc82bfcf63a2cd"},
{"error": false, "id":35, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":35, "subkey":"d060ee4d93f8de6d9ae60fca9596413455183a1f83c7a2381227cec8f7a217e4072f85"},
{"error": false, "id":36, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":36, "subkey":"20790290347b9b0f413a954f40e52e270b3b45417e96c8733161672188701c08dd76cc3d"},
{"error": false, "id":37, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":37, "subkey":"7674188112a1ab8d3926d468be8e51d788ce4144bb20ff842034e4d1ddab3929a4f1a13a74"},
{"error": false, "id":38, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":38, "subkey":"a2ab1f980a47472d8a539f20410cc9bf143d941331ab2259ea73684c0608939c5b23e9cbcb3d"},
{"error": false, "id":39, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":39, "subkey":"f4cfbe3050f15ebbaf8d2f3bf3a678c01fc21ee1f4be07d0744c7fbf4835ea9d9472a3d785c24c"},
{"error": false, "id":40, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":40, "subkey":"66efa5dfe3efd4cc8ca25f2d622c97a20a192d7add965f26b002b7eb81aae4203c0e5f07fd945845"},
{"error": false, "id":41, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":41, "subkey":"ad5d8031055c96dc9db10285206d7edc38d3af85736df8a3b5fdd30a318e80c28d9b26c95a60fa3e68"},
{"error": false, "id":42, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":42, "subkey":"9107c8a57a2c9ca40158f33ca0bfb64c095d2f21ca98bb7138477599330a36cdfc2ae5751e370d0e024e"},
{"error": false, "id":43, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":43, "subkey":"b0c190177358b955ebebc5e0b86ec91dde3b6f1982ea4d68ec5ec3bdd6527c362e5275600b263601c98452"},
{"error": false, "id":44, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":44, "subkey":"31bfaaad4adde0f87d87372e398c42cb7befe065ab2957ebb91ef9dc534b410783899b2e1e84221286f3bab4"},
{"error": false, "id":45, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":45, "subkey":"2258dd1f3e516cb8e3d1f6c45808573c365192f073698939721af8961a02a8bdd002a31fd239b9498663a01f27"},
{"error": false, "id":46, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":46, "subkey":"7c7a88016610493bb44a9432a88b50f97e2e94383972ff95da826692d96c52d82f86899b3561ec9c95a8b1bf3213"},
{"error": false, "id":47, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":47, "subkey":"3929dc7473be4c633be9e08801a8abd284dc0c6154c5c81a4c18259699dd86753c5e14fbd723be46ebb04f4ab3058c"},
{"error": false, "id":48, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":48, "subkey":"30b720220015fa60daa69c83f9754d772b1b2dd12ab6baaa2f4edab458d4d251c1cddb8c4a554f3eb13969316b890fbd"},
{"error": false, "id":49, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":49, "subkey":"33fa2412a5c3294d49e964419e96d043a2099a72b3351e3bed0f07e12255c95b509ea9bf2963a4c0fe9cc2314dbc44f673"},
{"error": false, "id":50, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":50, "subkey":"ca891d2c82a6a8f833dc1a05f190bab6de221307eab1dd2c88341d4d2537a2fc0056b0d04d8104fd3fe89e1ea20877893e81"},
{"error": false, "id":51, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":51, "subkey":"fd78ac89a64d03672ad99d663f2613d15277cda1636e334a1706b7211ff1f3a3b3d2e671e391c75e3d242c482ce7e1b8b427ed"},
{"error": false, "id":52, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":52, "subkey":"36a6072743d3aafd3ee89344b9ef92cb58a2853ae92b20283520439fcb55afffd3d4b5e4e8c92a85d3cf74497bdcf68bbf1fcf93"},
{"error": false, "id":53, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":53, "subkey":"a90afcfaffec1105ad05fdaa9473fb5daf1bf8fb376b7326db46ef4c120c553188c69131933371d409eb56d66d5adca618e1dac65b"},
{"error": false, "id":54, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":54, "subkey":"9b990d1fcddbdb5e5c7a48a6a2a666e02e7d4d4a814ece40660d99e1c02d5f023c56ae82526fc6dc8c933d0add92fc376efcddd55a42"},
{"error": false, "id":55, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":55, "subkey":"ec545dcf456d1b0907c07418a42bf2b3d668b4797ba6874bf0d563f5f429a820f02177dd4d05e639a06807c9619fee54ffe07712493543"},
{"error": false, "id":56, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":56, "subkey":"b0106957626894586682a275f69ed4533e2f94334cc0430394b68d82679aca00dd579e712bdd2d7f5bbce9a050269739bd8427b75b06027f"},
{"error": false, "id":57, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":57, "subkey":"05751bfeebb480c9bca0d25d8197e2673845f405d7fb9793e29169ac19956c525f6e637f3d5ea50597b04342afed4ca16f988b4f21a34f1902"},
{"error": false, "id":58, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":58, "subkey":"7b4e4294d3f64085b5c09be73548f1f5cb5c6f04e57ce6cdd3077e2fb37640bf1ca0c6393b87d48a6b7e3e42628bd30fca132ded03ce51f71d9d"},
{"error": false, "id":59, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":59, "subkey":"082d248862cbfd71a634769a4b1cf52a4af47ace5b9ea4d583ca52207efc7234a6d321788130cbdec122579ad03afe00bc68c9fb3f68dd0532a96f"},
{"error": false, "id":60, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":60, "subkey":"a2b39b4428d981013e8a9c0e41b3eed504983fc18dc4b60332b1ab28b9705228147bdb95cc17889d5f0f9cfb7fd16f9d414b1a829346a8922e945b40"},
{"error": false, "id":61, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":61, "subkey":"efbf0f8bda1b9ef24fe389f1cf0c0c8a08bca03fc95badabb79a487d8ce1351683f59183aa6229f880d69ad60114ac128f69b2be250109972ab1f3fc3b"},
{"error": false, "id":62, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":62, "subkey":"dfe0ba2a6de25fa06b47375e9d9cf6c6fa1493a8a2a81c28d6e09bc161057b445659db76e92e349ff44f34a2a9e3bcaa6b84b21bae56f1499c170ab81af0"},
{"error": false, "id":63, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":63, "subkey":"02f9cbdb10759314515b01379c474ad74a1b575137bd3949776dbcfc3e18060cb13ee1f6dcf86035768fc7be63e01de321cacbfade209900dd94273fd8e176"},
{"error": false, "id":64, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"06ae14308eeeda62a00cb6d5edf18d1707029515db98f472bbf0617419301b1d4f4f2ab65849446be46f87e1d31c6c74283897b9976f70d8a16253ac927e0d9f"},
{"error": true, "id":65, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":65, "subkey":null}
]

2050
test/fixtures/crypto_sign.json vendored Normal file

File diff suppressed because it is too large Load Diff

1025
test/fixtures/crypto_tweak_ed25519_sign.js vendored Normal file

File diff suppressed because it is too large Load Diff

6
test/fixtures/mprotect_noaccess.js vendored Normal file
View File

@ -0,0 +1,6 @@
/* eslint-disable */
const sodium = require('../..')
const buf = sodium.sodium_malloc(1)
sodium.sodium_mprotect_noaccess(buf)
buf[0]
process.send('read')

8
test/fixtures/mprotect_readonly.js vendored Normal file
View File

@ -0,0 +1,8 @@
/* eslint-disable */
const sodium = require('../..')
const buf = sodium.sodium_malloc(1)
sodium.sodium_mprotect_readonly(buf)
buf[0]
process.send('read')
buf[0] = 1
process.send('write')

11
test/fixtures/mprotect_readwrite.js vendored Normal file
View File

@ -0,0 +1,11 @@
/* eslint-disable */
const sodium = require('../..')
const buf = sodium.sodium_malloc(1)
sodium.sodium_mprotect_noaccess(buf)
sodium.sodium_mprotect_readwrite(buf)
buf[0]
process.send('read')
buf[0] = 1
process.send('write')
sodium.sodium_mprotect_readonly(buf)
process.send(buf[0] === 1 ? 'did_write' : 'did_not_write')

103
test/helpers.js Normal file
View File

@ -0,0 +1,103 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test('sodium_memcmp', function (t) {
const b1 = Buffer.from([0, 1, 2, 3])
const b2 = Buffer.from([3, 2, 1, 0])
t.exception.all(_ => sodium.sodium_memcmp(), 'no args')
t.exception.all(_ => sodium.sodium_memcmp(b1), 'arg mismatch')
t.exception.all(_ => sodium.sodium_memcmp(b1, b2.slice(1)), 'length mismatch')
t.ok(sodium.sodium_memcmp(Buffer.alloc(0), Buffer.alloc(0)))
t.ok(sodium.sodium_memcmp(Buffer.alloc(5), Buffer.alloc(5)))
t.ok(sodium.sodium_memcmp(b1, b1))
t.absent(sodium.sodium_memcmp(b2, b1))
t.absent(sodium.sodium_memcmp(b1, b2))
})
test.skip('sodium_compare', function (t) {
const one = Buffer.from([1])
const two = Buffer.from([2])
const three = Buffer.from([3])
t.is(sodium.sodium_compare(Buffer.alloc(0), Buffer.alloc(0)), 0)
t.is(sodium.sodium_compare(one, one), 0)
t.is(sodium.sodium_compare(two, two), 0)
t.is(sodium.sodium_compare(three, three), 0)
t.is(sodium.sodium_compare(one, two), -1)
t.is(sodium.sodium_compare(one, three), -1)
t.is(sodium.sodium_compare(two, one), 1)
t.is(sodium.sodium_compare(three, one), 1)
t.is(sodium.sodium_compare(two, three), -1)
t.is(sodium.sodium_compare(three, two), 1)
})
test.skip('sodium_add', function (t) {
const large = Buffer.alloc(32)
large[23] = 0b00000011
const largeLessOne = Buffer.alloc(32)
largeLessOne[23] = 0b00000001
const c = Buffer.from(large)
sodium.sodium_add(c, largeLessOne)
t.ok(large[23], 4)
const overflow = Buffer.alloc(56, 0xff)
const one = Buffer.alloc(56)
one[0] = 1
sodium.sodium_add(overflow, one)
t.ok(sodium.sodium_is_zero(overflow))
})
test.skip('sub', function (t) {
const large = Buffer.alloc(32)
large[23] = 0b00000011
const largeLessOne = Buffer.alloc(32)
largeLessOne[23] = 0b00000001
const c = Buffer.from(large)
sodium.sodium_sub(c, largeLessOne)
t.ok(large[23], 2)
const overflow = Buffer.alloc(56, 0x00)
const one = Buffer.alloc(56)
one[0] = 1
sodium.sodium_sub(overflow, one)
t.ok(sodium.sodium_memcmp(overflow, Buffer.alloc(56, 0xff)))
})
test('sodium_increment', function (t) {
const zero = Buffer.alloc(4)
sodium.sodium_increment(zero)
t.ok(zero[0], 1)
const overflow = Buffer.alloc(56, 0xff)
sodium.sodium_increment(overflow)
t.ok(sodium.sodium_is_zero(overflow))
})
test('sodium_is_zero', function (t) {
const buf = Buffer.from([0, 0, 0, 1])
t.exception.all(_ => sodium.sodium_is_zero(), 'no args')
t.exception.all(_ => sodium.sodium_is_zero(null), 'missing buf')
t.ok(sodium.sodium_is_zero(Buffer.alloc(0)), 'empty buffer')
t.ok(sodium.sodium_is_zero(buf.subarray(0, 0)), 'zero bytes')
t.ok(sodium.sodium_is_zero(buf.subarray(0, 1)), 'one byte')
t.ok(sodium.sodium_is_zero(buf.subarray(0, 2)), 'two bytes')
t.ok(sodium.sodium_is_zero(buf.subarray(0, 3)), '3 bytes')
t.absent(sodium.sodium_is_zero(buf), 'first non-zero byte')
t.ok(sodium.sodium_is_zero(buf.subarray(1, 2)), 'view')
t.ok(sodium.sodium_is_zero(buf.subarray(1, 2)), 'view')
t.absent(sodium.sodium_is_zero(buf.subarray(3)), 'view')
})

126
test/memory.js Normal file
View File

@ -0,0 +1,126 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
const fork = require('child_process').fork
test.skip('sodium_mprotect_noaccess', function (t) {
t.plan(1)
const p = fork(require.resolve('./fixtures/mprotect_noaccess'))
p.on('message', function () {
t.fail()
})
p.on('exit', function (code, signal) {
t.ok(p.signalCode !== null || p.exitCode > 0)
})
})
test.skip('sodium_mprotect_readonly', function (t) {
t.plan(2)
const p = fork(require.resolve('./fixtures/mprotect_readonly'))
p.on('message', function (msg) {
t.ok(msg === 'read')
})
p.on('exit', function (code, signal) {
t.ok(p.signalCode !== null || p.exitCode > 0)
})
})
test.skip('sodium_mprotect_readwrite', function (t) {
t.plan(4)
const p = fork(require.resolve('./fixtures/mprotect_readwrite'))
p.on('message', function (msg) {
switch (msg) {
case 'read': t.pass()
break
case 'write': t.pass()
break
case 'did_write': t.pass()
break
case 'did_not_write': t.fail()
break
default: t.fail()
break
}
})
p.on('exit', function (code, signal) {
t.ok(p.signalCode === null || p.exitCode === 0)
})
})
test('sodium_memzero', function (t) {
const buf = Buffer.alloc(10, 0xab)
const exp = Buffer.alloc(10, 0xab)
const zero = Buffer.alloc(10)
t.alike(buf, exp, 'buffers start out with same content')
t.unlike(buf, zero, 'buffer is not zero')
sodium.sodium_memzero(buf)
t.unlike(buf, exp, 'buffers are not longer the same')
t.alike(buf, zero, 'buffer is now zeroed')
})
test.skip('sodium_mlock / sodium_munlock', function (t) {
const buf = Buffer.alloc(10, 0x18)
const exp = Buffer.alloc(10, 0x18)
sodium.sodium_mlock(buf)
t.absent(buf.secure)
t.alike(buf, exp, 'mlock did not corrupt data')
sodium.sodium_munlock(buf)
t.absent(buf.secure)
t.alike(buf, Buffer.alloc(10), 'munlock did zero data')
})
test('sodium_malloc', function (t) {
const empty = sodium.sodium_malloc(0)
const small = sodium.sodium_malloc(1)
const large = sodium.sodium_malloc(1e8)
// sodium-javascript does not set secure prop
// t.ok(empty.secure)
// t.ok(small.secure)
// t.ok(large.secure)
t.ok(empty.length === 0, 'has correct size')
t.ok(small.length === 1, 'has correct size')
t.ok(large.length === 1e8, 'has correct size')
// const expected = Buffer.from([0xdb])
// expected.secure = true
// t.alike(small, expected, 'has canary content')
// test gc
for (let i = 0; i < 1e3; i++) {
if (sodium.sodium_malloc(256).length !== 256) {
t.fail('allocated incorrect size')
}
}
t.ok(empty.length === 0, 'retained correct size')
t.ok(small.length === 1, 'retained correct size')
t.ok(large.length === 1e8, 'retained correct size')
})
test('sodium_free', function (t) {
if (process.version.startsWith('v10')) {
t.comment('Skipping free test on v10')
return
}
const buf = sodium.sodium_malloc(1)
t.ok(buf.byteLength === 1)
sodium.sodium_free(buf)
t.ok(buf.byteLength === 0)
})
test.skip('sodium_malloc bounds', function (t) {
t.throws(function () {
sodium.sodium_malloc(-1)
}, 'too small')
t.throws(function () {
sodium.sodium_malloc(Number.MAX_SAFE_INTEGER)
}, 'too large')
})

111
test/randombytes.js Normal file
View File

@ -0,0 +1,111 @@
/* eslint-disable camelcase */
const test = require('brittle')
const sodium = require('..')
test.skip('constants', function (t) {
t.alike(typeof sodium.randombytes_SEEDBYTES, 'number', 'randombytes_SEEDBYTES is number')
})
test.skip('randombytes_random', function (t) {
for (let i = 0; i < 1e6; i++) {
const n = sodium.randombytes_random()
if (n > 0xffffffff || n < 0) t.fail()
}
})
test.skip('randombytes_uniform', function (t) {
const p = 5381
for (let i = 0; i < 1e6; i++) {
const n = sodium.randombytes_uniform(5381)
if (n >= p || n < 0) t.fail()
}
})
test('randombytes_buf', function (t) {
let buf = null
buf = Buffer.alloc(10)
sodium.randombytes_buf(buf)
t.not(buf, Buffer.alloc(10), 'not blank')
buf = Buffer.alloc(1024)
sodium.randombytes_buf(buf)
t.not(buf, Buffer.alloc(1024), 'large not blank')
})
test.skip('randombytes_deterministic', function (t) {
const seed1 = Buffer.allocUnsafe(sodium.randombytes_SEEDBYTES)
const seed2 = Buffer.allocUnsafe(sodium.randombytes_SEEDBYTES)
const buf1 = Buffer.alloc(10)
const buf2 = Buffer.alloc(10)
for (let i = 0; i < 1e6; i++) {
sodium.randombytes_buf(seed1)
sodium.randombytes_buf(seed2)
sodium.randombytes_buf_deterministic(buf1, seed1)
sodium.randombytes_buf_deterministic(buf2, seed1)
if (!buf1.equals(buf2)) t.fail('should equal')
sodium.randombytes_buf_deterministic(buf1, seed1)
sodium.randombytes_buf_deterministic(buf2, seed2)
if (buf1.equals(buf2)) t.fail('should not equal')
sodium.randombytes_buf_deterministic(buf1, seed2)
sodium.randombytes_buf_deterministic(buf2, seed1)
if (buf1.equals(buf2)) t.fail('should not equal')
sodium.randombytes_buf_deterministic(buf1, seed2)
sodium.randombytes_buf_deterministic(buf2, seed2)
if (!buf1.equals(buf2)) t.fail('should equal')
}
})
test.skip('Various test cases', function (t) {
sodium.randombytes_buf(Buffer.alloc(0))
sodium.randombytes_buf(new Uint8Array(16))
t.throws(function () {
sodium.randombytes_buf([])
})
t.end()
})
test('Generates random bytes', function (t) {
const bufConst = Buffer.alloc(64)
sodium.randombytes_buf(bufConst)
const buf1 = Buffer.alloc(64)
for (let i = 0; i < 1e4; i++) {
sodium.randombytes_buf(buf1)
if (Buffer.compare(buf1, bufConst) === 0) {
t.fail('Constant buffer should not be equal')
t.end()
return
}
}
t.pass('Generated unique buffers')
t.end()
})
test('Exceed quota', function (t) {
const buf = Buffer.alloc(1 << 17)
sodium.randombytes_buf(buf)
const scores = new Array(256)
scores.fill(0)
for (const b of buf) {
scores[b]++
}
scores
.map(cnt => cnt / 256)
.forEach(cnt => {
if (cnt < 1 && cnt > 3) t.fail('Statistically unreasonable')
})
t.end()
})

1230
test/vectors.js Normal file

File diff suppressed because it is too large Load Diff