├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── crypto_aead.js ├── crypto_auth.js ├── crypto_box.js ├── crypto_generichash.js ├── crypto_hash.js ├── crypto_hash_sha256.js ├── crypto_kdf.js ├── crypto_kx.js ├── crypto_onetimeauth.js ├── crypto_scalarmult.js ├── crypto_secretbox.js ├── crypto_secretstream.js ├── crypto_shorthash.js ├── crypto_sign.js ├── crypto_stream.js ├── crypto_stream_chacha20.js ├── crypto_verify.js ├── example.js ├── helpers.js ├── index.js ├── internal ├── ed25519.js ├── hchacha20.js └── poly1305.js ├── memory.js ├── package.json ├── randombytes.js └── test ├── crypto_aead_chacha20poly1305_ietf.js ├── crypto_auth.js ├── crypto_box.js ├── crypto_generichash.js ├── crypto_hash.js ├── crypto_hash_sha256.js ├── crypto_hash_sha512.js ├── crypto_kdf.js ├── crypto_kx.js ├── crypto_onetimeauth.js ├── crypto_scalarmult.js ├── crypto_secretbox.js ├── crypto_secretstream.js ├── crypto_shorthash.js ├── crypto_sign.js ├── crypto_stream.js ├── crypto_stream_chacha20.js ├── crypto_stream_chacha20_ietf.js ├── fixtures ├── crypto_kdf.json ├── crypto_sign.json ├── crypto_tweak_ed25519_sign.js ├── mprotect_noaccess.js ├── mprotect_readonly.js └── mprotect_readwrite.js ├── helpers.js ├── memory.js ├── randombytes.js └── vectors.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - lts/* 4 | env: 5 | global: 6 | - MOZ_HEADLESS=1 7 | services: 8 | - xvfb 9 | addons: 10 | firefox: latest 11 | chrome: stable 12 | cache: 13 | npm: false 14 | 15 | script: 16 | - npm test 17 | - xvfb-run --auto-servernum npm run test-browser -- --browser chrome 18 | - xvfb-run --auto-servernum npm run test-browser -- --browser firefox 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Mathias Buus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `sodium-javascript` 2 | 3 | [![Build Status](https://travis-ci.org/sodium-friends/sodium-javascript.svg?branch=master)](https://travis-ci.org/sodium-friends/sodium-javascript) 4 | 5 | > WIP - a pure javascript version of [sodium-native](https://github.com/sodium-friends/sodium-native). 6 | Based on tweetnacl 7 | 8 | ## Usage 9 | 10 | ``` js 11 | const sodium = require('sodium-javascript') 12 | 13 | const key = Buffer.alloc(sodium.crypto_secretbox_KEYBYTES) 14 | const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES) 15 | 16 | sodium.randombytes_buf(key) 17 | sodium.randombytes_buf(nonce) 18 | 19 | const message = Buffer.from('Hello, World!') 20 | const cipher = Buffer.alloc(message.length + sodium.crypto_secretbox_MACBYTES) 21 | 22 | sodium.crypto_secretbox_easy(cipher, message, nonce, key) 23 | 24 | console.log('Encrypted:', cipher) 25 | 26 | const plainText = Buffer.alloc(cipher.length - sodium.crypto_secretbox_MACBYTES) 27 | 28 | sodium.crypto_secretbox_open_easy(plainText, cipher, nonce, key) 29 | 30 | console.log('Plaintext:', plainText.toString()) 31 | ``` 32 | 33 | ## API 34 | 35 | See [sodium-native](https://github.com/sodium-friends/sodium-native). 36 | This is a work in progress so not all functions are implemented yet. 37 | 38 | This module is organised into individual submodules which can be required 39 | independently for smaller bundles in the browser. To leverage automatic 40 | switching between `sodium-javascript` and `sodium-native`, see 41 | [`sodium-universal`](https://github.com/sodium-friends/sodium-universal). 42 | 43 | ## Install 44 | 45 | ``` 46 | npm install sodium-javascript 47 | ``` 48 | 49 | ## License 50 | 51 | [MIT](LICENSE) 52 | -------------------------------------------------------------------------------- /crypto_aead.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const { crypto_stream_chacha20_ietf, crypto_stream_chacha20_ietf_xor_ic } = require('./crypto_stream_chacha20') 3 | const { crypto_verify_16 } = require('./crypto_verify') 4 | const Poly1305 = require('./internal/poly1305') 5 | const assert = require('nanoassert') 6 | 7 | const crypto_aead_chacha20poly1305_ietf_KEYBYTES = 32 8 | const crypto_aead_chacha20poly1305_ietf_NSECBYTES = 0 9 | const crypto_aead_chacha20poly1305_ietf_NPUBBYTES = 12 10 | const crypto_aead_chacha20poly1305_ietf_ABYTES = 16 11 | const crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX = Number.MAX_SAFE_INTEGER 12 | 13 | const _pad0 = new Uint8Array(16) 14 | 15 | function crypto_aead_chacha20poly1305_ietf_encrypt (c, m, ad, nsec, npub, k) { 16 | if (ad === null) return crypto_aead_chacha20poly1305_ietf_encrypt(c, m, new Uint8Array(0), nsec, npub, k) 17 | 18 | assert(c.byteLength === m.byteLength + crypto_aead_chacha20poly1305_ietf_ABYTES, 19 | "ciphertext should be 'crypto_aead_chacha20poly1305_ietf_ABYTES' longer than message") 20 | assert(npub.byteLength === crypto_aead_chacha20poly1305_ietf_NPUBBYTES, 21 | "npub should be 'crypto_aead_chacha20poly1305_ietf_NPUBBYTES' long") 22 | assert(k.byteLength === crypto_aead_chacha20poly1305_ietf_KEYBYTES, 23 | "k should be 'crypto_aead_chacha20poly1305_ietf_KEYBYTES' long") 24 | assert(m.byteLength <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'message is too large') 25 | 26 | const ret = crypto_aead_chacha20poly1305_ietf_encrypt_detached(c.subarray(0, m.byteLength), 27 | c.subarray(m.byteLength), m, ad, nsec, npub, k) 28 | 29 | return m.byteLength + ret 30 | } 31 | 32 | function crypto_aead_chacha20poly1305_ietf_encrypt_detached (c, mac, m, ad, nsec, npub, k) { 33 | if (ad === null) return crypto_aead_chacha20poly1305_ietf_encrypt_detached(c, mac, m, new Uint8Array(0), nsec, npub, k) 34 | 35 | assert(c.byteLength === m.byteLength, 'ciphertext should be same length than message') 36 | assert(npub.byteLength === crypto_aead_chacha20poly1305_ietf_NPUBBYTES, 37 | "npub should be 'crypto_aead_chacha20poly1305_ietf_NPUBBYTES' long") 38 | assert(k.byteLength === crypto_aead_chacha20poly1305_ietf_KEYBYTES, 39 | "k should be 'crypto_aead_chacha20poly1305_ietf_KEYBYTES' long") 40 | assert(m.byteLength <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'message is too large') 41 | assert(mac.byteLength <= crypto_aead_chacha20poly1305_ietf_ABYTES, 42 | "mac should be 'crypto_aead_chacha20poly1305_ietf_ABYTES' long") 43 | 44 | const block0 = new Uint8Array(64) 45 | var slen = new Uint8Array(8) 46 | 47 | crypto_stream_chacha20_ietf(block0, npub, k) 48 | const poly = new Poly1305(block0) 49 | block0.fill(0) 50 | 51 | poly.update(ad, 0, ad.byteLength) 52 | poly.update(_pad0, 0, (0x10 - ad.byteLength) & 0xf) 53 | 54 | crypto_stream_chacha20_ietf_xor_ic(c, m, npub, 1, k) 55 | 56 | poly.update(c, 0, m.byteLength) 57 | poly.update(_pad0, 0, (0x10 - m.byteLength) & 0xf) 58 | 59 | write64LE(slen, 0, ad.byteLength) 60 | poly.update(slen, 0, slen.byteLength) 61 | 62 | write64LE(slen, 0, m.byteLength) 63 | poly.update(slen, 0, slen.byteLength) 64 | 65 | poly.finish(mac, 0) 66 | slen.fill(0) 67 | 68 | return crypto_aead_chacha20poly1305_ietf_ABYTES 69 | } 70 | 71 | function crypto_aead_chacha20poly1305_ietf_decrypt (m, nsec, c, ad, npub, k) { 72 | if (ad === null) return crypto_aead_chacha20poly1305_ietf_decrypt(m, nsec, c, new Uint8Array(0), npub, k) 73 | 74 | assert(m.byteLength === c.byteLength - crypto_aead_chacha20poly1305_ietf_ABYTES, 75 | "message should be 'crypto_aead_chacha20poly1305_ietf_ABYTES' shorter than ciphertext") 76 | assert(npub.byteLength === crypto_aead_chacha20poly1305_ietf_NPUBBYTES, 77 | "npub should be 'crypto_aead_chacha20poly1305_ietf_NPUBBYTES' long") 78 | assert(k.byteLength === crypto_aead_chacha20poly1305_ietf_KEYBYTES, 79 | "k should be 'crypto_aead_chacha20poly1305_ietf_KEYBYTES' long") 80 | assert(m.byteLength <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'message is too large') 81 | 82 | if (c.byteLength < crypto_aead_chacha20poly1305_ietf_ABYTES) throw new Error('could not verify data') 83 | 84 | crypto_aead_chacha20poly1305_ietf_decrypt_detached( 85 | m, nsec, 86 | c.subarray(0, c.byteLength - crypto_aead_chacha20poly1305_ietf_ABYTES), 87 | c.subarray(c.byteLength - crypto_aead_chacha20poly1305_ietf_ABYTES), 88 | ad, npub, k) 89 | 90 | return c.byteLength - crypto_aead_chacha20poly1305_ietf_ABYTES 91 | } 92 | 93 | function crypto_aead_chacha20poly1305_ietf_decrypt_detached (m, nsec, c, mac, ad, npub, k) { 94 | if (ad === null) return crypto_aead_chacha20poly1305_ietf_decrypt_detached(m, nsec, c, mac, new Uint8Array(0), npub, k) 95 | 96 | assert(c.byteLength === m.byteLength, 'message should be same length than ciphertext') 97 | assert(npub.byteLength === crypto_aead_chacha20poly1305_ietf_NPUBBYTES, 98 | "npub should be 'crypto_aead_chacha20poly1305_ietf_NPUBBYTES' long") 99 | assert(k.byteLength === crypto_aead_chacha20poly1305_ietf_KEYBYTES, 100 | "k should be 'crypto_aead_chacha20poly1305_ietf_KEYBYTES' long") 101 | assert(m.byteLength <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'message is too large') 102 | assert(mac.byteLength <= crypto_aead_chacha20poly1305_ietf_ABYTES, 103 | "mac should be 'crypto_aead_chacha20poly1305_ietf_ABYTES' long") 104 | 105 | const block0 = new Uint8Array(64) 106 | const slen = new Uint8Array(8) 107 | const computed_mac = new Uint8Array(crypto_aead_chacha20poly1305_ietf_ABYTES) 108 | 109 | crypto_stream_chacha20_ietf(block0, npub, k) 110 | const poly = new Poly1305(block0) 111 | block0.fill(0) 112 | 113 | poly.update(ad, 0, ad.byteLength) 114 | poly.update(_pad0, 0, (0x10 - ad.byteLength) & 0xf) 115 | 116 | const mlen = c.byteLength 117 | poly.update(c, 0, mlen) 118 | poly.update(_pad0, 0, (0x10 - mlen) & 0xf) 119 | 120 | write64LE(slen, 0, ad.byteLength) 121 | poly.update(slen, 0, slen.byteLength) 122 | 123 | write64LE(slen, 0, mlen) 124 | poly.update(slen, 0, slen.byteLength) 125 | 126 | poly.finish(computed_mac, 0) 127 | 128 | assert(computed_mac.byteLength === 16) 129 | const ret = crypto_verify_16(computed_mac, 0, mac, 0) 130 | 131 | computed_mac.fill(0) 132 | slen.fill(0) 133 | 134 | if (!ret) { 135 | m.fill(0) 136 | throw new Error('could not verify data') 137 | } 138 | 139 | crypto_stream_chacha20_ietf_xor_ic(m, c, npub, 1, k) 140 | } 141 | 142 | function write64LE (buf, offset, int) { 143 | buf.fill(0, 0, 8) 144 | 145 | const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength) 146 | view.setUint32(offset, int & 0xffffffff, true) 147 | view.setUint32(offset + 4, (int / 2 ** 32) & 0xffffffff, true) 148 | } 149 | 150 | module.exports = { 151 | crypto_aead_chacha20poly1305_ietf_encrypt, 152 | crypto_aead_chacha20poly1305_ietf_encrypt_detached, 153 | crypto_aead_chacha20poly1305_ietf_decrypt, 154 | crypto_aead_chacha20poly1305_ietf_decrypt_detached, 155 | crypto_aead_chacha20poly1305_ietf_ABYTES, 156 | crypto_aead_chacha20poly1305_ietf_KEYBYTES, 157 | crypto_aead_chacha20poly1305_ietf_NPUBBYTES, 158 | crypto_aead_chacha20poly1305_ietf_NSECBYTES, 159 | crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX 160 | } 161 | -------------------------------------------------------------------------------- /crypto_auth.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const { crypto_verify_32 } = require('./crypto_verify') 3 | const Sha512 = require('sha512-universal') 4 | const assert = require('nanoassert') 5 | 6 | const crypto_auth_BYTES = 32 7 | const crypto_auth_KEYBYTES = 32 8 | 9 | function crypto_auth (out, input, k) { 10 | assert(out.byteLength === crypto_auth_BYTES, "out should be 'crypto_auth_BYTES' in length") 11 | assert(k.byteLength === crypto_auth_KEYBYTES, "key should be 'crypto_auth_KEYBYTES' in length") 12 | 13 | const out0 = new Uint8Array(64) 14 | const hmac = Sha512.HMAC(k) 15 | hmac.update(input) 16 | hmac.digest(out0) 17 | 18 | out.set(out0.subarray(0, 32)) 19 | } 20 | 21 | function crypto_auth_verify (h, input, k) { 22 | assert(h.byteLength === crypto_auth_BYTES, "h should be 'crypto_auth_BYTES' in length") 23 | assert(k.byteLength === crypto_auth_KEYBYTES, "key should be 'crypto_auth_KEYBYTES' in length") 24 | 25 | const correct = Sha512.HMAC(k).update(input).digest() 26 | 27 | return crypto_verify_32(h, 0, correct, 0) 28 | } 29 | 30 | module.exports = { 31 | crypto_auth_BYTES, 32 | crypto_auth_KEYBYTES, 33 | crypto_auth, 34 | crypto_auth_verify 35 | } 36 | -------------------------------------------------------------------------------- /crypto_box.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const { crypto_hash_sha512 } = require('./crypto_hash') 3 | const { crypto_scalarmult, crypto_scalarmult_base } = require('./crypto_scalarmult') 4 | const { randombytes } = require('./randombytes') 5 | const { crypto_generichash_batch } = require('./crypto_generichash') 6 | const { crypto_stream_xsalsa20_MESSAGEBYTES_MAX } = require('./crypto_stream') 7 | const { 8 | crypto_secretbox_open_easy, 9 | crypto_secretbox_easy, 10 | crypto_secretbox_detached, 11 | crypto_secretbox_open_detached 12 | } = require('./crypto_secretbox') 13 | const xsalsa20 = require('xsalsa20') 14 | const assert = require('nanoassert') 15 | 16 | const crypto_box_PUBLICKEYBYTES = 32 17 | const crypto_box_SECRETKEYBYTES = 32 18 | const crypto_box_NONCEBYTES = 24 19 | const crypto_box_ZEROBYTES = 32 20 | const crypto_box_BOXZEROBYTES = 16 21 | const crypto_box_SEALBYTES = 48 22 | const crypto_box_SEEDBYTES = 32 23 | const crypto_box_BEFORENMBYTES = 32 24 | const crypto_box_MACBYTES = 16 25 | 26 | const crypto_box_curve25519xsalsa20poly1305_MACBYTES = 16 27 | 28 | const crypto_box_MESSAGEBYTES_MAX = 29 | crypto_stream_xsalsa20_MESSAGEBYTES_MAX - 30 | crypto_box_curve25519xsalsa20poly1305_MACBYTES 31 | 32 | module.exports = { 33 | crypto_box_easy, 34 | crypto_box_open_easy, 35 | crypto_box_keypair, 36 | crypto_box_seed_keypair, 37 | crypto_box_seal, 38 | crypto_box_seal_open, 39 | crypto_box_PUBLICKEYBYTES, 40 | crypto_box_SECRETKEYBYTES, 41 | crypto_box_NONCEBYTES, 42 | crypto_box_ZEROBYTES, 43 | crypto_box_BOXZEROBYTES, 44 | crypto_box_SEALBYTES, 45 | crypto_box_SEEDBYTES, 46 | crypto_box_BEFORENMBYTES, 47 | crypto_box_MACBYTES 48 | } 49 | 50 | function crypto_box_keypair (pk, sk) { 51 | check(pk, crypto_box_PUBLICKEYBYTES) 52 | check(sk, crypto_box_SECRETKEYBYTES) 53 | randombytes(sk, 32) 54 | return crypto_scalarmult_base(pk, sk) 55 | } 56 | function crypto_box_seed_keypair (pk, sk, seed) { 57 | assert(pk.byteLength === crypto_box_PUBLICKEYBYTES, "pk should be 'crypto_box_PUBLICKEYBYTES' bytes") 58 | assert(sk.byteLength === crypto_box_SECRETKEYBYTES, "sk should be 'crypto_box_SECRETKEYBYTES' bytes") 59 | assert(sk.byteLength === crypto_box_SEEDBYTES, "sk should be 'crypto_box_SEEDBYTES' bytes") 60 | 61 | const hash = new Uint8Array(64) 62 | crypto_hash_sha512(hash, seed, 32) 63 | sk.set(hash.subarray(0, 32)) 64 | hash.fill(0) 65 | 66 | return crypto_scalarmult_base(pk, sk) 67 | } 68 | 69 | function crypto_box_seal (c, m, pk) { 70 | check(c, crypto_box_SEALBYTES + m.length) 71 | check(pk, crypto_box_PUBLICKEYBYTES) 72 | 73 | var epk = c.subarray(0, crypto_box_PUBLICKEYBYTES) 74 | var esk = new Uint8Array(crypto_box_SECRETKEYBYTES) 75 | crypto_box_keypair(epk, esk) 76 | 77 | var n = new Uint8Array(crypto_box_NONCEBYTES) 78 | crypto_generichash_batch(n, [epk, pk]) 79 | 80 | var s = new Uint8Array(crypto_box_PUBLICKEYBYTES) 81 | crypto_scalarmult(s, esk, pk) 82 | 83 | var k = new Uint8Array(crypto_box_BEFORENMBYTES) 84 | var zero = new Uint8Array(16) 85 | xsalsa20.core_hsalsa20(k, zero, s, xsalsa20.SIGMA) 86 | 87 | crypto_secretbox_easy(c.subarray(epk.length), m, n, k) 88 | 89 | cleanup(esk) 90 | } 91 | 92 | function crypto_box_seal_open (m, c, pk, sk) { 93 | check(c, crypto_box_SEALBYTES) 94 | check(m, c.length - crypto_box_SEALBYTES) 95 | check(pk, crypto_box_PUBLICKEYBYTES) 96 | check(sk, crypto_box_SECRETKEYBYTES) 97 | 98 | var epk = c.subarray(0, crypto_box_PUBLICKEYBYTES) 99 | 100 | var n = new Uint8Array(crypto_box_NONCEBYTES) 101 | crypto_generichash_batch(n, [epk, pk]) 102 | 103 | var s = new Uint8Array(crypto_box_PUBLICKEYBYTES) 104 | crypto_scalarmult(s, sk, epk) 105 | 106 | var k = new Uint8Array(crypto_box_BEFORENMBYTES) 107 | var zero = new Uint8Array(16) 108 | xsalsa20.core_hsalsa20(k, zero, s, xsalsa20.SIGMA) 109 | 110 | return crypto_secretbox_open_easy(m, c.subarray(epk.length), n, k) 111 | } 112 | 113 | function crypto_box_beforenm (k, pk, sk) { 114 | const zero = new Uint8Array(16) 115 | const s = new Uint8Array(32) 116 | 117 | assert(crypto_scalarmult(s, sk, pk) === 0) 118 | 119 | xsalsa20.core_hsalsa20(k, zero, s, xsalsa20.SIGMA) 120 | 121 | return true 122 | } 123 | 124 | function crypto_box_detached_afternm (c, mac, m, n, k) { 125 | return crypto_secretbox_detached(c, mac, m, n, k) 126 | } 127 | 128 | function crypto_box_detached (c, mac, m, n, pk, sk) { 129 | check(mac, crypto_box_MACBYTES) 130 | check(n, crypto_box_NONCEBYTES) 131 | check(pk, crypto_box_PUBLICKEYBYTES) 132 | check(sk, crypto_box_SECRETKEYBYTES) 133 | 134 | const k = new Uint8Array(crypto_box_BEFORENMBYTES) 135 | 136 | assert(crypto_box_beforenm(k, pk, sk)) 137 | 138 | const ret = crypto_box_detached_afternm(c, mac, m, n, k) 139 | cleanup(k) 140 | 141 | return ret 142 | } 143 | 144 | function crypto_box_easy (c, m, n, pk, sk) { 145 | assert( 146 | c.length >= m.length + crypto_box_MACBYTES, 147 | "c should be at least 'm.length + crypto_box_MACBYTES' bytes" 148 | ) 149 | assert( 150 | m.length <= crypto_box_MESSAGEBYTES_MAX, 151 | "m should be at most 'crypto_box_MESSAGEBYTES_MAX' bytes" 152 | ) 153 | 154 | return crypto_box_detached( 155 | c.subarray(crypto_box_MACBYTES, m.length + crypto_box_MACBYTES), 156 | c.subarray(0, crypto_box_MACBYTES), 157 | m, 158 | n, 159 | pk, 160 | sk 161 | ) 162 | } 163 | 164 | function crypto_box_open_detached_afternm (m, c, mac, n, k) { 165 | return crypto_secretbox_open_detached(m, c, mac, n, k) 166 | } 167 | 168 | function crypto_box_open_detached (m, c, mac, n, pk, sk) { 169 | const k = new Uint8Array(crypto_box_BEFORENMBYTES) 170 | assert(crypto_box_beforenm(k, pk, sk)) 171 | 172 | const ret = crypto_box_open_detached_afternm(m, c, mac, n, k) 173 | cleanup(k) 174 | 175 | return ret 176 | } 177 | 178 | function crypto_box_open_easy (m, c, n, pk, sk) { 179 | assert( 180 | c.length >= m.length + crypto_box_MACBYTES, 181 | "c should be at least 'm.length + crypto_box_MACBYTES' bytes" 182 | ) 183 | 184 | return crypto_box_open_detached( 185 | m, 186 | c.subarray(crypto_box_MACBYTES, m.length + crypto_box_MACBYTES), 187 | c.subarray(0, crypto_box_MACBYTES), 188 | n, 189 | pk, 190 | sk 191 | ) 192 | } 193 | 194 | function check (buf, len) { 195 | if (!buf || (len && buf.length < len)) throw new Error('Argument must be a buffer' + (len ? ' of length ' + len : '')) 196 | } 197 | 198 | function cleanup (arr) { 199 | for (let i = 0; i < arr.length; i++) arr[i] = 0 200 | } 201 | -------------------------------------------------------------------------------- /crypto_generichash.js: -------------------------------------------------------------------------------- 1 | var blake2b = require('blake2b') 2 | 3 | if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.') 4 | 5 | module.exports.crypto_generichash_PRIMITIVE = 'blake2b' 6 | module.exports.crypto_generichash_BYTES_MIN = blake2b.BYTES_MIN 7 | module.exports.crypto_generichash_BYTES_MAX = blake2b.BYTES_MAX 8 | module.exports.crypto_generichash_BYTES = blake2b.BYTES 9 | module.exports.crypto_generichash_KEYBYTES_MIN = blake2b.KEYBYTES_MIN 10 | module.exports.crypto_generichash_KEYBYTES_MAX = blake2b.KEYBYTES_MAX 11 | module.exports.crypto_generichash_KEYBYTES = blake2b.KEYBYTES 12 | module.exports.crypto_generichash_WASM_SUPPORTED = blake2b.WASM_SUPPORTED 13 | module.exports.crypto_generichash_WASM_LOADED = false 14 | 15 | module.exports.crypto_generichash = function (output, input, key) { 16 | blake2b(output.length, key).update(input).final(output) 17 | } 18 | 19 | module.exports.crypto_generichash_ready = blake2b.ready 20 | 21 | module.exports.crypto_generichash_batch = function (output, inputArray, key) { 22 | var ctx = blake2b(output.length, key) 23 | for (var i = 0; i < inputArray.length; i++) { 24 | ctx.update(inputArray[i]) 25 | } 26 | ctx.final(output) 27 | } 28 | 29 | module.exports.crypto_generichash_instance = function (key, outlen) { 30 | if (outlen == null) outlen = module.exports.crypto_generichash_BYTES 31 | return blake2b(outlen, key) 32 | } 33 | 34 | blake2b.ready(function (_) { 35 | module.exports.crypto_generichash_WASM_LOADED = blake2b.WASM_LOADED 36 | }) 37 | -------------------------------------------------------------------------------- /crypto_hash.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const sha512 = require('sha512-universal') 3 | const assert = require('nanoassert') 4 | 5 | if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.') 6 | 7 | const crypto_hash_sha512_BYTES = 64 8 | const crypto_hash_BYTES = crypto_hash_sha512_BYTES 9 | 10 | function crypto_hash_sha512 (out, m, n) { 11 | assert(out.byteLength === crypto_hash_sha512_BYTES, "out must be 'crypto_hash_sha512_BYTES' bytes long") 12 | 13 | sha512().update(m.subarray(0, n)).digest(out) 14 | return 0 15 | } 16 | 17 | function crypto_hash (out, m, n) { 18 | return crypto_hash_sha512(out, m, n) 19 | } 20 | 21 | module.exports = { 22 | crypto_hash, 23 | crypto_hash_sha512, 24 | crypto_hash_sha512_BYTES, 25 | crypto_hash_BYTES 26 | } 27 | -------------------------------------------------------------------------------- /crypto_hash_sha256.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const sha256 = require('sha256-universal') 3 | const assert = require('nanoassert') 4 | 5 | if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.') 6 | 7 | const crypto_hash_sha256_BYTES = 32 8 | 9 | function crypto_hash_sha256 (out, m, n) { 10 | assert(out.byteLength === crypto_hash_sha256_BYTES, "out must be 'crypto_hash_sha256_BYTES' bytes long") 11 | 12 | sha256().update(m.subarray(0, n)).digest(out) 13 | return 0 14 | } 15 | 16 | module.exports = { 17 | crypto_hash_sha256, 18 | crypto_hash_sha256_BYTES 19 | } 20 | -------------------------------------------------------------------------------- /crypto_kdf.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const assert = require('nanoassert') 3 | const randombytes_buf = require('./randombytes').randombytes_buf 4 | const blake2b = require('blake2b') 5 | 6 | module.exports.crypto_kdf_PRIMITIVE = 'blake2b' 7 | module.exports.crypto_kdf_BYTES_MIN = 16 8 | module.exports.crypto_kdf_BYTES_MAX = 64 9 | module.exports.crypto_kdf_CONTEXTBYTES = 8 10 | module.exports.crypto_kdf_KEYBYTES = 32 11 | 12 | function STORE64_LE (dest, int) { 13 | var mul = 1 14 | var i = 0 15 | dest[0] = int & 0xFF 16 | while (++i < 8 && (mul *= 0x100)) { 17 | dest[i] = (int / mul) & 0xFF 18 | } 19 | } 20 | 21 | module.exports.crypto_kdf_derive_from_key = function crypto_kdf_derive_from_key (subkey, subkey_id, ctx, key) { 22 | assert(subkey.length >= module.exports.crypto_kdf_BYTES_MIN, 'subkey must be at least crypto_kdf_BYTES_MIN') 23 | assert(subkey_id >= 0 && subkey_id <= 0x1fffffffffffff, 'subkey_id must be safe integer') 24 | assert(ctx.length >= module.exports.crypto_kdf_CONTEXTBYTES, 'context must be at least crypto_kdf_CONTEXTBYTES') 25 | 26 | var ctx_padded = new Uint8Array(blake2b.PERSONALBYTES) 27 | var salt = new Uint8Array(blake2b.SALTBYTES) 28 | 29 | ctx_padded.set(ctx, 0, module.exports.crypto_kdf_CONTEXTBYTES) 30 | STORE64_LE(salt, subkey_id) 31 | 32 | var outlen = Math.min(subkey.length, module.exports.crypto_kdf_BYTES_MAX) 33 | blake2b(outlen, key.subarray(0, module.exports.crypto_kdf_KEYBYTES), salt, ctx_padded, true) 34 | .final(subkey) 35 | } 36 | 37 | module.exports.crypto_kdf_keygen = function crypto_kdf_keygen (out) { 38 | assert(out.length >= module.exports.crypto_kdf_KEYBYTES, 'out.length must be crypto_kdf_KEYBYTES') 39 | randombytes_buf(out.subarray(0, module.exports.crypto_kdf_KEYBYTES)) 40 | } 41 | -------------------------------------------------------------------------------- /crypto_kx.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const { crypto_scalarmult_base } = require('./crypto_scalarmult') 3 | const { crypto_generichash } = require('./crypto_generichash') 4 | const { randombytes_buf } = require('./randombytes') 5 | const assert = require('nanoassert') 6 | 7 | const crypto_kx_SEEDBYTES = 32 8 | const crypto_kx_PUBLICKEYBYTES = 32 9 | const crypto_kx_SECRETKEYBYTES = 32 10 | 11 | function crypto_kx_keypair (pk, sk) { 12 | assert(pk.byteLength === crypto_kx_PUBLICKEYBYTES, "pk must be 'crypto_kx_PUBLICKEYBYTES' bytes") 13 | assert(sk.byteLength === crypto_kx_SECRETKEYBYTES, "sk must be 'crypto_kx_SECRETKEYBYTES' bytes") 14 | 15 | randombytes_buf(sk, crypto_kx_SECRETKEYBYTES) 16 | return crypto_scalarmult_base(pk, sk) 17 | } 18 | 19 | function crypto_kx_seed_keypair (pk, sk, seed) { 20 | assert(pk.byteLength === crypto_kx_PUBLICKEYBYTES, "pk must be 'crypto_kx_PUBLICKEYBYTES' bytes") 21 | assert(sk.byteLength === crypto_kx_SECRETKEYBYTES, "sk must be 'crypto_kx_SECRETKEYBYTES' bytes") 22 | assert(seed.byteLength === crypto_kx_SEEDBYTES, "seed must be 'crypto_kx_SEEDBYTES' bytes") 23 | 24 | crypto_generichash(sk, seed) 25 | return crypto_scalarmult_base(pk, sk) 26 | } 27 | 28 | module.exports = { 29 | crypto_kx_keypair, 30 | crypto_kx_seed_keypair, 31 | crypto_kx_SEEDBYTES, 32 | crypto_kx_SECRETKEYBYTES, 33 | crypto_kx_PUBLICKEYBYTES 34 | } 35 | -------------------------------------------------------------------------------- /crypto_onetimeauth.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const assert = require('nanoassert') 3 | const Poly1305 = require('./internal/poly1305') 4 | const { crypto_verify_16 } = require('./crypto_verify') 5 | 6 | const crypto_onetimeauth_BYTES = 16 7 | const crypto_onetimeauth_KEYBYTES = 32 8 | const crypto_onetimeauth_PRIMITIVE = 'poly1305' 9 | 10 | module.exports = { 11 | crypto_onetimeauth, 12 | crypto_onetimeauth_verify, 13 | crypto_onetimeauth_BYTES, 14 | crypto_onetimeauth_KEYBYTES, 15 | crypto_onetimeauth_PRIMITIVE 16 | } 17 | 18 | function crypto_onetimeauth (mac, msg, key) { 19 | assert(mac.byteLength === crypto_onetimeauth_BYTES, "mac must be 'crypto_onetimeauth_BYTES' bytes") 20 | assert(msg.byteLength != null, 'msg must be buffer') 21 | assert(key.byteLength === crypto_onetimeauth_KEYBYTES, "key must be 'crypto_onetimeauth_KEYBYTES' bytes") 22 | 23 | var s = new Poly1305(key) 24 | s.update(msg, 0, msg.byteLength) 25 | s.finish(mac, 0) 26 | } 27 | 28 | function crypto_onetimeauth_verify (mac, msg, key) { 29 | assert(mac.byteLength === crypto_onetimeauth_BYTES, "mac must be 'crypto_onetimeauth_BYTES' bytes") 30 | assert(msg.byteLength != null, 'msg must be buffer') 31 | assert(key.byteLength === crypto_onetimeauth_KEYBYTES, "key must be 'crypto_onetimeauth_KEYBYTES' bytes") 32 | 33 | var tmp = new Uint8Array(16) 34 | crypto_onetimeauth(tmp, msg, key) 35 | return crypto_verify_16(mac, 0, tmp, 0) 36 | } 37 | -------------------------------------------------------------------------------- /crypto_scalarmult.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase, one-var */ 2 | const { _9, _121665, gf, inv25519, pack25519, unpack25519, sel25519, A, M, Z, S } = require('./internal/ed25519') 3 | 4 | const crypto_scalarmult_BYTES = 32 5 | const crypto_scalarmult_SCALARBYTES = 32 6 | 7 | module.exports = { 8 | crypto_scalarmult, 9 | crypto_scalarmult_base, 10 | crypto_scalarmult_BYTES, 11 | crypto_scalarmult_SCALARBYTES 12 | } 13 | 14 | function crypto_scalarmult (q, n, p) { 15 | check(q, crypto_scalarmult_BYTES) 16 | check(n, crypto_scalarmult_SCALARBYTES) 17 | check(p, crypto_scalarmult_BYTES) 18 | var z = new Uint8Array(32) 19 | var x = new Float64Array(80), r, i 20 | var a = gf(), b = gf(), c = gf(), 21 | d = gf(), e = gf(), f = gf() 22 | for (i = 0; i < 31; i++) z[i] = n[i] 23 | z[31] = (n[31] & 127) | 64 24 | z[0] &= 248 25 | unpack25519(x, p) 26 | for (i = 0; i < 16; i++) { 27 | b[i] = x[i] 28 | d[i] = a[i] = c[i] = 0 29 | } 30 | a[0] = d[0] = 1 31 | for (i = 254; i >= 0; --i) { 32 | r = (z[i >>> 3] >>> (i & 7)) & 1 33 | sel25519(a, b, r) 34 | sel25519(c, d, r) 35 | A(e, a, c) 36 | Z(a, a, c) 37 | A(c, b, d) 38 | Z(b, b, d) 39 | S(d, e) 40 | S(f, a) 41 | M(a, c, a) 42 | M(c, b, e) 43 | A(e, a, c) 44 | Z(a, a, c) 45 | S(b, a) 46 | Z(c, d, f) 47 | M(a, c, _121665) 48 | A(a, a, d) 49 | M(c, c, a) 50 | M(a, d, f) 51 | M(d, b, x) 52 | S(b, e) 53 | sel25519(a, b, r) 54 | sel25519(c, d, r) 55 | } 56 | for (i = 0; i < 16; i++) { 57 | x[i + 16] = a[i] 58 | x[i + 32] = c[i] 59 | x[i + 48] = b[i] 60 | x[i + 64] = d[i] 61 | } 62 | var x32 = x.subarray(32) 63 | var x16 = x.subarray(16) 64 | inv25519(x32, x32) 65 | M(x16, x16, x32) 66 | pack25519(q, x16) 67 | return 0 68 | } 69 | 70 | function crypto_scalarmult_base (q, n) { 71 | return crypto_scalarmult(q, n, _9) 72 | } 73 | 74 | function check (buf, len) { 75 | if (!buf || (len && buf.length < len)) throw new Error('Argument must be a buffer' + (len ? ' of length ' + len : '')) 76 | } 77 | -------------------------------------------------------------------------------- /crypto_secretbox.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const assert = require('nanoassert') 3 | const { crypto_stream, crypto_stream_xor } = require('./crypto_stream') 4 | const { crypto_onetimeauth, crypto_onetimeauth_verify, crypto_onetimeauth_BYTES, crypto_onetimeauth_KEYBYTES } = require('./crypto_onetimeauth') 5 | 6 | const crypto_secretbox_KEYBYTES = 32 7 | const crypto_secretbox_NONCEBYTES = 24 8 | const crypto_secretbox_ZEROBYTES = 32 9 | const crypto_secretbox_BOXZEROBYTES = 16 10 | const crypto_secretbox_MACBYTES = 16 11 | 12 | module.exports = { 13 | crypto_secretbox, 14 | crypto_secretbox_open, 15 | crypto_secretbox_detached, 16 | crypto_secretbox_open_detached, 17 | crypto_secretbox_easy, 18 | crypto_secretbox_open_easy, 19 | crypto_secretbox_KEYBYTES, 20 | crypto_secretbox_NONCEBYTES, 21 | crypto_secretbox_ZEROBYTES, 22 | crypto_secretbox_BOXZEROBYTES, 23 | crypto_secretbox_MACBYTES 24 | } 25 | 26 | function crypto_secretbox (c, m, n, k) { 27 | assert(c.byteLength === m.byteLength, "c must be 'm.byteLength' bytes") 28 | const mlen = m.byteLength 29 | assert(mlen >= crypto_secretbox_ZEROBYTES, "mlen must be at least 'crypto_secretbox_ZEROBYTES'") 30 | assert(n.byteLength === crypto_secretbox_NONCEBYTES, "n must be 'crypto_secretbox_NONCEBYTES' bytes") 31 | assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes") 32 | 33 | crypto_stream_xor(c, m, n, k) 34 | crypto_onetimeauth( 35 | c.subarray(crypto_secretbox_BOXZEROBYTES, crypto_secretbox_BOXZEROBYTES + crypto_onetimeauth_BYTES), 36 | c.subarray(crypto_secretbox_BOXZEROBYTES + crypto_onetimeauth_BYTES, c.byteLength), 37 | c.subarray(0, crypto_onetimeauth_KEYBYTES) 38 | ) 39 | c.fill(0, 0, crypto_secretbox_BOXZEROBYTES) 40 | } 41 | 42 | function crypto_secretbox_open (m, c, n, k) { 43 | assert(c.byteLength === m.byteLength, "c must be 'm.byteLength' bytes") 44 | const mlen = m.byteLength 45 | assert(mlen >= crypto_secretbox_ZEROBYTES, "mlen must be at least 'crypto_secretbox_ZEROBYTES'") 46 | assert(n.byteLength === crypto_secretbox_NONCEBYTES, "n must be 'crypto_secretbox_NONCEBYTES' bytes") 47 | assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes") 48 | 49 | const x = new Uint8Array(crypto_onetimeauth_KEYBYTES) 50 | crypto_stream(x, n, k) 51 | const validMac = crypto_onetimeauth_verify( 52 | c.subarray(crypto_secretbox_BOXZEROBYTES, crypto_secretbox_BOXZEROBYTES + crypto_onetimeauth_BYTES), 53 | c.subarray(crypto_secretbox_BOXZEROBYTES + crypto_onetimeauth_BYTES, c.byteLength), 54 | x 55 | ) 56 | 57 | if (validMac === false) return false 58 | crypto_stream_xor(m, c, n, k) 59 | m.fill(0, 0, 32) 60 | return true 61 | } 62 | 63 | function crypto_secretbox_detached (o, mac, msg, n, k) { 64 | assert(o.byteLength === msg.byteLength, "o must be 'msg.byteLength' bytes") 65 | assert(mac.byteLength === crypto_secretbox_MACBYTES, "mac must be 'crypto_secretbox_MACBYTES' bytes") 66 | assert(n.byteLength === crypto_secretbox_NONCEBYTES, "n must be 'crypto_secretbox_NONCEBYTES' bytes") 67 | assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes") 68 | 69 | const tmp = new Uint8Array(msg.byteLength + mac.byteLength) 70 | crypto_secretbox_easy(tmp, msg, n, k) 71 | mac.set(tmp.subarray(0, mac.byteLength)) 72 | o.set(tmp.subarray(mac.byteLength)) 73 | return true 74 | } 75 | 76 | function crypto_secretbox_open_detached (msg, o, mac, n, k) { 77 | assert(o.byteLength === msg.byteLength, "o must be 'msg.byteLength' bytes") 78 | assert(mac.byteLength === crypto_secretbox_MACBYTES, "mac must be 'crypto_secretbox_MACBYTES' bytes") 79 | assert(n.byteLength === crypto_secretbox_NONCEBYTES, "n must be 'crypto_secretbox_NONCEBYTES' bytes") 80 | assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes") 81 | 82 | const tmp = new Uint8Array(o.byteLength + mac.byteLength) 83 | tmp.set(mac) 84 | tmp.set(o, mac.byteLength) 85 | return crypto_secretbox_open_easy(msg, tmp, n, k) 86 | } 87 | 88 | function crypto_secretbox_easy (o, msg, n, k) { 89 | assert(o.byteLength === msg.byteLength + crypto_secretbox_MACBYTES, "o must be 'msg.byteLength + crypto_secretbox_MACBYTES' bytes") 90 | assert(n.byteLength === crypto_secretbox_NONCEBYTES, "n must be 'crypto_secretbox_NONCEBYTES' bytes") 91 | assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes") 92 | 93 | const m = new Uint8Array(crypto_secretbox_ZEROBYTES + msg.byteLength) 94 | const c = new Uint8Array(m.byteLength) 95 | m.set(msg, crypto_secretbox_ZEROBYTES) 96 | crypto_secretbox(c, m, n, k) 97 | o.set(c.subarray(crypto_secretbox_BOXZEROBYTES)) 98 | } 99 | 100 | function crypto_secretbox_open_easy (msg, box, n, k) { 101 | assert(box.byteLength === msg.byteLength + crypto_secretbox_MACBYTES, "box must be 'msg.byteLength + crypto_secretbox_MACBYTES' bytes") 102 | assert(n.byteLength === crypto_secretbox_NONCEBYTES, "n must be 'crypto_secretbox_NONCEBYTES' bytes") 103 | assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes") 104 | 105 | const c = new Uint8Array(crypto_secretbox_BOXZEROBYTES + box.byteLength) 106 | const m = new Uint8Array(c.byteLength) 107 | c.set(box, crypto_secretbox_BOXZEROBYTES) 108 | if (crypto_secretbox_open(m, c, n, k) === false) return false 109 | msg.set(m.subarray(crypto_secretbox_ZEROBYTES)) 110 | return true 111 | } 112 | -------------------------------------------------------------------------------- /crypto_secretstream.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const assert = require('nanoassert') 3 | const { randombytes_buf } = require('./randombytes') 4 | const { 5 | crypto_stream_chacha20_ietf, 6 | crypto_stream_chacha20_ietf_xor, 7 | crypto_stream_chacha20_ietf_xor_ic, 8 | crypto_stream_chacha20_ietf_KEYBYTES 9 | } = require('./crypto_stream_chacha20') 10 | const { crypto_core_hchacha20, crypto_core_hchacha20_INPUTBYTES } = require('./internal/hchacha20') 11 | const Poly1305 = require('./internal/poly1305') 12 | const { sodium_increment, sodium_is_zero, sodium_memcmp } = require('./helpers') 13 | 14 | const crypto_onetimeauth_poly1305_BYTES = 16 15 | const crypto_secretstream_xchacha20poly1305_COUNTERBYTES = 4 16 | const crypto_secretstream_xchacha20poly1305_INONCEBYTES = 8 17 | const crypto_aead_xchacha20poly1305_ietf_KEYBYTES = 32 18 | const crypto_secretstream_xchacha20poly1305_KEYBYTES = crypto_aead_xchacha20poly1305_ietf_KEYBYTES 19 | const crypto_aead_xchacha20poly1305_ietf_NPUBBYTES = 24 20 | const crypto_secretstream_xchacha20poly1305_HEADERBYTES = crypto_aead_xchacha20poly1305_ietf_NPUBBYTES 21 | const crypto_aead_xchacha20poly1305_ietf_ABYTES = 16 22 | const crypto_secretstream_xchacha20poly1305_ABYTES = 1 + crypto_aead_xchacha20poly1305_ietf_ABYTES 23 | const crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX = Number.MAX_SAFE_INTEGER 24 | const crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX = Number.MAX_SAFE_INTEGER 25 | const crypto_secretstream_xchacha20poly1305_TAGBYTES = 1 26 | const crypto_secretstream_xchacha20poly1305_TAG_MESSAGE = new Uint8Array([0]) 27 | const crypto_secretstream_xchacha20poly1305_TAG_PUSH = new Uint8Array([1]) 28 | const crypto_secretstream_xchacha20poly1305_TAG_REKEY = new Uint8Array([2]) 29 | const crypto_secretstream_xchacha20poly1305_TAG_FINAL = new Uint8Array([crypto_secretstream_xchacha20poly1305_TAG_PUSH | crypto_secretstream_xchacha20poly1305_TAG_REKEY]) 30 | const crypto_secretstream_xchacha20poly1305_STATEBYTES = crypto_secretstream_xchacha20poly1305_KEYBYTES + 31 | crypto_secretstream_xchacha20poly1305_INONCEBYTES + crypto_secretstream_xchacha20poly1305_COUNTERBYTES + 8 32 | 33 | const KEY_OFFSET = 0 34 | const NONCE_OFFSET = crypto_secretstream_xchacha20poly1305_KEYBYTES 35 | const PAD_OFFSET = NONCE_OFFSET + crypto_secretstream_xchacha20poly1305_INONCEBYTES + crypto_secretstream_xchacha20poly1305_COUNTERBYTES 36 | 37 | const _pad0 = new Uint8Array(16) 38 | 39 | function STORE64_LE (dest, int) { 40 | let mul = 1 41 | let i = 0 42 | dest[0] = int & 0xFF 43 | while (++i < 8 && (mul *= 0x100)) { 44 | dest[i] = (int / mul) & 0xFF 45 | } 46 | } 47 | 48 | function crypto_secretstream_xchacha20poly1305_counter_reset (state) { 49 | assert(state.byteLength === crypto_secretstream_xchacha20poly1305_STATEBYTES, 50 | 'state is should be crypto_secretstream_xchacha20poly1305_STATEBYTES long') 51 | 52 | const nonce = state.subarray(NONCE_OFFSET, PAD_OFFSET) 53 | for (let i = 0; i < crypto_secretstream_xchacha20poly1305_COUNTERBYTES; i++) { 54 | nonce[i] = 0 55 | } 56 | nonce[0] = 1 57 | } 58 | 59 | function crypto_secretstream_xchacha20poly1305_keygen (k) { 60 | assert(k.length === crypto_secretstream_xchacha20poly1305_KEYBYTES) 61 | randombytes_buf(k) 62 | } 63 | 64 | function crypto_secretstream_xchacha20poly1305_init_push (state, out, key) { 65 | assert(state.byteLength === crypto_secretstream_xchacha20poly1305_STATEBYTES, 66 | 'state is should be crypto_secretstream_xchacha20poly1305_STATEBYTES long') 67 | assert(out instanceof Uint8Array && out.length === crypto_secretstream_xchacha20poly1305_HEADERBYTES, 'out not byte array of length crypto_secretstream_xchacha20poly1305_HEADERBYTES') 68 | assert(key instanceof Uint8Array && key.length === crypto_secretstream_xchacha20poly1305_KEYBYTES, 'key not byte array of length crypto_secretstream_xchacha20poly1305_KEYBYTES') 69 | 70 | const k = state.subarray(KEY_OFFSET, NONCE_OFFSET) 71 | const nonce = state.subarray(NONCE_OFFSET, PAD_OFFSET) 72 | const pad = state.subarray(PAD_OFFSET) 73 | 74 | randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES) 75 | crypto_core_hchacha20(k, out, key, null) 76 | crypto_secretstream_xchacha20poly1305_counter_reset(state) 77 | for (let i = 0; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { 78 | nonce[i + crypto_secretstream_xchacha20poly1305_COUNTERBYTES] = out[i + crypto_core_hchacha20_INPUTBYTES] 79 | } 80 | pad.fill(0) 81 | } 82 | 83 | function crypto_secretstream_xchacha20poly1305_init_pull (state, _in, key) { 84 | assert(state.byteLength === crypto_secretstream_xchacha20poly1305_STATEBYTES, 85 | 'state is should be crypto_secretstream_xchacha20poly1305_STATEBYTES long') 86 | assert(_in instanceof Uint8Array && _in.length === crypto_secretstream_xchacha20poly1305_HEADERBYTES, 87 | '_in not byte array of length crypto_secretstream_xchacha20poly1305_HEADERBYTES') 88 | assert(key instanceof Uint8Array && key.length === crypto_secretstream_xchacha20poly1305_KEYBYTES, 89 | 'key not byte array of length crypto_secretstream_xchacha20poly1305_KEYBYTES') 90 | 91 | const k = state.subarray(KEY_OFFSET, NONCE_OFFSET) 92 | const nonce = state.subarray(NONCE_OFFSET, PAD_OFFSET) 93 | const pad = state.subarray(PAD_OFFSET) 94 | 95 | crypto_core_hchacha20(k, _in, key, null) 96 | crypto_secretstream_xchacha20poly1305_counter_reset(state) 97 | 98 | for (let i = 0; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { 99 | nonce[i + crypto_secretstream_xchacha20poly1305_COUNTERBYTES] = _in[i + crypto_core_hchacha20_INPUTBYTES] 100 | } 101 | pad.fill(0) 102 | } 103 | 104 | function crypto_secretstream_xchacha20poly1305_rekey (state) { 105 | assert(state.byteLength === crypto_secretstream_xchacha20poly1305_STATEBYTES, 106 | 'state is should be crypto_secretstream_xchacha20poly1305_STATEBYTES long') 107 | 108 | const k = state.subarray(KEY_OFFSET, NONCE_OFFSET) 109 | const nonce = state.subarray(NONCE_OFFSET, PAD_OFFSET) 110 | 111 | const new_key_and_inonce = new Uint8Array( 112 | crypto_stream_chacha20_ietf_KEYBYTES + crypto_secretstream_xchacha20poly1305_INONCEBYTES) 113 | let i 114 | for (i = 0; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { 115 | new_key_and_inonce[i] = k[i] 116 | } 117 | for (i = 0; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { 118 | new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] = 119 | nonce[crypto_secretstream_xchacha20poly1305_COUNTERBYTES + i] 120 | } 121 | crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce, nonce, k) 122 | for (i = 0; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { 123 | k[i] = new_key_and_inonce[i] 124 | } 125 | for (i = 0; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { 126 | nonce[crypto_secretstream_xchacha20poly1305_COUNTERBYTES + i] = 127 | new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] 128 | } 129 | crypto_secretstream_xchacha20poly1305_counter_reset(state) 130 | } 131 | 132 | function crypto_secretstream_xchacha20poly1305_push (state, out, m, ad, tag) { 133 | assert(state.byteLength === crypto_secretstream_xchacha20poly1305_STATEBYTES, 134 | 'state is should be crypto_secretstream_xchacha20poly1305_STATEBYTES long') 135 | if (!ad) ad = new Uint8Array(0) 136 | 137 | const k = state.subarray(KEY_OFFSET, NONCE_OFFSET) 138 | const nonce = state.subarray(NONCE_OFFSET, PAD_OFFSET) 139 | 140 | const block = new Uint8Array(64) 141 | const slen = new Uint8Array(8) 142 | 143 | assert(crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX <= 144 | crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX) 145 | 146 | crypto_stream_chacha20_ietf(block, nonce, k) 147 | const poly = new Poly1305(block) 148 | block.fill(0) 149 | 150 | poly.update(ad, 0, ad.byteLength) 151 | poly.update(_pad0, 0, (0x10 - ad.byteLength) & 0xf) 152 | 153 | block[0] = tag[0] 154 | crypto_stream_chacha20_ietf_xor_ic(block, block, nonce, 1, k) 155 | 156 | poly.update(block, 0, block.byteLength) 157 | out[0] = block[0] 158 | 159 | const c = out.subarray(1, out.byteLength) 160 | crypto_stream_chacha20_ietf_xor_ic(c, m, nonce, 2, k) 161 | poly.update(c, 0, m.byteLength) 162 | poly.update(_pad0, 0, (0x10 - block.byteLength + m.byteLength) & 0xf) 163 | 164 | STORE64_LE(slen, ad.byteLength) 165 | poly.update(slen, 0, slen.byteLength) 166 | STORE64_LE(slen, block.byteLength + m.byteLength) 167 | poly.update(slen, 0, slen.byteLength) 168 | 169 | const mac = out.subarray(1 + m.byteLength, out.byteLength) 170 | poly.finish(mac, 0) 171 | 172 | assert(crypto_onetimeauth_poly1305_BYTES >= 173 | crypto_secretstream_xchacha20poly1305_INONCEBYTES) 174 | xor_buf(nonce.subarray(crypto_secretstream_xchacha20poly1305_COUNTERBYTES, nonce.length), 175 | mac, crypto_secretstream_xchacha20poly1305_INONCEBYTES) 176 | sodium_increment(nonce) 177 | 178 | if ((tag[0] & crypto_secretstream_xchacha20poly1305_TAG_REKEY) !== 0 || 179 | sodium_is_zero(nonce.subarray(0, crypto_secretstream_xchacha20poly1305_COUNTERBYTES))) { 180 | crypto_secretstream_xchacha20poly1305_rekey(state) 181 | } 182 | 183 | return crypto_secretstream_xchacha20poly1305_ABYTES + m.byteLength 184 | } 185 | 186 | function crypto_secretstream_xchacha20poly1305_pull (state, m, tag, _in, ad) { 187 | assert(state.byteLength === crypto_secretstream_xchacha20poly1305_STATEBYTES, 188 | 'state is should be crypto_secretstream_xchacha20poly1305_STATEBYTES long') 189 | if (!ad) ad = new Uint8Array(0) 190 | 191 | const k = state.subarray(KEY_OFFSET, NONCE_OFFSET) 192 | const nonce = state.subarray(NONCE_OFFSET, PAD_OFFSET) 193 | 194 | const block = new Uint8Array(64) 195 | const slen = new Uint8Array(8) 196 | const mac = new Uint8Array(crypto_onetimeauth_poly1305_BYTES) 197 | 198 | assert(_in.byteLength >= crypto_secretstream_xchacha20poly1305_ABYTES, 199 | 'ciphertext is too short.') 200 | 201 | const mlen = _in.byteLength - crypto_secretstream_xchacha20poly1305_ABYTES 202 | crypto_stream_chacha20_ietf(block, nonce, k) 203 | const poly = new Poly1305(block) 204 | block.fill(0) // sodium_memzero(block, sizeof block); 205 | 206 | poly.update(ad, 0, ad.byteLength) 207 | poly.update(_pad0, 0, (0x10 - ad.byteLength) & 0xf) 208 | 209 | block.fill(0) // memset(block, 0, sizeof block); 210 | block[0] = _in[0] 211 | crypto_stream_chacha20_ietf_xor_ic(block, block, nonce, 1, k) 212 | 213 | tag[0] = block[0] 214 | block[0] = _in[0] 215 | poly.update(block, 0, block.byteLength) 216 | 217 | const c = _in.subarray(1, _in.length) 218 | poly.update(c, 0, mlen) 219 | 220 | poly.update(_pad0, 0, (0x10 - block.byteLength + mlen) & 0xf) 221 | 222 | STORE64_LE(slen, ad.byteLength) 223 | poly.update(slen, 0, slen.byteLength) 224 | STORE64_LE(slen, block.byteLength + m.byteLength) 225 | poly.update(slen, 0, slen.byteLength) 226 | 227 | poly.finish(mac, 0) 228 | const stored_mac = _in.subarray(1 + mlen, _in.length) 229 | 230 | if (!sodium_memcmp(mac, stored_mac)) { 231 | mac.fill(0) 232 | throw new Error('MAC could not be verified.') 233 | } 234 | 235 | crypto_stream_chacha20_ietf_xor_ic(m, c.subarray(0, m.length), nonce, 2, k) 236 | xor_buf(nonce.subarray(crypto_secretstream_xchacha20poly1305_COUNTERBYTES, nonce.length), 237 | mac, crypto_secretstream_xchacha20poly1305_INONCEBYTES) 238 | sodium_increment(nonce) 239 | 240 | if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) !== 0 || 241 | sodium_is_zero(nonce.subarray(0, crypto_secretstream_xchacha20poly1305_COUNTERBYTES))) { 242 | crypto_secretstream_xchacha20poly1305_rekey(state) 243 | } 244 | 245 | return mlen 246 | } 247 | 248 | function xor_buf (out, _in, n) { 249 | for (let i = 0; i < n; i++) { 250 | out[i] ^= _in[i] 251 | } 252 | } 253 | 254 | module.exports = { 255 | crypto_secretstream_xchacha20poly1305_keygen, 256 | crypto_secretstream_xchacha20poly1305_init_push, 257 | crypto_secretstream_xchacha20poly1305_init_pull, 258 | crypto_secretstream_xchacha20poly1305_rekey, 259 | crypto_secretstream_xchacha20poly1305_push, 260 | crypto_secretstream_xchacha20poly1305_pull, 261 | crypto_secretstream_xchacha20poly1305_STATEBYTES, 262 | crypto_secretstream_xchacha20poly1305_ABYTES, 263 | crypto_secretstream_xchacha20poly1305_HEADERBYTES, 264 | crypto_secretstream_xchacha20poly1305_KEYBYTES, 265 | crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX, 266 | crypto_secretstream_xchacha20poly1305_TAGBYTES, 267 | crypto_secretstream_xchacha20poly1305_TAG_MESSAGE, 268 | crypto_secretstream_xchacha20poly1305_TAG_PUSH, 269 | crypto_secretstream_xchacha20poly1305_TAG_REKEY, 270 | crypto_secretstream_xchacha20poly1305_TAG_FINAL 271 | } 272 | -------------------------------------------------------------------------------- /crypto_shorthash.js: -------------------------------------------------------------------------------- 1 | var siphash = require('siphash24') 2 | 3 | if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.') 4 | 5 | exports.crypto_shorthash_PRIMITIVE = 'siphash24' 6 | exports.crypto_shorthash_BYTES = siphash.BYTES 7 | exports.crypto_shorthash_KEYBYTES = siphash.KEYBYTES 8 | exports.crypto_shorthash_WASM_SUPPORTED = siphash.WASM_SUPPORTED 9 | exports.crypto_shorthash_WASM_LOADED = siphash.WASM_LOADED 10 | exports.crypto_shorthash = shorthash 11 | 12 | function shorthash (out, data, key, noAssert) { 13 | siphash(data, key, out, noAssert) 14 | } 15 | -------------------------------------------------------------------------------- /crypto_sign.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase, one-var */ 2 | const { crypto_verify_32 } = require('./crypto_verify') 3 | const { crypto_hash } = require('./crypto_hash') 4 | const { 5 | gf, gf0, gf1, D, D2, 6 | X, Y, I, A, Z, M, S, 7 | sel25519, pack25519, 8 | inv25519, unpack25519 9 | } = require('./internal/ed25519') 10 | const { randombytes } = require('./randombytes') 11 | const { crypto_scalarmult_BYTES } = require('./crypto_scalarmult.js') 12 | const { crypto_hash_sha512_BYTES } = require('./crypto_hash.js') 13 | const assert = require('nanoassert') 14 | 15 | const crypto_sign_ed25519_PUBLICKEYBYTES = 32 16 | const crypto_sign_ed25519_SECRETKEYBYTES = 64 17 | const crypto_sign_ed25519_SEEDBYTES = 32 18 | const crypto_sign_ed25519_BYTES = 64 19 | 20 | const crypto_sign_BYTES = crypto_sign_ed25519_BYTES 21 | const crypto_sign_PUBLICKEYBYTES = crypto_sign_ed25519_PUBLICKEYBYTES 22 | const crypto_sign_SECRETKEYBYTES = crypto_sign_ed25519_SECRETKEYBYTES 23 | const crypto_sign_SEEDBYTES = crypto_sign_ed25519_SEEDBYTES 24 | 25 | module.exports = { 26 | crypto_sign_keypair, 27 | crypto_sign_seed_keypair, 28 | crypto_sign, 29 | crypto_sign_detached, 30 | crypto_sign_open, 31 | crypto_sign_verify_detached, 32 | crypto_sign_BYTES, 33 | crypto_sign_PUBLICKEYBYTES, 34 | crypto_sign_SECRETKEYBYTES, 35 | crypto_sign_SEEDBYTES, 36 | crypto_sign_ed25519_PUBLICKEYBYTES, 37 | crypto_sign_ed25519_SECRETKEYBYTES, 38 | crypto_sign_ed25519_SEEDBYTES, 39 | crypto_sign_ed25519_BYTES, 40 | crypto_sign_ed25519_pk_to_curve25519, 41 | crypto_sign_ed25519_sk_to_curve25519, 42 | crypto_sign_ed25519_sk_to_pk, 43 | unpackneg, 44 | pack 45 | } 46 | 47 | function set25519 (r, a) { 48 | for (let i = 0; i < 16; i++) r[i] = a[i] | 0 49 | } 50 | 51 | function pow2523 (o, i) { 52 | var c = gf() 53 | var a 54 | for (a = 0; a < 16; a++) c[a] = i[a] 55 | for (a = 250; a >= 0; a--) { 56 | S(c, c) 57 | if (a !== 1) M(c, c, i) 58 | } 59 | for (a = 0; a < 16; a++) o[a] = c[a] 60 | } 61 | 62 | function add (p, q) { 63 | var a = gf(), b = gf(), c = gf(), 64 | d = gf(), e = gf(), f = gf(), 65 | g = gf(), h = gf(), t = gf() 66 | 67 | Z(a, p[1], p[0]) 68 | Z(t, q[1], q[0]) 69 | M(a, a, t) 70 | A(b, p[0], p[1]) 71 | A(t, q[0], q[1]) 72 | M(b, b, t) 73 | M(c, p[3], q[3]) 74 | M(c, c, D2) 75 | M(d, p[2], q[2]) 76 | A(d, d, d) 77 | Z(e, b, a) 78 | Z(f, d, c) 79 | A(g, d, c) 80 | A(h, b, a) 81 | 82 | M(p[0], e, f) 83 | M(p[1], h, g) 84 | M(p[2], g, f) 85 | M(p[3], e, h) 86 | } 87 | 88 | function cswap (p, q, b) { 89 | var i 90 | for (i = 0; i < 4; i++) { 91 | sel25519(p[i], q[i], b) 92 | } 93 | } 94 | 95 | function pack (r, p) { 96 | var tx = gf(), ty = gf(), zi = gf() 97 | inv25519(zi, p[2]) 98 | M(tx, p[0], zi) 99 | M(ty, p[1], zi) 100 | pack25519(r, ty) 101 | r[31] ^= par25519(tx) << 7 102 | } 103 | 104 | function scalarmult (p, q, s) { 105 | // don't mutate q 106 | var h = [gf(q[0]), gf(q[1]), gf(q[2]), gf(q[3])] 107 | var b, i 108 | set25519(p[0], gf0) 109 | set25519(p[1], gf1) 110 | set25519(p[2], gf1) 111 | set25519(p[3], gf0) 112 | for (i = 255; i >= 0; --i) { 113 | b = (s[(i / 8) | 0] >> (i & 7)) & 1 114 | cswap(p, h, b) 115 | add(h, p) 116 | add(p, p) 117 | cswap(p, h, b) 118 | } 119 | } 120 | 121 | function scalarbase (p, s) { 122 | var q = [gf(), gf(), gf(), gf()] 123 | set25519(q[0], X) 124 | set25519(q[1], Y) 125 | set25519(q[2], gf1) 126 | M(q[3], X, Y) 127 | scalarmult(p, q, s) 128 | } 129 | 130 | function crypto_sign_keypair (pk, sk, seeded) { 131 | check(pk, crypto_sign_PUBLICKEYBYTES) 132 | check(sk, crypto_sign_SECRETKEYBYTES) 133 | 134 | var d = new Uint8Array(64) 135 | var p = [gf(), gf(), gf(), gf()] 136 | var i 137 | 138 | if (!seeded) randombytes(sk, 32) 139 | crypto_hash(d, sk, 32) 140 | d[0] &= 248 141 | d[31] &= 127 142 | d[31] |= 64 143 | 144 | scalarbase(p, d) 145 | pack(pk, p) 146 | 147 | for (i = 0; i < 32; i++) sk[i + 32] = pk[i] 148 | } 149 | 150 | function crypto_sign_seed_keypair (pk, sk, seed) { 151 | check(seed, crypto_sign_SEEDBYTES) 152 | sk.set(seed) 153 | return crypto_sign_keypair(pk, sk, true) 154 | } 155 | 156 | 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]) 157 | 158 | function modL (r, x) { 159 | var carry, i, j, k 160 | for (i = 63; i >= 32; --i) { 161 | carry = 0 162 | for (j = i - 32, k = i - 12; j < k; ++j) { 163 | x[j] += carry - 16 * x[i] * L[j - (i - 32)] 164 | carry = (x[j] + 128) >> 8 165 | x[j] -= carry * 256 166 | } 167 | x[j] += carry 168 | x[i] = 0 169 | } 170 | carry = 0 171 | for (j = 0; j < 32; j++) { 172 | x[j] += carry - (x[31] >> 4) * L[j] 173 | carry = x[j] >> 8 174 | x[j] &= 255 175 | } 176 | for (j = 0; j < 32; j++) x[j] -= carry * L[j] 177 | for (i = 0; i < 32; i++) { 178 | x[i + 1] += x[i] >> 8 179 | r[i] = x[i] & 255 180 | } 181 | } 182 | 183 | function reduce (r) { 184 | var x = new Float64Array(64) 185 | for (let i = 0; i < 64; i++) x[i] = r[i] 186 | for (let i = 0; i < 64; i++) r[i] = 0 187 | modL(r, x) 188 | } 189 | 190 | // Note: difference from C - smlen returned, not passed as argument. 191 | function crypto_sign (sm, m, sk) { 192 | check(sm, crypto_sign_BYTES + m.length) 193 | check(m, 0) 194 | check(sk, crypto_sign_SECRETKEYBYTES) 195 | var n = m.length 196 | 197 | var d = new Uint8Array(64), h = new Uint8Array(64), r = new Uint8Array(64) 198 | var i, j, x = new Float64Array(64) 199 | var p = [gf(), gf(), gf(), gf()] 200 | 201 | crypto_hash(d, sk, 32) 202 | d[0] &= 248 203 | d[31] &= 127 204 | d[31] |= 64 205 | 206 | var smlen = n + 64 207 | for (i = 0; i < n; i++) sm[64 + i] = m[i] 208 | for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i] 209 | 210 | crypto_hash(r, sm.subarray(32), n + 32) 211 | reduce(r) 212 | scalarbase(p, r) 213 | pack(sm, p) 214 | 215 | for (i = 32; i < 64; i++) sm[i] = sk[i] 216 | crypto_hash(h, sm, n + 64) 217 | reduce(h) 218 | 219 | for (i = 0; i < 64; i++) x[i] = 0 220 | for (i = 0; i < 32; i++) x[i] = r[i] 221 | for (i = 0; i < 32; i++) { 222 | for (j = 0; j < 32; j++) { 223 | x[i + j] += h[i] * d[j] 224 | } 225 | } 226 | 227 | modL(sm.subarray(32), x) 228 | return smlen 229 | } 230 | 231 | function crypto_sign_detached (sig, m, sk) { 232 | var sm = new Uint8Array(m.length + crypto_sign_BYTES) 233 | crypto_sign(sm, m, sk) 234 | for (let i = 0; i < crypto_sign_BYTES; i++) sig[i] = sm[i] 235 | } 236 | 237 | function unpackneg (r, p) { 238 | var t = gf(), chk = gf(), num = gf(), 239 | den = gf(), den2 = gf(), den4 = gf(), 240 | den6 = gf() 241 | 242 | set25519(r[2], gf1) 243 | unpack25519(r[1], p) 244 | S(num, r[1]) 245 | M(den, num, D) 246 | Z(num, num, r[2]) 247 | A(den, r[2], den) 248 | 249 | S(den2, den) 250 | S(den4, den2) 251 | M(den6, den4, den2) 252 | M(t, den6, num) 253 | M(t, t, den) 254 | 255 | pow2523(t, t) 256 | M(t, t, num) 257 | M(t, t, den) 258 | M(t, t, den) 259 | M(r[0], t, den) 260 | 261 | S(chk, r[0]) 262 | M(chk, chk, den) 263 | if (!neq25519(chk, num)) M(r[0], r[0], I) 264 | 265 | S(chk, r[0]) 266 | M(chk, chk, den) 267 | if (!neq25519(chk, num)) return false 268 | 269 | if (par25519(r[0]) === (p[31] >> 7)) { 270 | Z(r[0], gf(), r[0]) 271 | } 272 | 273 | M(r[3], r[0], r[1]) 274 | return true 275 | } 276 | 277 | /* eslint-disable no-unused-vars */ 278 | function crypto_sign_open (msg, sm, pk) { 279 | check(msg, sm.length - crypto_sign_BYTES) 280 | check(sm, crypto_sign_BYTES) 281 | check(pk, crypto_sign_PUBLICKEYBYTES) 282 | var n = sm.length 283 | var m = new Uint8Array(sm.length) 284 | 285 | var i, mlen 286 | var t = new Uint8Array(32), h = new Uint8Array(64) 287 | var p = [gf(), gf(), gf(), gf()], 288 | q = [gf(), gf(), gf(), gf()] 289 | 290 | mlen = -1 291 | if (n < 64) return false 292 | 293 | if (!unpackneg(q, pk)) return false 294 | 295 | for (i = 0; i < n; i++) m[i] = sm[i] 296 | for (i = 0; i < 32; i++) m[i + 32] = pk[i] 297 | crypto_hash(h, m, n) 298 | reduce(h) 299 | scalarmult(p, q, h) 300 | 301 | scalarbase(q, sm.subarray(32)) 302 | add(p, q) 303 | pack(t, p) 304 | 305 | n -= 64 306 | if (!crypto_verify_32(sm, 0, t, 0)) { 307 | for (i = 0; i < n; i++) m[i] = 0 308 | return false 309 | // throw new Error('crypto_sign_open failed') 310 | } 311 | 312 | for (i = 0; i < n; i++) msg[i] = sm[i + 64] 313 | mlen = n 314 | return true 315 | } 316 | /* eslint-enable no-unused-vars */ 317 | 318 | function crypto_sign_verify_detached (sig, m, pk) { 319 | check(sig, crypto_sign_BYTES) 320 | var sm = new Uint8Array(m.length + crypto_sign_BYTES) 321 | var i = 0 322 | for (i = 0; i < crypto_sign_BYTES; i++) sm[i] = sig[i] 323 | for (i = 0; i < m.length; i++) sm[i + crypto_sign_BYTES] = m[i] 324 | return crypto_sign_open(m, sm, pk) 325 | } 326 | 327 | function par25519 (a) { 328 | var d = new Uint8Array(32) 329 | pack25519(d, a) 330 | return d[0] & 1 331 | } 332 | 333 | function neq25519 (a, b) { 334 | var c = new Uint8Array(32), d = new Uint8Array(32) 335 | pack25519(c, a) 336 | pack25519(d, b) 337 | return crypto_verify_32(c, 0, d, 0) 338 | } 339 | 340 | function ed25519_mul_l (p, q) { 341 | scalarmult(p, q, L) 342 | } 343 | 344 | function ed25519_is_on_main_subgroup (p) { 345 | var pl = [gf(), gf(), gf(), gf()] 346 | 347 | ed25519_mul_l(pl, p) 348 | 349 | var zero = 0 350 | for (let i = 0; i < 16; i++) { 351 | zero |= (pl[0][i] & 0xffff) 352 | } 353 | 354 | return zero === 0 355 | } 356 | 357 | function crypto_sign_ed25519_pk_to_curve25519 (x25519_pk, ed25519_pk) { 358 | check(x25519_pk, crypto_sign_PUBLICKEYBYTES) 359 | check(ed25519_pk, crypto_sign_ed25519_PUBLICKEYBYTES) 360 | 361 | var a = [gf(), gf(), gf(), gf()] 362 | var x = gf([1]) 363 | var one_minus_y = gf([1]) 364 | 365 | assert( 366 | isSmallOrder(ed25519_pk) && 367 | unpackneg(a, ed25519_pk) && 368 | ed25519_is_on_main_subgroup(a), 'Cannot convert key: bad point') 369 | 370 | for (let i = 0; i < a.length; i++) { 371 | pack25519(x25519_pk, a[i]) 372 | } 373 | 374 | Z(one_minus_y, one_minus_y, a[1]) 375 | A(x, x, a[1]) 376 | inv25519(one_minus_y, one_minus_y) 377 | M(x, x, one_minus_y) 378 | pack25519(x25519_pk, x) 379 | 380 | return 0 381 | } 382 | 383 | function isSmallOrder (s) { 384 | Uint8Array.from([]) 385 | 386 | var bad_points = [ 387 | // 0 (order 4) 388 | Uint8Array.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 389 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 390 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), 391 | 392 | // 1 (order 1) 393 | Uint8Array.from([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 394 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 395 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), 396 | 397 | // 2707385501144840649318225287225658788936804267575313519463743609750303402022(order 8) 398 | Uint8Array.from([0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 399 | 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x05, 0xd3, 400 | 0xc6, 0x33, 0x39, 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05]), 401 | 402 | // 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) 403 | Uint8Array.from([0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 404 | 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 405 | 0x39, 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a]), 406 | 407 | // p-1 (order 2) 408 | Uint8Array.from([0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 409 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 410 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]), 411 | 412 | // p (=0 order 4) 413 | Uint8Array.from([0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 414 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 415 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]), 416 | 417 | // p + 1 (=1 order 1) 418 | Uint8Array.from([0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 419 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 420 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]) 421 | ] 422 | 423 | var c = new Uint8Array(7) 424 | var j 425 | 426 | check(bad_points, 7) 427 | for (let i = 0; i < bad_points.length; i++) { 428 | for (j = 0; j < 31; j++) { 429 | c[i] |= s[j] ^ bad_points[i][j] 430 | } 431 | } 432 | 433 | for (let i = 0; i < bad_points.length; i++) { 434 | c[i] |= (s[j] & 0x7f) ^ bad_points[i][j] 435 | } 436 | 437 | var k = 0 438 | for (let i = 0; i < bad_points.length; i++) { 439 | k |= (c[i] - 1) 440 | } 441 | 442 | return ((k >> 8) & 1) === 0 443 | } 444 | 445 | function crypto_sign_ed25519_sk_to_pk (pk, sk) { 446 | check(pk, crypto_sign_ed25519_PUBLICKEYBYTES) 447 | pk.set(sk.subarray(crypto_sign_ed25519_SEEDBYTES)) 448 | return pk 449 | } 450 | 451 | function crypto_sign_ed25519_sk_to_curve25519 (curveSk, edSk) { 452 | assert(curveSk && curveSk.byteLength === crypto_scalarmult_BYTES, "curveSk must be 'crypto_sign_SECRETKEYBYTES' long") 453 | assert(edSk && edSk.byteLength === crypto_sign_ed25519_SECRETKEYBYTES, "edSk must be 'crypto_sign_ed25519_SECRETKEYBYTES' long") 454 | 455 | var h = new Uint8Array(crypto_hash_sha512_BYTES) 456 | crypto_hash(h, edSk, 32) 457 | 458 | h[0] &= 248 459 | h[31] &= 127 460 | h[31] |= 64 461 | 462 | curveSk.set(h.subarray(0, crypto_scalarmult_BYTES)) 463 | h.fill(0) 464 | return curveSk 465 | } 466 | 467 | function check (buf, len, arg = 'Argument') { 468 | if (!buf || (len && buf.length < len)) throw new Error(arg + ' must be a buffer' + (len ? ' of length ' + len : '')) 469 | } 470 | -------------------------------------------------------------------------------- /crypto_stream.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const xsalsa20 = require('xsalsa20') 3 | 4 | if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.') 5 | 6 | exports.crypto_stream_KEYBYTES = 32 7 | exports.crypto_stream_NONCEBYTES = 24 8 | exports.crypto_stream_PRIMITIVE = 'xsalsa20' 9 | exports.crypto_stream_xsalsa20_MESSAGEBYTES_MAX = Number.MAX_SAFE_INTEGER 10 | 11 | exports.crypto_stream = function (c, nonce, key) { 12 | c.fill(0) 13 | exports.crypto_stream_xor(c, c, nonce, key) 14 | } 15 | 16 | exports.crypto_stream_xor = function (c, m, nonce, key) { 17 | const xor = xsalsa20(nonce, key) 18 | 19 | xor.update(m, c) 20 | xor.final() 21 | } 22 | 23 | exports.crypto_stream_xor_instance = function (nonce, key) { 24 | return new XOR(nonce, key) 25 | } 26 | 27 | function XOR (nonce, key) { 28 | this._instance = xsalsa20(nonce, key) 29 | } 30 | 31 | XOR.prototype.update = function (out, inp) { 32 | this._instance.update(inp, out) 33 | } 34 | 35 | XOR.prototype.final = function () { 36 | this._instance.finalize() 37 | this._instance = null 38 | } 39 | -------------------------------------------------------------------------------- /crypto_stream_chacha20.js: -------------------------------------------------------------------------------- 1 | const assert = require('nanoassert') 2 | const Chacha20 = require('chacha20-universal') 3 | 4 | if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.') 5 | 6 | exports.crypto_stream_chacha20_KEYBYTES = 32 7 | exports.crypto_stream_chacha20_NONCEBYTES = 8 8 | exports.crypto_stream_chacha20_MESSAGEBYTES_MAX = Number.MAX_SAFE_INTEGER 9 | 10 | exports.crypto_stream_chacha20_ietf_KEYBYTES = 32 11 | exports.crypto_stream_chacha20_ietf_NONCEBYTES = 12 12 | exports.crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX = 2 ** 32 13 | 14 | exports.crypto_stream_chacha20 = function (c, n, k) { 15 | c.fill(0) 16 | exports.crypto_stream_chacha20_xor(c, c, n, k) 17 | } 18 | 19 | exports.crypto_stream_chacha20_xor = function (c, m, n, k) { 20 | assert(n.byteLength === exports.crypto_stream_chacha20_NONCEBYTES, 21 | 'n should be crypto_stream_chacha20_NONCEBYTES') 22 | assert(k.byteLength === exports.crypto_stream_chacha20_KEYBYTES, 23 | 'k should be crypto_stream_chacha20_KEYBYTES') 24 | 25 | const xor = new Chacha20(n, k) 26 | xor.update(c, m) 27 | xor.final() 28 | } 29 | 30 | exports.crypto_stream_chacha20_xor_ic = function (c, m, n, ic, k) { 31 | assert(n.byteLength === exports.crypto_stream_chacha20_NONCEBYTES, 32 | 'n should be crypto_stream_chacha20_NONCEBYTES') 33 | assert(k.byteLength === exports.crypto_stream_chacha20_KEYBYTES, 34 | 'k should be crypto_stream_chacha20_KEYBYTES') 35 | 36 | const xor = new Chacha20(n, k, ic) 37 | xor.update(c, m) 38 | xor.final() 39 | } 40 | 41 | exports.crypto_stream_chacha20_xor_instance = function (n, k) { 42 | assert(n.byteLength === exports.crypto_stream_chacha20_NONCEBYTES, 43 | 'n should be crypto_stream_chacha20_NONCEBYTES') 44 | assert(k.byteLength === exports.crypto_stream_chacha20_KEYBYTES, 45 | 'k should be crypto_stream_chacha20_KEYBYTES') 46 | 47 | return new Chacha20(n, k) 48 | } 49 | 50 | exports.crypto_stream_chacha20_ietf = function (c, n, k) { 51 | c.fill(0) 52 | exports.crypto_stream_chacha20_ietf_xor(c, c, n, k) 53 | } 54 | 55 | exports.crypto_stream_chacha20_ietf_xor = function (c, m, n, k) { 56 | assert(n.byteLength === exports.crypto_stream_chacha20_ietf_NONCEBYTES, 57 | 'n should be crypto_stream_chacha20_ietf_NONCEBYTES') 58 | assert(k.byteLength === exports.crypto_stream_chacha20_ietf_KEYBYTES, 59 | 'k should be crypto_stream_chacha20_ietf_KEYBYTES') 60 | 61 | const xor = new Chacha20(n, k) 62 | xor.update(c, m) 63 | xor.final() 64 | } 65 | 66 | exports.crypto_stream_chacha20_ietf_xor_ic = function (c, m, n, ic, k) { 67 | assert(n.byteLength === exports.crypto_stream_chacha20_ietf_NONCEBYTES, 68 | 'n should be crypto_stream_chacha20_ietf_NONCEBYTES') 69 | assert(k.byteLength === exports.crypto_stream_chacha20_ietf_KEYBYTES, 70 | 'k should be crypto_stream_chacha20_ietf_KEYBYTES') 71 | 72 | const xor = new Chacha20(n, k, ic) 73 | xor.update(c, m) 74 | xor.final() 75 | } 76 | 77 | exports.crypto_stream_chacha20_ietf_xor_instance = function (n, k) { 78 | assert(n.byteLength === exports.crypto_stream_chacha20_ietf_NONCEBYTES, 79 | 'n should be crypto_stream_chacha20_ietf_NONCEBYTES') 80 | assert(k.byteLength === exports.crypto_stream_chacha20_ietf_KEYBYTES, 81 | 'k should be crypto_stream_chacha20_ietf_KEYBYTES') 82 | 83 | return new Chacha20(n, k) 84 | } 85 | -------------------------------------------------------------------------------- /crypto_verify.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | module.exports = { 3 | crypto_verify_16, 4 | crypto_verify_32, 5 | crypto_verify_64 6 | } 7 | 8 | function vn (x, xi, y, yi, n) { 9 | var d = 0 10 | for (let i = 0; i < n; i++) d |= x[xi + i] ^ y[yi + i] 11 | return (1 & ((d - 1) >>> 8)) - 1 12 | } 13 | 14 | // Make non enumerable as this is an internal function 15 | Object.defineProperty(module.exports, 'vn', { 16 | value: vn 17 | }) 18 | 19 | function crypto_verify_16 (x, xi, y, yi) { 20 | return vn(x, xi, y, yi, 16) === 0 21 | } 22 | 23 | function crypto_verify_32 (x, xi, y, yi) { 24 | return vn(x, xi, y, yi, 32) === 0 25 | } 26 | 27 | function crypto_verify_64 (x, xi, y, yi) { 28 | return vn(x, xi, y, yi, 64) === 0 29 | } 30 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | const sodium = require('./') 2 | 3 | const key = Buffer.alloc(sodium.crypto_secretbox_KEYBYTES) 4 | const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES) 5 | 6 | sodium.randombytes_buf(key) 7 | sodium.randombytes_buf(nonce) 8 | 9 | const message = Buffer.from('Hello, World!') 10 | const cipher = Buffer.alloc(message.length + sodium.crypto_secretbox_MACBYTES) 11 | 12 | sodium.crypto_secretbox_easy(cipher, message, nonce, key) 13 | 14 | console.log('Encrypted:', cipher) 15 | 16 | const plainText = Buffer.alloc(cipher.length - sodium.crypto_secretbox_MACBYTES) 17 | 18 | sodium.crypto_secretbox_open_easy(plainText, cipher, nonce, key) 19 | 20 | console.log('Plaintext:', plainText.toString()) 21 | 22 | if (typeof window !== 'undefined') window.close() 23 | -------------------------------------------------------------------------------- /helpers.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const assert = require('nanoassert') 3 | const { vn } = require('./crypto_verify') 4 | 5 | function sodium_increment (n) { 6 | const nlen = n.byteLength 7 | var c = 1 8 | for (var i = 0; i < nlen; i++) { 9 | c += n[i] 10 | n[i] = c 11 | c >>= 8 12 | } 13 | } 14 | 15 | function sodium_memcmp (a, b) { 16 | assert(a.byteLength === b.byteLength, 'buffers must be the same size') 17 | 18 | return vn(a, 0, b, 0, a.byteLength) === 0 19 | } 20 | 21 | function sodium_is_zero (arr) { 22 | var d = 0 23 | for (let i = 0; i < arr.length; i++) d |= arr[i] 24 | return d === 0 25 | } 26 | 27 | module.exports = { 28 | sodium_increment, 29 | sodium_memcmp, 30 | sodium_is_zero 31 | } 32 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // Based on https://github.com/dchest/tweetnacl-js/blob/6dcbcaf5f5cbfd313f2dcfe763db35c828c8ff5b/nacl-fast.js. 4 | 5 | // Ported in 2014 by Dmitry Chestnykh and Devi Mandiri. 6 | // Public domain. 7 | // 8 | // Implementation derived from TweetNaCl version 20140427. 9 | // See for details: http://tweetnacl.cr.yp.to/ 10 | 11 | forward(require('./randombytes')) 12 | forward(require('./memory')) 13 | forward(require('./helpers')) 14 | forward(require('./crypto_verify')) 15 | forward(require('./crypto_auth')) 16 | forward(require('./crypto_box')) 17 | forward(require('./crypto_generichash')) 18 | forward(require('./crypto_hash')) 19 | forward(require('./crypto_hash_sha256')) 20 | forward(require('./crypto_kdf')) 21 | forward(require('./crypto_kx')) 22 | forward(require('./crypto_aead')) 23 | forward(require('./crypto_onetimeauth')) 24 | forward(require('./crypto_scalarmult')) 25 | forward(require('./crypto_secretbox')) 26 | forward(require('./crypto_secretstream')) 27 | forward(require('./crypto_shorthash')) 28 | forward(require('./crypto_sign')) 29 | forward(require('./crypto_stream')) 30 | forward(require('./crypto_stream_chacha20')) 31 | 32 | function forward (submodule) { 33 | Object.keys(submodule).forEach(function (prop) { 34 | module.exports[prop] = submodule[prop] 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /internal/ed25519.js: -------------------------------------------------------------------------------- 1 | if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.') 2 | 3 | var gf = function(init) { 4 | var i, r = new Float64Array(16); 5 | if (init) for (i = 0; i < init.length; i++) r[i] = init[i]; 6 | return r; 7 | } 8 | 9 | var _0 = new Uint8Array(16); 10 | var _9 = new Uint8Array(32); _9[0] = 9; 11 | 12 | var gf0 = gf(), 13 | gf1 = gf([1]), 14 | _121665 = gf([0xdb41, 1]), 15 | D = gf([0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]), 16 | D2 = gf([0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]), 17 | X = gf([0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]), 18 | Y = gf([0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]), 19 | I = gf([0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]); 20 | 21 | function A(o, a, b) { 22 | for (var i = 0; i < 16; i++) o[i] = a[i] + b[i]; 23 | } 24 | 25 | function Z(o, a, b) { 26 | for (var i = 0; i < 16; i++) o[i] = a[i] - b[i]; 27 | } 28 | 29 | function M(o, a, b) { 30 | var v, c, 31 | t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, 32 | t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0, 33 | t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0, 34 | t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0, 35 | b0 = b[0], 36 | b1 = b[1], 37 | b2 = b[2], 38 | b3 = b[3], 39 | b4 = b[4], 40 | b5 = b[5], 41 | b6 = b[6], 42 | b7 = b[7], 43 | b8 = b[8], 44 | b9 = b[9], 45 | b10 = b[10], 46 | b11 = b[11], 47 | b12 = b[12], 48 | b13 = b[13], 49 | b14 = b[14], 50 | b15 = b[15]; 51 | 52 | v = a[0]; 53 | t0 += v * b0; 54 | t1 += v * b1; 55 | t2 += v * b2; 56 | t3 += v * b3; 57 | t4 += v * b4; 58 | t5 += v * b5; 59 | t6 += v * b6; 60 | t7 += v * b7; 61 | t8 += v * b8; 62 | t9 += v * b9; 63 | t10 += v * b10; 64 | t11 += v * b11; 65 | t12 += v * b12; 66 | t13 += v * b13; 67 | t14 += v * b14; 68 | t15 += v * b15; 69 | v = a[1]; 70 | t1 += v * b0; 71 | t2 += v * b1; 72 | t3 += v * b2; 73 | t4 += v * b3; 74 | t5 += v * b4; 75 | t6 += v * b5; 76 | t7 += v * b6; 77 | t8 += v * b7; 78 | t9 += v * b8; 79 | t10 += v * b9; 80 | t11 += v * b10; 81 | t12 += v * b11; 82 | t13 += v * b12; 83 | t14 += v * b13; 84 | t15 += v * b14; 85 | t16 += v * b15; 86 | v = a[2]; 87 | t2 += v * b0; 88 | t3 += v * b1; 89 | t4 += v * b2; 90 | t5 += v * b3; 91 | t6 += v * b4; 92 | t7 += v * b5; 93 | t8 += v * b6; 94 | t9 += v * b7; 95 | t10 += v * b8; 96 | t11 += v * b9; 97 | t12 += v * b10; 98 | t13 += v * b11; 99 | t14 += v * b12; 100 | t15 += v * b13; 101 | t16 += v * b14; 102 | t17 += v * b15; 103 | v = a[3]; 104 | t3 += v * b0; 105 | t4 += v * b1; 106 | t5 += v * b2; 107 | t6 += v * b3; 108 | t7 += v * b4; 109 | t8 += v * b5; 110 | t9 += v * b6; 111 | t10 += v * b7; 112 | t11 += v * b8; 113 | t12 += v * b9; 114 | t13 += v * b10; 115 | t14 += v * b11; 116 | t15 += v * b12; 117 | t16 += v * b13; 118 | t17 += v * b14; 119 | t18 += v * b15; 120 | v = a[4]; 121 | t4 += v * b0; 122 | t5 += v * b1; 123 | t6 += v * b2; 124 | t7 += v * b3; 125 | t8 += v * b4; 126 | t9 += v * b5; 127 | t10 += v * b6; 128 | t11 += v * b7; 129 | t12 += v * b8; 130 | t13 += v * b9; 131 | t14 += v * b10; 132 | t15 += v * b11; 133 | t16 += v * b12; 134 | t17 += v * b13; 135 | t18 += v * b14; 136 | t19 += v * b15; 137 | v = a[5]; 138 | t5 += v * b0; 139 | t6 += v * b1; 140 | t7 += v * b2; 141 | t8 += v * b3; 142 | t9 += v * b4; 143 | t10 += v * b5; 144 | t11 += v * b6; 145 | t12 += v * b7; 146 | t13 += v * b8; 147 | t14 += v * b9; 148 | t15 += v * b10; 149 | t16 += v * b11; 150 | t17 += v * b12; 151 | t18 += v * b13; 152 | t19 += v * b14; 153 | t20 += v * b15; 154 | v = a[6]; 155 | t6 += v * b0; 156 | t7 += v * b1; 157 | t8 += v * b2; 158 | t9 += v * b3; 159 | t10 += v * b4; 160 | t11 += v * b5; 161 | t12 += v * b6; 162 | t13 += v * b7; 163 | t14 += v * b8; 164 | t15 += v * b9; 165 | t16 += v * b10; 166 | t17 += v * b11; 167 | t18 += v * b12; 168 | t19 += v * b13; 169 | t20 += v * b14; 170 | t21 += v * b15; 171 | v = a[7]; 172 | t7 += v * b0; 173 | t8 += v * b1; 174 | t9 += v * b2; 175 | t10 += v * b3; 176 | t11 += v * b4; 177 | t12 += v * b5; 178 | t13 += v * b6; 179 | t14 += v * b7; 180 | t15 += v * b8; 181 | t16 += v * b9; 182 | t17 += v * b10; 183 | t18 += v * b11; 184 | t19 += v * b12; 185 | t20 += v * b13; 186 | t21 += v * b14; 187 | t22 += v * b15; 188 | v = a[8]; 189 | t8 += v * b0; 190 | t9 += v * b1; 191 | t10 += v * b2; 192 | t11 += v * b3; 193 | t12 += v * b4; 194 | t13 += v * b5; 195 | t14 += v * b6; 196 | t15 += v * b7; 197 | t16 += v * b8; 198 | t17 += v * b9; 199 | t18 += v * b10; 200 | t19 += v * b11; 201 | t20 += v * b12; 202 | t21 += v * b13; 203 | t22 += v * b14; 204 | t23 += v * b15; 205 | v = a[9]; 206 | t9 += v * b0; 207 | t10 += v * b1; 208 | t11 += v * b2; 209 | t12 += v * b3; 210 | t13 += v * b4; 211 | t14 += v * b5; 212 | t15 += v * b6; 213 | t16 += v * b7; 214 | t17 += v * b8; 215 | t18 += v * b9; 216 | t19 += v * b10; 217 | t20 += v * b11; 218 | t21 += v * b12; 219 | t22 += v * b13; 220 | t23 += v * b14; 221 | t24 += v * b15; 222 | v = a[10]; 223 | t10 += v * b0; 224 | t11 += v * b1; 225 | t12 += v * b2; 226 | t13 += v * b3; 227 | t14 += v * b4; 228 | t15 += v * b5; 229 | t16 += v * b6; 230 | t17 += v * b7; 231 | t18 += v * b8; 232 | t19 += v * b9; 233 | t20 += v * b10; 234 | t21 += v * b11; 235 | t22 += v * b12; 236 | t23 += v * b13; 237 | t24 += v * b14; 238 | t25 += v * b15; 239 | v = a[11]; 240 | t11 += v * b0; 241 | t12 += v * b1; 242 | t13 += v * b2; 243 | t14 += v * b3; 244 | t15 += v * b4; 245 | t16 += v * b5; 246 | t17 += v * b6; 247 | t18 += v * b7; 248 | t19 += v * b8; 249 | t20 += v * b9; 250 | t21 += v * b10; 251 | t22 += v * b11; 252 | t23 += v * b12; 253 | t24 += v * b13; 254 | t25 += v * b14; 255 | t26 += v * b15; 256 | v = a[12]; 257 | t12 += v * b0; 258 | t13 += v * b1; 259 | t14 += v * b2; 260 | t15 += v * b3; 261 | t16 += v * b4; 262 | t17 += v * b5; 263 | t18 += v * b6; 264 | t19 += v * b7; 265 | t20 += v * b8; 266 | t21 += v * b9; 267 | t22 += v * b10; 268 | t23 += v * b11; 269 | t24 += v * b12; 270 | t25 += v * b13; 271 | t26 += v * b14; 272 | t27 += v * b15; 273 | v = a[13]; 274 | t13 += v * b0; 275 | t14 += v * b1; 276 | t15 += v * b2; 277 | t16 += v * b3; 278 | t17 += v * b4; 279 | t18 += v * b5; 280 | t19 += v * b6; 281 | t20 += v * b7; 282 | t21 += v * b8; 283 | t22 += v * b9; 284 | t23 += v * b10; 285 | t24 += v * b11; 286 | t25 += v * b12; 287 | t26 += v * b13; 288 | t27 += v * b14; 289 | t28 += v * b15; 290 | v = a[14]; 291 | t14 += v * b0; 292 | t15 += v * b1; 293 | t16 += v * b2; 294 | t17 += v * b3; 295 | t18 += v * b4; 296 | t19 += v * b5; 297 | t20 += v * b6; 298 | t21 += v * b7; 299 | t22 += v * b8; 300 | t23 += v * b9; 301 | t24 += v * b10; 302 | t25 += v * b11; 303 | t26 += v * b12; 304 | t27 += v * b13; 305 | t28 += v * b14; 306 | t29 += v * b15; 307 | v = a[15]; 308 | t15 += v * b0; 309 | t16 += v * b1; 310 | t17 += v * b2; 311 | t18 += v * b3; 312 | t19 += v * b4; 313 | t20 += v * b5; 314 | t21 += v * b6; 315 | t22 += v * b7; 316 | t23 += v * b8; 317 | t24 += v * b9; 318 | t25 += v * b10; 319 | t26 += v * b11; 320 | t27 += v * b12; 321 | t28 += v * b13; 322 | t29 += v * b14; 323 | t30 += v * b15; 324 | 325 | t0 += 38 * t16; 326 | t1 += 38 * t17; 327 | t2 += 38 * t18; 328 | t3 += 38 * t19; 329 | t4 += 38 * t20; 330 | t5 += 38 * t21; 331 | t6 += 38 * t22; 332 | t7 += 38 * t23; 333 | t8 += 38 * t24; 334 | t9 += 38 * t25; 335 | t10 += 38 * t26; 336 | t11 += 38 * t27; 337 | t12 += 38 * t28; 338 | t13 += 38 * t29; 339 | t14 += 38 * t30; 340 | // t15 left as is 341 | 342 | // first car 343 | c = 1; 344 | v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; 345 | v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; 346 | v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; 347 | v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; 348 | v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; 349 | v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; 350 | v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; 351 | v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; 352 | v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; 353 | v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; 354 | v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; 355 | v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; 356 | v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; 357 | v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; 358 | v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; 359 | v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; 360 | t0 += c-1 + 37 * (c-1); 361 | 362 | // second car 363 | c = 1; 364 | v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; 365 | v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; 366 | v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; 367 | v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; 368 | v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; 369 | v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; 370 | v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; 371 | v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; 372 | v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; 373 | v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; 374 | v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; 375 | v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; 376 | v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; 377 | v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; 378 | v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; 379 | v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; 380 | t0 += c-1 + 37 * (c-1); 381 | 382 | o[ 0] = t0; 383 | o[ 1] = t1; 384 | o[ 2] = t2; 385 | o[ 3] = t3; 386 | o[ 4] = t4; 387 | o[ 5] = t5; 388 | o[ 6] = t6; 389 | o[ 7] = t7; 390 | o[ 8] = t8; 391 | o[ 9] = t9; 392 | o[10] = t10; 393 | o[11] = t11; 394 | o[12] = t12; 395 | o[13] = t13; 396 | o[14] = t14; 397 | o[15] = t15; 398 | } 399 | 400 | function S(o, a) { 401 | M(o, a, a); 402 | } 403 | 404 | function sel25519(p, q, b) { 405 | var t, c = ~(b-1); 406 | for (var i = 0; i < 16; i++) { 407 | t = c & (p[i] ^ q[i]); 408 | p[i] ^= t; 409 | q[i] ^= t; 410 | } 411 | } 412 | 413 | function pack25519(o, n) { 414 | var i, j, b; 415 | var m = gf(), t = gf(); 416 | for (i = 0; i < 16; i++) t[i] = n[i]; 417 | car25519(t); 418 | car25519(t); 419 | car25519(t); 420 | for (j = 0; j < 2; j++) { 421 | m[0] = t[0] - 0xffed; 422 | for (i = 1; i < 15; i++) { 423 | m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1); 424 | m[i-1] &= 0xffff; 425 | } 426 | m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1); 427 | b = (m[15]>>16) & 1; 428 | m[14] &= 0xffff; 429 | sel25519(t, m, 1-b); 430 | } 431 | for (i = 0; i < 16; i++) { 432 | o[2*i] = t[i] & 0xff; 433 | o[2*i+1] = t[i]>>8; 434 | } 435 | } 436 | 437 | function unpack25519(o, n) { 438 | var i; 439 | for (i = 0; i < 16; i++) o[i] = n[2*i] + (n[2*i+1] << 8); 440 | o[15] &= 0x7fff; 441 | } 442 | 443 | function inv25519(o, i) { 444 | var c = gf(); 445 | var a; 446 | for (a = 0; a < 16; a++) c[a] = i[a]; 447 | for (a = 253; a >= 0; a--) { 448 | S(c, c); 449 | if(a !== 2 && a !== 4) M(c, c, i); 450 | } 451 | for (a = 0; a < 16; a++) o[a] = c[a]; 452 | } 453 | 454 | function car25519(o) { 455 | var i, v, c = 1; 456 | for (i = 0; i < 16; i++) { 457 | v = o[i] + c + 65535; 458 | c = Math.floor(v / 65536); 459 | o[i] = v - c * 65536; 460 | } 461 | o[0] += c-1 + 37 * (c-1); 462 | } 463 | 464 | module.exports = { 465 | gf, 466 | A, 467 | Z, 468 | M, 469 | S, 470 | sel25519, 471 | pack25519, 472 | unpack25519, 473 | inv25519, 474 | gf0, 475 | gf1, 476 | _9, 477 | _121665, 478 | D, 479 | D2, 480 | X, 481 | Y, 482 | I 483 | } 484 | -------------------------------------------------------------------------------- /internal/hchacha20.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const { sodium_malloc } = require('../memory') 3 | const assert = require('nanoassert') 4 | 5 | if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.') 6 | 7 | const crypto_core_hchacha20_OUTPUTBYTES = 32 8 | const crypto_core_hchacha20_INPUTBYTES = 16 9 | const crypto_core_hchacha20_KEYBYTES = 32 10 | const crypto_core_hchacha20_CONSTBYTES = 16 11 | 12 | function ROTL32 (x, b) { 13 | x &= 0xFFFFFFFF 14 | b &= 0xFFFFFFFF 15 | return (x << b) | (x >>> (32 - b)) 16 | } 17 | 18 | function LOAD32_LE (src, offset) { 19 | assert(src instanceof Uint8Array, 'src not byte array') 20 | let w = src[offset] 21 | w |= src[offset + 1] << 8 22 | w |= src[offset + 2] << 16 23 | w |= src[offset + 3] << 24 24 | return w 25 | } 26 | 27 | function STORE32_LE (dest, int, offset) { 28 | assert(dest instanceof Uint8Array, 'dest not byte array') 29 | var mul = 1 30 | var i = 0 31 | dest[offset] = int & 0xFF // grab bottom byte 32 | while (++i < 4 && (mul *= 0x100)) { 33 | dest[offset + i] = (int / mul) & 0xFF 34 | } 35 | } 36 | 37 | function QUARTERROUND (l, A, B, C, D) { 38 | l[A] += l[B] 39 | l[D] = ROTL32(l[D] ^ l[A], 16) 40 | l[C] += l[D] 41 | l[B] = ROTL32(l[B] ^ l[C], 12) 42 | l[A] += l[B] 43 | l[D] = ROTL32(l[D] ^ l[A], 8) 44 | l[C] += l[D] 45 | l[B] = ROTL32(l[B] ^ l[C], 7) 46 | } 47 | 48 | function crypto_core_hchacha20 (out, _in, k, c) { 49 | assert(out instanceof Uint8Array && out.length === 32, 'out is not an array of 32 bytes') 50 | assert(k instanceof Uint8Array && k.length === 32, 'k is not an array of 32 bytes') 51 | assert(c === null || (c instanceof Uint8Array && c.length === 16), 'c is not null or an array of 16 bytes') 52 | 53 | let i = 0 54 | const x = new Uint32Array(16) 55 | if (!c) { 56 | x[0] = 0x61707865 57 | x[1] = 0x3320646E 58 | x[2] = 0x79622D32 59 | x[3] = 0x6B206574 60 | } else { 61 | x[0] = LOAD32_LE(c, 0) 62 | x[1] = LOAD32_LE(c, 4) 63 | x[2] = LOAD32_LE(c, 8) 64 | x[3] = LOAD32_LE(c, 12) 65 | } 66 | x[4] = LOAD32_LE(k, 0) 67 | x[5] = LOAD32_LE(k, 4) 68 | x[6] = LOAD32_LE(k, 8) 69 | x[7] = LOAD32_LE(k, 12) 70 | x[8] = LOAD32_LE(k, 16) 71 | x[9] = LOAD32_LE(k, 20) 72 | x[10] = LOAD32_LE(k, 24) 73 | x[11] = LOAD32_LE(k, 28) 74 | x[12] = LOAD32_LE(_in, 0) 75 | x[13] = LOAD32_LE(_in, 4) 76 | x[14] = LOAD32_LE(_in, 8) 77 | x[15] = LOAD32_LE(_in, 12) 78 | 79 | for (i = 0; i < 10; i++) { 80 | QUARTERROUND(x, 0, 4, 8, 12) 81 | QUARTERROUND(x, 1, 5, 9, 13) 82 | QUARTERROUND(x, 2, 6, 10, 14) 83 | QUARTERROUND(x, 3, 7, 11, 15) 84 | QUARTERROUND(x, 0, 5, 10, 15) 85 | QUARTERROUND(x, 1, 6, 11, 12) 86 | QUARTERROUND(x, 2, 7, 8, 13) 87 | QUARTERROUND(x, 3, 4, 9, 14) 88 | } 89 | 90 | STORE32_LE(out, x[0], 0) 91 | STORE32_LE(out, x[1], 4) 92 | STORE32_LE(out, x[2], 8) 93 | STORE32_LE(out, x[3], 12) 94 | STORE32_LE(out, x[12], 16) 95 | STORE32_LE(out, x[13], 20) 96 | STORE32_LE(out, x[14], 24) 97 | STORE32_LE(out, x[15], 28) 98 | 99 | return 0 100 | } 101 | 102 | function crypto_core_hchacha20_outputbytes () { 103 | return crypto_core_hchacha20_OUTPUTBYTES 104 | } 105 | 106 | function crypto_core_hchacha20_inputbytes () { 107 | return crypto_core_hchacha20_INPUTBYTES 108 | } 109 | 110 | function crypto_core_hchacha20_keybytes () { 111 | return crypto_core_hchacha20_KEYBYTES 112 | } 113 | 114 | function crypto_core_hchacha20_constbytes () { 115 | return crypto_core_hchacha20_CONSTBYTES 116 | } 117 | 118 | module.exports = { 119 | crypto_core_hchacha20_INPUTBYTES, 120 | LOAD32_LE, 121 | STORE32_LE, 122 | QUARTERROUND, 123 | crypto_core_hchacha20, 124 | crypto_core_hchacha20_outputbytes, 125 | crypto_core_hchacha20_inputbytes, 126 | crypto_core_hchacha20_keybytes, 127 | crypto_core_hchacha20_constbytes 128 | } 129 | -------------------------------------------------------------------------------- /internal/poly1305.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Port of Andrew Moon's Poly1305-donna-16. Public domain. 3 | * https://github.com/floodyberry/poly1305-donna 4 | */ 5 | 6 | if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is not supported.') 7 | 8 | var poly1305 = function(key) { 9 | this.buffer = new Uint8Array(16); 10 | this.r = new Uint16Array(10); 11 | this.h = new Uint16Array(10); 12 | this.pad = new Uint16Array(8); 13 | this.leftover = 0; 14 | this.fin = 0; 15 | 16 | var t0, t1, t2, t3, t4, t5, t6, t7; 17 | 18 | t0 = key[ 0] & 0xff | (key[ 1] & 0xff) << 8; this.r[0] = ( t0 ) & 0x1fff; 19 | t1 = key[ 2] & 0xff | (key[ 3] & 0xff) << 8; this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff; 20 | t2 = key[ 4] & 0xff | (key[ 5] & 0xff) << 8; this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03; 21 | t3 = key[ 6] & 0xff | (key[ 7] & 0xff) << 8; this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff; 22 | t4 = key[ 8] & 0xff | (key[ 9] & 0xff) << 8; this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff; 23 | this.r[5] = ((t4 >>> 1)) & 0x1ffe; 24 | t5 = key[10] & 0xff | (key[11] & 0xff) << 8; this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff; 25 | t6 = key[12] & 0xff | (key[13] & 0xff) << 8; this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81; 26 | t7 = key[14] & 0xff | (key[15] & 0xff) << 8; this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff; 27 | this.r[9] = ((t7 >>> 5)) & 0x007f; 28 | 29 | this.pad[0] = key[16] & 0xff | (key[17] & 0xff) << 8; 30 | this.pad[1] = key[18] & 0xff | (key[19] & 0xff) << 8; 31 | this.pad[2] = key[20] & 0xff | (key[21] & 0xff) << 8; 32 | this.pad[3] = key[22] & 0xff | (key[23] & 0xff) << 8; 33 | this.pad[4] = key[24] & 0xff | (key[25] & 0xff) << 8; 34 | this.pad[5] = key[26] & 0xff | (key[27] & 0xff) << 8; 35 | this.pad[6] = key[28] & 0xff | (key[29] & 0xff) << 8; 36 | this.pad[7] = key[30] & 0xff | (key[31] & 0xff) << 8; 37 | }; 38 | 39 | poly1305.prototype.blocks = function(m, mpos, bytes) { 40 | var hibit = this.fin ? 0 : (1 << 11); 41 | var t0, t1, t2, t3, t4, t5, t6, t7, c; 42 | var d0, d1, d2, d3, d4, d5, d6, d7, d8, d9; 43 | 44 | var h0 = this.h[0], 45 | h1 = this.h[1], 46 | h2 = this.h[2], 47 | h3 = this.h[3], 48 | h4 = this.h[4], 49 | h5 = this.h[5], 50 | h6 = this.h[6], 51 | h7 = this.h[7], 52 | h8 = this.h[8], 53 | h9 = this.h[9]; 54 | 55 | var r0 = this.r[0], 56 | r1 = this.r[1], 57 | r2 = this.r[2], 58 | r3 = this.r[3], 59 | r4 = this.r[4], 60 | r5 = this.r[5], 61 | r6 = this.r[6], 62 | r7 = this.r[7], 63 | r8 = this.r[8], 64 | r9 = this.r[9]; 65 | 66 | while (bytes >= 16) { 67 | t0 = m[mpos+ 0] & 0xff | (m[mpos+ 1] & 0xff) << 8; h0 += ( t0 ) & 0x1fff; 68 | t1 = m[mpos+ 2] & 0xff | (m[mpos+ 3] & 0xff) << 8; h1 += ((t0 >>> 13) | (t1 << 3)) & 0x1fff; 69 | t2 = m[mpos+ 4] & 0xff | (m[mpos+ 5] & 0xff) << 8; h2 += ((t1 >>> 10) | (t2 << 6)) & 0x1fff; 70 | t3 = m[mpos+ 6] & 0xff | (m[mpos+ 7] & 0xff) << 8; h3 += ((t2 >>> 7) | (t3 << 9)) & 0x1fff; 71 | t4 = m[mpos+ 8] & 0xff | (m[mpos+ 9] & 0xff) << 8; h4 += ((t3 >>> 4) | (t4 << 12)) & 0x1fff; 72 | h5 += ((t4 >>> 1)) & 0x1fff; 73 | t5 = m[mpos+10] & 0xff | (m[mpos+11] & 0xff) << 8; h6 += ((t4 >>> 14) | (t5 << 2)) & 0x1fff; 74 | t6 = m[mpos+12] & 0xff | (m[mpos+13] & 0xff) << 8; h7 += ((t5 >>> 11) | (t6 << 5)) & 0x1fff; 75 | t7 = m[mpos+14] & 0xff | (m[mpos+15] & 0xff) << 8; h8 += ((t6 >>> 8) | (t7 << 8)) & 0x1fff; 76 | h9 += ((t7 >>> 5)) | hibit; 77 | 78 | c = 0; 79 | 80 | d0 = c; 81 | d0 += h0 * r0; 82 | d0 += h1 * (5 * r9); 83 | d0 += h2 * (5 * r8); 84 | d0 += h3 * (5 * r7); 85 | d0 += h4 * (5 * r6); 86 | c = (d0 >>> 13); d0 &= 0x1fff; 87 | d0 += h5 * (5 * r5); 88 | d0 += h6 * (5 * r4); 89 | d0 += h7 * (5 * r3); 90 | d0 += h8 * (5 * r2); 91 | d0 += h9 * (5 * r1); 92 | c += (d0 >>> 13); d0 &= 0x1fff; 93 | 94 | d1 = c; 95 | d1 += h0 * r1; 96 | d1 += h1 * r0; 97 | d1 += h2 * (5 * r9); 98 | d1 += h3 * (5 * r8); 99 | d1 += h4 * (5 * r7); 100 | c = (d1 >>> 13); d1 &= 0x1fff; 101 | d1 += h5 * (5 * r6); 102 | d1 += h6 * (5 * r5); 103 | d1 += h7 * (5 * r4); 104 | d1 += h8 * (5 * r3); 105 | d1 += h9 * (5 * r2); 106 | c += (d1 >>> 13); d1 &= 0x1fff; 107 | 108 | d2 = c; 109 | d2 += h0 * r2; 110 | d2 += h1 * r1; 111 | d2 += h2 * r0; 112 | d2 += h3 * (5 * r9); 113 | d2 += h4 * (5 * r8); 114 | c = (d2 >>> 13); d2 &= 0x1fff; 115 | d2 += h5 * (5 * r7); 116 | d2 += h6 * (5 * r6); 117 | d2 += h7 * (5 * r5); 118 | d2 += h8 * (5 * r4); 119 | d2 += h9 * (5 * r3); 120 | c += (d2 >>> 13); d2 &= 0x1fff; 121 | 122 | d3 = c; 123 | d3 += h0 * r3; 124 | d3 += h1 * r2; 125 | d3 += h2 * r1; 126 | d3 += h3 * r0; 127 | d3 += h4 * (5 * r9); 128 | c = (d3 >>> 13); d3 &= 0x1fff; 129 | d3 += h5 * (5 * r8); 130 | d3 += h6 * (5 * r7); 131 | d3 += h7 * (5 * r6); 132 | d3 += h8 * (5 * r5); 133 | d3 += h9 * (5 * r4); 134 | c += (d3 >>> 13); d3 &= 0x1fff; 135 | 136 | d4 = c; 137 | d4 += h0 * r4; 138 | d4 += h1 * r3; 139 | d4 += h2 * r2; 140 | d4 += h3 * r1; 141 | d4 += h4 * r0; 142 | c = (d4 >>> 13); d4 &= 0x1fff; 143 | d4 += h5 * (5 * r9); 144 | d4 += h6 * (5 * r8); 145 | d4 += h7 * (5 * r7); 146 | d4 += h8 * (5 * r6); 147 | d4 += h9 * (5 * r5); 148 | c += (d4 >>> 13); d4 &= 0x1fff; 149 | 150 | d5 = c; 151 | d5 += h0 * r5; 152 | d5 += h1 * r4; 153 | d5 += h2 * r3; 154 | d5 += h3 * r2; 155 | d5 += h4 * r1; 156 | c = (d5 >>> 13); d5 &= 0x1fff; 157 | d5 += h5 * r0; 158 | d5 += h6 * (5 * r9); 159 | d5 += h7 * (5 * r8); 160 | d5 += h8 * (5 * r7); 161 | d5 += h9 * (5 * r6); 162 | c += (d5 >>> 13); d5 &= 0x1fff; 163 | 164 | d6 = c; 165 | d6 += h0 * r6; 166 | d6 += h1 * r5; 167 | d6 += h2 * r4; 168 | d6 += h3 * r3; 169 | d6 += h4 * r2; 170 | c = (d6 >>> 13); d6 &= 0x1fff; 171 | d6 += h5 * r1; 172 | d6 += h6 * r0; 173 | d6 += h7 * (5 * r9); 174 | d6 += h8 * (5 * r8); 175 | d6 += h9 * (5 * r7); 176 | c += (d6 >>> 13); d6 &= 0x1fff; 177 | 178 | d7 = c; 179 | d7 += h0 * r7; 180 | d7 += h1 * r6; 181 | d7 += h2 * r5; 182 | d7 += h3 * r4; 183 | d7 += h4 * r3; 184 | c = (d7 >>> 13); d7 &= 0x1fff; 185 | d7 += h5 * r2; 186 | d7 += h6 * r1; 187 | d7 += h7 * r0; 188 | d7 += h8 * (5 * r9); 189 | d7 += h9 * (5 * r8); 190 | c += (d7 >>> 13); d7 &= 0x1fff; 191 | 192 | d8 = c; 193 | d8 += h0 * r8; 194 | d8 += h1 * r7; 195 | d8 += h2 * r6; 196 | d8 += h3 * r5; 197 | d8 += h4 * r4; 198 | c = (d8 >>> 13); d8 &= 0x1fff; 199 | d8 += h5 * r3; 200 | d8 += h6 * r2; 201 | d8 += h7 * r1; 202 | d8 += h8 * r0; 203 | d8 += h9 * (5 * r9); 204 | c += (d8 >>> 13); d8 &= 0x1fff; 205 | 206 | d9 = c; 207 | d9 += h0 * r9; 208 | d9 += h1 * r8; 209 | d9 += h2 * r7; 210 | d9 += h3 * r6; 211 | d9 += h4 * r5; 212 | c = (d9 >>> 13); d9 &= 0x1fff; 213 | d9 += h5 * r4; 214 | d9 += h6 * r3; 215 | d9 += h7 * r2; 216 | d9 += h8 * r1; 217 | d9 += h9 * r0; 218 | c += (d9 >>> 13); d9 &= 0x1fff; 219 | 220 | c = (((c << 2) + c)) | 0; 221 | c = (c + d0) | 0; 222 | d0 = c & 0x1fff; 223 | c = (c >>> 13); 224 | d1 += c; 225 | 226 | h0 = d0; 227 | h1 = d1; 228 | h2 = d2; 229 | h3 = d3; 230 | h4 = d4; 231 | h5 = d5; 232 | h6 = d6; 233 | h7 = d7; 234 | h8 = d8; 235 | h9 = d9; 236 | 237 | mpos += 16; 238 | bytes -= 16; 239 | } 240 | this.h[0] = h0; 241 | this.h[1] = h1; 242 | this.h[2] = h2; 243 | this.h[3] = h3; 244 | this.h[4] = h4; 245 | this.h[5] = h5; 246 | this.h[6] = h6; 247 | this.h[7] = h7; 248 | this.h[8] = h8; 249 | this.h[9] = h9; 250 | }; 251 | 252 | poly1305.prototype.finish = function(mac, macpos) { 253 | var g = new Uint16Array(10); 254 | var c, mask, f, i; 255 | 256 | if (this.leftover) { 257 | i = this.leftover; 258 | this.buffer[i++] = 1; 259 | for (; i < 16; i++) this.buffer[i] = 0; 260 | this.fin = 1; 261 | this.blocks(this.buffer, 0, 16); 262 | } 263 | 264 | c = this.h[1] >>> 13; 265 | this.h[1] &= 0x1fff; 266 | for (i = 2; i < 10; i++) { 267 | this.h[i] += c; 268 | c = this.h[i] >>> 13; 269 | this.h[i] &= 0x1fff; 270 | } 271 | this.h[0] += (c * 5); 272 | c = this.h[0] >>> 13; 273 | this.h[0] &= 0x1fff; 274 | this.h[1] += c; 275 | c = this.h[1] >>> 13; 276 | this.h[1] &= 0x1fff; 277 | this.h[2] += c; 278 | 279 | g[0] = this.h[0] + 5; 280 | c = g[0] >>> 13; 281 | g[0] &= 0x1fff; 282 | for (i = 1; i < 10; i++) { 283 | g[i] = this.h[i] + c; 284 | c = g[i] >>> 13; 285 | g[i] &= 0x1fff; 286 | } 287 | g[9] -= (1 << 13); 288 | 289 | mask = (c ^ 1) - 1; 290 | for (i = 0; i < 10; i++) g[i] &= mask; 291 | mask = ~mask; 292 | for (i = 0; i < 10; i++) this.h[i] = (this.h[i] & mask) | g[i]; 293 | 294 | this.h[0] = ((this.h[0] ) | (this.h[1] << 13) ) & 0xffff; 295 | this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10) ) & 0xffff; 296 | this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7) ) & 0xffff; 297 | this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4) ) & 0xffff; 298 | this.h[4] = ((this.h[4] >>> 12) | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff; 299 | this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11) ) & 0xffff; 300 | this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8) ) & 0xffff; 301 | this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5) ) & 0xffff; 302 | 303 | f = this.h[0] + this.pad[0]; 304 | this.h[0] = f & 0xffff; 305 | for (i = 1; i < 8; i++) { 306 | f = (((this.h[i] + this.pad[i]) | 0) + (f >>> 16)) | 0; 307 | this.h[i] = f & 0xffff; 308 | } 309 | 310 | mac[macpos+ 0] = (this.h[0] >>> 0) & 0xff; 311 | mac[macpos+ 1] = (this.h[0] >>> 8) & 0xff; 312 | mac[macpos+ 2] = (this.h[1] >>> 0) & 0xff; 313 | mac[macpos+ 3] = (this.h[1] >>> 8) & 0xff; 314 | mac[macpos+ 4] = (this.h[2] >>> 0) & 0xff; 315 | mac[macpos+ 5] = (this.h[2] >>> 8) & 0xff; 316 | mac[macpos+ 6] = (this.h[3] >>> 0) & 0xff; 317 | mac[macpos+ 7] = (this.h[3] >>> 8) & 0xff; 318 | mac[macpos+ 8] = (this.h[4] >>> 0) & 0xff; 319 | mac[macpos+ 9] = (this.h[4] >>> 8) & 0xff; 320 | mac[macpos+10] = (this.h[5] >>> 0) & 0xff; 321 | mac[macpos+11] = (this.h[5] >>> 8) & 0xff; 322 | mac[macpos+12] = (this.h[6] >>> 0) & 0xff; 323 | mac[macpos+13] = (this.h[6] >>> 8) & 0xff; 324 | mac[macpos+14] = (this.h[7] >>> 0) & 0xff; 325 | mac[macpos+15] = (this.h[7] >>> 8) & 0xff; 326 | }; 327 | 328 | poly1305.prototype.update = function(m, mpos, bytes) { 329 | var i, want; 330 | 331 | if (this.leftover) { 332 | want = (16 - this.leftover); 333 | if (want > bytes) 334 | want = bytes; 335 | for (i = 0; i < want; i++) 336 | this.buffer[this.leftover + i] = m[mpos+i]; 337 | bytes -= want; 338 | mpos += want; 339 | this.leftover += want; 340 | if (this.leftover < 16) 341 | return; 342 | this.blocks(this.buffer, 0, 16); 343 | this.leftover = 0; 344 | } 345 | 346 | if (bytes >= 16) { 347 | want = bytes - (bytes % 16); 348 | this.blocks(m, mpos, want); 349 | mpos += want; 350 | bytes -= want; 351 | } 352 | 353 | if (bytes) { 354 | for (i = 0; i < bytes; i++) 355 | this.buffer[this.leftover + i] = m[mpos+i]; 356 | this.leftover += bytes; 357 | } 358 | }; 359 | 360 | module.exports = poly1305 361 | -------------------------------------------------------------------------------- /memory.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | 3 | function sodium_malloc (n) { 4 | return new Uint8Array(n) 5 | } 6 | 7 | function sodium_free (n) { 8 | sodium_memzero(n) 9 | loadSink().port1.postMessage(n.buffer, [n.buffer]) 10 | } 11 | 12 | function sodium_memzero (arr) { 13 | arr.fill(0) 14 | } 15 | 16 | var sink 17 | 18 | function loadSink () { 19 | if (sink) return sink 20 | var MessageChannel = globalThis.MessageChannel 21 | if (MessageChannel == null) ({ MessageChannel } = require('worker' + '_threads')) 22 | sink = new MessageChannel() 23 | return sink 24 | } 25 | 26 | module.exports = { 27 | sodium_malloc, 28 | sodium_free, 29 | sodium_memzero 30 | } 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sodium-javascript", 3 | "version": "0.8.0", 4 | "description": "WIP - a pure javascript version of sodium-native", 5 | "main": "index.js", 6 | "dependencies": { 7 | "blake2b": "^2.1.1", 8 | "chacha20-universal": "^1.0.4", 9 | "nanoassert": "^2.0.0", 10 | "sha256-universal": "^1.1.0", 11 | "sha512-universal": "^1.1.0", 12 | "siphash24": "^1.0.1", 13 | "xsalsa20": "^1.0.0" 14 | }, 15 | "devDependencies": { 16 | "brittle": "^3.2.1", 17 | "browserify": "^16.5.1", 18 | "standard": "^15.0.1" 19 | }, 20 | "standard": { 21 | "ignore": [ 22 | "/internal/**/*.js", 23 | "/test/fixtures/*.js" 24 | ], 25 | "rules": { 26 | "camelcase": "off" 27 | } 28 | }, 29 | "browser": { 30 | "crypto": false, 31 | "worker_threads": false 32 | }, 33 | "scripts": { 34 | "pretest": "standard", 35 | "test": "brittle test/*.js", 36 | "test-browser": "browserify test.js | tape-run" 37 | }, 38 | "repository": { 39 | "type": "git", 40 | "url": "git+https://github.com/sodium-friends/sodium-javascript.git" 41 | }, 42 | "contributors": [ 43 | "Christophe Diederichs ", 44 | "Emil Bay (http://bayes.dk)", 45 | "Mathias Buus (https://mafinto.sh)" 46 | ], 47 | "license": "MIT", 48 | "bugs": { 49 | "url": "https://github.com/sodium-friends/sodium-javascript/issues" 50 | }, 51 | "homepage": "https://github.com/sodium-friends/sodium-javascript#readme" 52 | } 53 | -------------------------------------------------------------------------------- /randombytes.js: -------------------------------------------------------------------------------- 1 | var assert = require('nanoassert') 2 | 3 | var randombytes = (function () { 4 | var QUOTA = 65536 // limit for QuotaExceededException 5 | var crypto = globalThis.crypto || globalThis.msCrypto 6 | 7 | function browserBytes (out, n) { 8 | for (let i = 0; i < n; i += QUOTA) { 9 | crypto.getRandomValues(new Uint8Array(out.buffer, i + out.byteOffset, Math.min(n - i, QUOTA))) 10 | } 11 | } 12 | 13 | function nodeBytes (out, n) { 14 | new Uint8Array(out.buffer, out.byteOffset, n).set(crypto.randomBytes(n)) 15 | } 16 | 17 | function noImpl () { 18 | throw new Error('No secure random number generator available') 19 | } 20 | 21 | if (crypto && crypto.getRandomValues) return browserBytes 22 | 23 | if (require != null) { 24 | // Node.js. Bust Browserify 25 | crypto = require('cry' + 'pto') 26 | if (crypto && crypto.randomBytes) return nodeBytes 27 | } 28 | 29 | return noImpl 30 | })() 31 | 32 | // Make non enumerable as this is an internal function 33 | Object.defineProperty(module.exports, 'randombytes', { 34 | value: randombytes 35 | }) 36 | 37 | module.exports.randombytes_buf = function (out) { 38 | assert(out, 'out must be given') 39 | randombytes(out, out.byteLength) 40 | } 41 | -------------------------------------------------------------------------------- /test/crypto_aead_chacha20poly1305_ietf.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const b4a = require('b4a') 4 | const sodium = require('..') 5 | 6 | test('constants', function (t) { 7 | t.is(typeof sodium.crypto_aead_chacha20poly1305_ietf_ABYTES, 'number') 8 | t.is(typeof sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES, 'number') 9 | t.is(typeof sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES, 'number') 10 | t.is(typeof sodium.crypto_aead_chacha20poly1305_ietf_NSECBYTES, 'number') 11 | t.is(sodium.crypto_aead_chacha20poly1305_ietf_NSECBYTES, 0) 12 | t.is(typeof sodium.crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'number') 13 | t.is(sodium.crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, Number.MAX_SAFE_INTEGER) // to make sure, see note in binding.cc 14 | }) 15 | 16 | test('ported from libsodium', function (t) { 17 | const mlen = 114 18 | const adlen = 12 19 | const clen = mlen + sodium.crypto_aead_chacha20poly1305_ietf_ABYTES 20 | 21 | const firstkey = b4a.from([ 22 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 23 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 24 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 25 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f 26 | ]) 27 | 28 | 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.') 29 | 30 | const m = sodium.sodium_malloc(mlen) 31 | const nonce = b4a.from([ 32 | 0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 33 | 0x44, 0x45, 0x46, 0x47 34 | ]) 35 | t.is(nonce.length, sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES) 36 | 37 | const ad = b4a.from([ 38 | 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 39 | 0xc4, 0xc5, 0xc6, 0xc7 40 | ]) 41 | t.is(ad.length, adlen) 42 | 43 | const c = sodium.sodium_malloc(clen) 44 | const detachedc = sodium.sodium_malloc(mlen) 45 | 46 | const mac = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_ABYTES) 47 | 48 | const m2 = sodium.sodium_malloc(mlen) 49 | 50 | let foundclen = 0 51 | let foundmaclen = 0 52 | let m2len = 0 53 | 54 | let i = 0 55 | 56 | t.is(message.length, mlen) 57 | b4a.copy(message, m) 58 | 59 | foundclen = sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c, m, ad, null, nonce, firstkey) 60 | t.is(foundclen, mlen + sodium.crypto_aead_chacha20poly1305_ietf_ABYTES) 61 | 62 | const exp1 = new Uint8Array([ 63 | 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 64 | 0x53, 0xef, 0x7e, 0xc2, 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, 65 | 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, 0x3d, 0xbe, 0xa4, 0x5e, 66 | 0x8c, 0xa9, 0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, 67 | 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6, 68 | 0x7e, 0xcd, 0x3b, 0x36, 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, 69 | 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, 0xfa, 0xb3, 0x24, 0xe4, 70 | 0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, 71 | 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65, 72 | 0x86, 0xce, 0xc6, 0x4b, 0x61, 0x16, 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 73 | 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91 74 | ]) 75 | 76 | t.alike(c, exp1) 77 | 78 | foundmaclen = sodium.crypto_aead_chacha20poly1305_ietf_encrypt_detached(detachedc, mac, m, ad, null, nonce, firstkey) 79 | 80 | t.is(foundmaclen, sodium.crypto_aead_chacha20poly1305_ietf_ABYTES) 81 | const exp0 = c.slice(0, mlen) 82 | 83 | t.alike(detachedc, exp0) 84 | 85 | m2len = sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c, ad, nonce, firstkey) 86 | t.is(m2len, mlen) 87 | 88 | t.alike(m, m2) 89 | 90 | m2.fill(0) 91 | sodium.crypto_aead_chacha20poly1305_ietf_decrypt_detached(m2, null, c.slice(0, mlen), mac, ad, nonce, firstkey) 92 | 93 | t.alike(m, m2) 94 | 95 | for (i = 0; i < clen; i++) { 96 | c[i] ^= (i + 1) 97 | t.exception.all(_ => sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c, ad, nonce, firstkey)) 98 | if (b4a.equals(m, m2)) t.fail() 99 | c[i] ^= (i + 1) 100 | } 101 | 102 | foundclen = sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c, m, null, null, nonce, firstkey) 103 | t.is(foundclen, clen) 104 | 105 | const exp2 = new Uint8Array([ 106 | 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 107 | 0x53, 0xef, 0x7e, 0xc2, 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, 108 | 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, 0x3d, 0xbe, 0xa4, 0x5e, 109 | 0x8c, 0xa9, 0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, 110 | 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6, 111 | 0x7e, 0xcd, 0x3b, 0x36, 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, 112 | 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, 0xfa, 0xb3, 0x24, 0xe4, 113 | 0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, 114 | 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65, 115 | 0x86, 0xce, 0xc6, 0x4b, 0x61, 0x16, 0x6a, 0x23, 0xa4, 0x68, 0x1f, 0xd5, 116 | 0x94, 0x56, 0xae, 0xa1, 0xd2, 0x9f, 0x82, 0x47, 0x72, 0x16 117 | ]) 118 | 119 | t.alike(c, exp2) 120 | 121 | m2len = sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c, null, nonce, firstkey) 122 | t.is(m2len, mlen) 123 | 124 | t.alike(m2, m) 125 | 126 | b4a.copy(m, c) 127 | 128 | foundclen = sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c, c.slice(0, mlen), null, null, nonce, firstkey) 129 | 130 | t.is(foundclen, clen, 'clen is properly set (adlen=0)') 131 | 132 | const exp3 = new Uint8Array([ 133 | 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 134 | 0x53, 0xef, 0x7e, 0xc2, 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, 135 | 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, 0x3d, 0xbe, 0xa4, 0x5e, 136 | 0x8c, 0xa9, 0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, 137 | 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6, 138 | 0x7e, 0xcd, 0x3b, 0x36, 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, 139 | 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, 0xfa, 0xb3, 0x24, 0xe4, 140 | 0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, 141 | 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65, 142 | 0x86, 0xce, 0xc6, 0x4b, 0x61, 0x16, 0x6a, 0x23, 0xa4, 0x68, 0x1f, 0xd5, 143 | 0x94, 0x56, 0xae, 0xa1, 0xd2, 0x9f, 0x82, 0x47, 0x72, 0x16 144 | ]) 145 | 146 | t.alike(c, exp3) 147 | 148 | const decrypted = sodium.sodium_malloc(c.byteLength - sodium.crypto_aead_chacha20poly1305_ietf_ABYTES) 149 | m2len = sodium.crypto_aead_chacha20poly1305_ietf_decrypt(decrypted, null, c, null, nonce, firstkey) 150 | t.is(m2len, mlen, 'm2len is properly set (adlen=0)') 151 | 152 | t.alike(m, decrypted, 'm == c (adlen=0)') 153 | }) 154 | 155 | test.skip('keygen', function (t) { 156 | const key1 = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES) 157 | const key2 = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES) 158 | 159 | sodium.crypto_aead_chacha20poly1305_ietf_keygen(key1) 160 | sodium.crypto_aead_chacha20poly1305_ietf_keygen(key2) 161 | 162 | t.unlike(key1, key2) 163 | }) 164 | 165 | test.skip('different keys', function (t) { 166 | 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.') 167 | 168 | const key1 = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES) 169 | const key2 = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES) 170 | sodium.crypto_aead_chacha20poly1305_ietf_keygen(key1) 171 | sodium.crypto_aead_chacha20poly1305_ietf_keygen(key2) 172 | 173 | const nonce = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES) 174 | sodium.randombytes_buf(nonce) 175 | 176 | const clen = m.byteLength + sodium.crypto_aead_chacha20poly1305_ietf_ABYTES 177 | const c1 = sodium.sodium_malloc(clen) 178 | const c2 = sodium.sodium_malloc(clen) 179 | 180 | const m1 = sodium.sodium_malloc(m.byteLength) 181 | const m2 = sodium.sodium_malloc(m.byteLength) 182 | 183 | t.is(sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c1, m, null, null, nonce, key1), clen) 184 | t.absent(c1.equals(c2)) 185 | t.absent(c1.equals(m)) 186 | t.is(sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c2, m, null, null, nonce, key2), clen) 187 | t.absent(c1.equals(c2)) 188 | t.absent(c2.equals(m)) 189 | 190 | t.exception.all(_ => sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m1, null, c1, null, nonce, key2)) 191 | t.exception.all(_ => sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c2, null, nonce, key1)) 192 | 193 | t.is(sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m1, null, c1, null, nonce, key1), m.byteLength) 194 | t.ok(m.equals(m1)) 195 | t.is(sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c2, null, nonce, key2), m.byteLength) 196 | t.ok(m.equals(m2)) 197 | }) 198 | 199 | test.skip('different nonce', function (t) { 200 | 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.') 201 | 202 | const key = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES) 203 | sodium.crypto_aead_chacha20poly1305_ietf_keygen(key) 204 | 205 | const n1 = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES) 206 | const n2 = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES) 207 | sodium.randombytes_buf(n1) 208 | sodium.randombytes_buf(n2) 209 | 210 | const clen = m.byteLength + sodium.crypto_aead_chacha20poly1305_ietf_ABYTES 211 | const c1 = sodium.sodium_malloc(clen) 212 | const c2 = sodium.sodium_malloc(clen) 213 | 214 | const m1 = sodium.sodium_malloc(m.byteLength) 215 | const m2 = sodium.sodium_malloc(m.byteLength) 216 | 217 | t.is(sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c1, m, null, null, n1, key), clen) 218 | t.absent(c1.equals(c2)) 219 | t.absent(c1.equals(m)) 220 | t.is(sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c2, m, null, null, n2, key), clen) 221 | t.absent(c1.equals(c2)) 222 | t.absent(c2.equals(m)) 223 | 224 | t.exception.all(_ => sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m1, null, c1, null, n2, key)) 225 | t.exception.all(_ => sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c2, null, n1, key)) 226 | 227 | t.is(sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m1, null, c1, null, n1, key), m.byteLength) 228 | t.ok(m.equals(m1)) 229 | t.is(sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m2, null, c2, null, n2, key), m.byteLength) 230 | t.ok(m.equals(m2)) 231 | }) 232 | 233 | test.skip('detached -> non-detached', function (t) { 234 | 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.') 235 | m.secure = true 236 | 237 | const key = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES) 238 | sodium.crypto_aead_chacha20poly1305_ietf_keygen(key) 239 | 240 | const nonce = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES) 241 | sodium.randombytes_buf(nonce) 242 | 243 | const mac = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_ABYTES) 244 | const clen = m.byteLength 245 | const c = sodium.sodium_malloc(clen) 246 | 247 | t.is(sodium.crypto_aead_chacha20poly1305_ietf_encrypt_detached(c, mac, m, null, null, nonce, key), mac.byteLength) 248 | 249 | const m1 = sodium.sodium_malloc(m.byteLength) 250 | t.is(sodium.crypto_aead_chacha20poly1305_ietf_decrypt(m1, null, b4a.concat([c, mac]), null, nonce, key), m.byteLength) 251 | 252 | t.alike(m, m1) 253 | }) 254 | 255 | test.skip('non-detached -> detached', function (t) { 256 | 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.') 257 | m.secure = true 258 | 259 | const key = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_KEYBYTES) 260 | sodium.crypto_aead_chacha20poly1305_ietf_keygen(key) 261 | 262 | const nonce = sodium.sodium_malloc(sodium.crypto_aead_chacha20poly1305_ietf_NPUBBYTES) 263 | sodium.randombytes_buf(nonce) 264 | 265 | const clen = m.byteLength + sodium.crypto_aead_chacha20poly1305_ietf_ABYTES 266 | const c = sodium.sodium_malloc(clen) 267 | 268 | t.is(sodium.crypto_aead_chacha20poly1305_ietf_encrypt(c, m, null, null, nonce, key), c.byteLength) 269 | 270 | const m1 = sodium.sodium_malloc(m.byteLength) 271 | const csub = c.subarray(0, clen - sodium.crypto_aead_chacha20poly1305_ietf_ABYTES) 272 | const macsub = c.subarray(csub.byteLength) 273 | sodium.crypto_aead_chacha20poly1305_ietf_decrypt_detached(m1, null, csub, macsub, null, nonce, key) 274 | 275 | t.alike(m, m1) 276 | }) 277 | 278 | /** 279 | * Need to test in-place encryption 280 | * detach can talk to non detach 281 | * encrypt - decrypt 282 | * different nonce 283 | * different key 284 | * return values 285 | */ 286 | -------------------------------------------------------------------------------- /test/crypto_auth.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('crypto_auth', function (t) { 6 | const key = Buffer.alloc(sodium.crypto_auth_KEYBYTES) 7 | sodium.randombytes_buf(key) 8 | 9 | const mac = Buffer.alloc(sodium.crypto_auth_BYTES) 10 | const value = Buffer.from('Hej, Verden') 11 | 12 | sodium.crypto_auth(mac, value, key) 13 | 14 | t.not(mac, Buffer.alloc(mac.length), 'mac not blank') 15 | t.absent(sodium.crypto_auth_verify(Buffer.alloc(mac.length), value, key), 'does not verify') 16 | t.ok(sodium.crypto_auth_verify(mac, value, key), 'verifies') 17 | }) 18 | 19 | test('crypto_auth #1', t => { 20 | // "Test Case 2" from RFC 4231 21 | const key = stringToArray('Jefe', 32) 22 | const c = stringToArray('what do ya want for nothing?') 23 | const c1 = stringToArray('wwhat do ya want for nothing') 24 | 25 | const a = new Uint8Array(sodium.crypto_auth_BYTES) 26 | 27 | const exp = [ 28 | new Uint8Array([ 29 | 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, 30 | 0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3, 31 | 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6, 32 | 0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54 33 | ]), 34 | new Uint8Array([ 35 | 0x7b, 0x9d, 0x83, 0x38, 0xeb, 0x1e, 0x3d, 0xdd, 36 | 0xba, 0x8a, 0x9a, 0x35, 0x08, 0xd0, 0x34, 0xa1, 37 | 0xec, 0xbe, 0x75, 0x11, 0x37, 0xfa, 0x1b, 0xcb, 38 | 0xa0, 0xf9, 0x2a, 0x3e, 0x6d, 0xfc, 0x79, 0x80 39 | ]), 40 | new Uint8Array([ 41 | 0xb9, 0xd1, 0x4c, 0x51, 0xa6, 0xd4, 0xdd, 0x41, 42 | 0x60, 0x4e, 0xb0, 0x6c, 0x9c, 0x24, 0x0f, 0x1f, 43 | 0x64, 0xf1, 0x43, 0xb5, 0xcf, 0xde, 0xa3, 0x71, 44 | 0x29, 0xb2, 0x8b, 0xb7, 0x5d, 0x13, 0x71, 0xd3 45 | ]) 46 | ] 47 | 48 | sodium.crypto_auth(a, c, key) 49 | t.alike(a, exp[0]) 50 | t.ok(sodium.crypto_auth_verify(exp[0], c, key)) 51 | 52 | a.fill(0) 53 | sodium.crypto_auth(a, c1, key) 54 | t.alike(a, exp[1]) 55 | t.ok(sodium.crypto_auth_verify(exp[1], c1, key)) 56 | 57 | // Empty message tests 58 | a.fill(0) 59 | sodium.crypto_auth(a, new Uint8Array(0), key) 60 | t.alike(a, exp[2]) 61 | t.ok(sodium.crypto_auth_verify(exp[2], new Uint8Array(0), key)) 62 | t.end() 63 | }) 64 | 65 | test('crypto_auth', function (t) { 66 | const key = stringToArray('Jefe', 32) 67 | const c = stringToArray('what do ya want for nothing?') 68 | const a = new Uint8Array(sodium.crypto_auth_BYTES) 69 | const expected = new Uint8Array([ 70 | 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, 0xe3, 0x95, 0xfb, 0xe7, 71 | 0x3b, 0x56, 0xe0, 0xa3, 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6, 72 | 0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54 73 | ]) 74 | 75 | sodium.crypto_auth(a, c, key) 76 | 77 | t.alike(a, expected) 78 | t.ok(sodium.crypto_auth_verify(a, c, key)) 79 | 80 | c[Math.floor(Math.random() * c.length)] += 1 81 | t.absent(sodium.crypto_auth_verify(a, c, key)) 82 | 83 | t.end() 84 | }) 85 | 86 | test('wrong keylength', t => { 87 | const a = new Uint8Array(32) 88 | const c = new Uint8Array(0) 89 | 90 | for (let i = 0; i < 128; i++) { 91 | if (i === 32) continue 92 | const k = new Uint8Array(i) 93 | try { 94 | sodium.crypto_auth(a, c, k) 95 | t.fail('failed on test #' + i) 96 | } catch (e) { 97 | try { 98 | sodium.crypto_auth_verify(a, c, k) 99 | t.fail('failed on test #' + i) 100 | } catch (e) { 101 | try { 102 | sodium.crypto_auth_verify(k, c, a) 103 | t.fail('failed on test #' + i) 104 | } catch {} 105 | } 106 | } 107 | } 108 | 109 | t.pass('should not accept bad input length') 110 | t.end() 111 | }) 112 | 113 | test('crypto_auth constants', t => { 114 | t.is(sodium.crypto_auth_BYTES, 32) 115 | t.is(sodium.crypto_auth_KEYBYTES, 32) 116 | t.end() 117 | }) 118 | 119 | test('rfc4231 test case #6', t => { 120 | const keys = [ 121 | new Uint8Array([ 122 | 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 123 | 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 124 | 0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00, 125 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 126 | ]), 127 | new Uint8Array([ 128 | 0x4a, 0x65, 0x66, 0x65, 0x00, 0x00, 0x00, 0x00, 129 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 130 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 131 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 132 | ]), 133 | new Uint8Array([ 134 | 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 135 | 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 136 | 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 137 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 138 | ]), 139 | new Uint8Array([ 140 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 141 | 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 142 | 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 143 | 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 144 | ]) 145 | ] 146 | 147 | const data = [ 148 | new Uint8Array([ 149 | 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 150 | ]), 151 | new Uint8Array([ 152 | 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, 153 | 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, 154 | 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, 155 | 0x69, 0x6e, 0x67, 0x3f 156 | ]), 157 | new Uint8Array([ 158 | 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 159 | 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 160 | 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 161 | 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 162 | 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 163 | 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 164 | 0xdd, 0xdd 165 | ]), 166 | new Uint8Array([ 167 | 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 168 | 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 169 | 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 170 | 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 171 | 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 172 | 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 173 | 0xcd, 0xcd 174 | ]) 175 | ] 176 | 177 | const exp = [ 178 | new Uint8Array([ 179 | 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, 180 | 0x4f, 0xf0, 0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0, 181 | 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78, 182 | 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde 183 | ]), 184 | new Uint8Array([ 185 | 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, 186 | 0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3, 187 | 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6, 188 | 0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54 189 | ]), 190 | new Uint8Array([ 191 | 0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 192 | 0xef, 0xb0, 0xf0, 0x75, 0x6c, 0x89, 0x0b, 0xe9, 193 | 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, 194 | 0x55, 0xf8, 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39 195 | ]), 196 | new Uint8Array([ 197 | 0xb0, 0xba, 0x46, 0x56, 0x37, 0x45, 0x8c, 0x69, 198 | 0x90, 0xe5, 0xa8, 0xc5, 0xf6, 0x1d, 0x4a, 0xf7, 199 | 0xe5, 0x76, 0xd9, 0x7f, 0xf9, 0x4b, 0x87, 0x2d, 200 | 0xe7, 0x6f, 0x80, 0x50, 0x36, 0x1e, 0xe3, 0xdb 201 | ]) 202 | ] 203 | 204 | const a = new Uint8Array(sodium.crypto_auth_BYTES) 205 | 206 | for (let i = 0; i < keys.length; i++) { 207 | sodium.crypto_auth(a, data[i], keys[i]) 208 | t.alike(a, exp[i]) 209 | t.ok(sodium.crypto_auth_verify(exp[i], data[i], keys[i])) 210 | } 211 | 212 | t.end() 213 | }) 214 | 215 | function stringToArray (s, size = s.length) { 216 | const array = new Uint8Array(size) 217 | array.set(s.split('').map((c) => c.charCodeAt(0))) 218 | return array 219 | } 220 | -------------------------------------------------------------------------------- /test/crypto_box.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('crypto_box_seed_keypair', function (t) { 6 | const pk = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES) 7 | const sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES) 8 | const seed = Buffer.alloc(sodium.crypto_box_SEEDBYTES, 'lo') 9 | 10 | t.exception.all(function () { 11 | sodium.crypto_box_seed_keypair() 12 | }, 'should validate input') 13 | 14 | t.exception.all(function () { 15 | sodium.crypto_box_seed_keypair(Buffer.alloc(0), Buffer.alloc(0), Buffer.alloc(0)) 16 | }, 'should validate input length') 17 | 18 | sodium.crypto_box_seed_keypair(pk, sk, seed) 19 | 20 | const eSk = '8661a95d21b134adc02881022ad86d37f32a230d537b525b997bce27aa745afc' 21 | const ePk = '425c5ba523e70411c77300bb48dd846562e6c1fcf0142d81d2567d650ce76c3b' 22 | 23 | t.alike(pk.toString('hex'), ePk, 'seeded public key') 24 | t.alike(sk.toString('hex'), eSk, 'seeded secret key') 25 | }) 26 | 27 | test('crypto_box_keypair', function (t) { 28 | const pk = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES) 29 | const sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES) 30 | 31 | sodium.crypto_box_keypair(pk, sk) 32 | 33 | t.not(pk, Buffer.alloc(pk.length), 'made public key') 34 | t.not(sk, Buffer.alloc(sk.length), 'made secret key') 35 | 36 | t.exception.all(function () { 37 | sodium.crypto_box_keypair() 38 | }, 'should validate input') 39 | 40 | t.exception.all(function () { 41 | sodium.crypto_box_keypair(Buffer.alloc(0), Buffer.alloc(0)) 42 | }, 'should validate input length') 43 | }) 44 | 45 | test('crypto_box_detached', function (t) { 46 | const pk = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES) 47 | const sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES) 48 | const nonce = Buffer.alloc(sodium.crypto_box_NONCEBYTES) 49 | 50 | sodium.crypto_box_keypair(pk, sk) 51 | 52 | const message = Buffer.from('Hello, World!') 53 | const mac = Buffer.alloc(sodium.crypto_box_MACBYTES) 54 | const cipher = Buffer.alloc(message.length) 55 | 56 | sodium.crypto_box_detached(cipher, mac, message, nonce, pk, sk) 57 | 58 | t.not(cipher, Buffer.alloc(cipher.length), 'not blank') 59 | 60 | const plain = Buffer.alloc(cipher.length) 61 | t.absent(sodium.crypto_box_open_detached(plain, cipher, Buffer.alloc(mac.length), nonce, pk, sk), 'does not decrypt') 62 | t.ok(sodium.crypto_box_open_detached(plain, cipher, mac, nonce, pk, sk), 'decrypts') 63 | t.alike(plain, message, 'same message') 64 | }) 65 | 66 | test('crypto_box_easy', function (t) { 67 | const pk = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES) 68 | const sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES) 69 | const nonce = Buffer.alloc(sodium.crypto_box_NONCEBYTES) 70 | 71 | sodium.crypto_box_keypair(pk, sk) 72 | 73 | const message = Buffer.from('Hello, World!') 74 | const cipher = Buffer.alloc(message.length + sodium.crypto_box_MACBYTES) 75 | 76 | sodium.crypto_box_easy(cipher, message, nonce, pk, sk) 77 | 78 | t.not(cipher, Buffer.alloc(cipher.length), 'not blank') 79 | 80 | const plain = Buffer.alloc(cipher.length - sodium.crypto_box_MACBYTES) 81 | t.absent(sodium.crypto_box_open_easy(plain, Buffer.alloc(cipher.length), nonce, pk, sk), 'does not decrypt') 82 | t.ok(sodium.crypto_box_open_easy(plain, cipher, nonce, pk, sk), 'decrypts') 83 | t.alike(plain, message, 'same message') 84 | }) 85 | 86 | test('crypto_box_seal', function (t) { 87 | const pk = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES) 88 | const sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES) 89 | 90 | sodium.crypto_box_keypair(pk, sk) 91 | 92 | const pk2 = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES) 93 | const sk2 = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES) 94 | 95 | sodium.crypto_box_keypair(pk2, sk2) 96 | 97 | const message = Buffer.from('Hello, sealed World!') 98 | const cipher = Buffer.alloc(message.length + sodium.crypto_box_SEALBYTES) 99 | 100 | sodium.crypto_box_seal(cipher, message, pk) 101 | t.not(cipher, message, 'did not encrypt!') 102 | 103 | t.not(cipher, Buffer.alloc(cipher.length), 'not blank') 104 | 105 | const plain = Buffer.alloc(cipher.length - sodium.crypto_box_SEALBYTES) 106 | t.absent(sodium.crypto_box_seal_open(plain, cipher, pk2, sk2), 'does not decrypt') 107 | t.ok(sodium.crypto_box_seal_open(plain, cipher, pk, sk), 'decrypts') 108 | t.alike(plain, message, 'same message') 109 | }) 110 | 111 | test('crypto_box_seal/crypto_box_seal_open self-decrypt', function (t) { 112 | const pubKey = Buffer.alloc(sodium.crypto_box_PUBLICKEYBYTES) 113 | const secret = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES) 114 | 115 | sodium.crypto_box_keypair(pubKey, secret) 116 | 117 | const msg = Buffer.from('hello world') 118 | const cipher = Buffer.alloc(sodium.crypto_box_SEALBYTES + msg.length) 119 | sodium.crypto_box_seal(cipher, msg, pubKey) 120 | 121 | const out = Buffer.alloc(cipher.length - sodium.crypto_box_SEALBYTES) 122 | sodium.crypto_box_seal_open(out, cipher, pubKey, secret) 123 | t.alike(out.toString(), msg.toString()) 124 | t.end() 125 | }) 126 | 127 | test('crypto_box_seal_open cross-decrypt', function (t) { 128 | const pubKey = Buffer.from( 129 | 'e0bb844ae3f48bb04323c8dfe7c34cf86608db2e2112f927953060c80506287f', 'hex') 130 | const secret = Buffer.from( 131 | '036a9de1ecc9d152cf39fed1b3e15bf761ae39a299031adc011cc9809041abfa', 'hex') 132 | const cipher = Buffer.from( 133 | '249912e916ad8bcf96a3f9b750da2703' + 134 | '2eccdf83b5cff0d6a59a8bbe0bcd5823' + 135 | '5de9fbca55bd5416c754e5e0e0fe2f0c' + 136 | '4e50df0cb302f1c4378f80', 'hex') 137 | 138 | const out = Buffer.alloc(cipher.length - sodium.crypto_box_SEALBYTES) 139 | sodium.crypto_box_seal_open(out, cipher, pubKey, secret) 140 | t.alike(out.toString(), 'hello world') 141 | t.end() 142 | }) 143 | 144 | test('crypto_box_seed_keypair', function (t) { 145 | const seed = Buffer.from([ 146 | 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 147 | 0x7d, 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 148 | 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 149 | 0xc0, 0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 150 | 0x1d, 0xb9, 0x2c, 0x2a 151 | ]) 152 | 153 | const expPk = Buffer.from([ 154 | 0xed, 0x77, 0x49, 0xb4, 0xd9, 0x89, 0xf6, 0x95, 155 | 0x7f, 0x3b, 0xfd, 0xe6, 0xc5, 0x67, 0x67, 0xe9, 156 | 0x88, 0xe2, 0x1c, 0x9f, 0x87, 0x84, 0xd9, 0x1d, 157 | 0x61, 0x00, 0x11, 0xcd, 0x55, 0x3f, 0x9b, 0x06 158 | ]) 159 | 160 | const expSk = Buffer.from([ 161 | 0xac, 0xcd, 0x44, 0xeb, 0x8e, 0x93, 0x31, 0x9c, 162 | 0x05, 0x70, 0xbc, 0x11, 0x00, 0x5c, 0x0e, 0x01, 163 | 0x89, 0xd3, 0x4f, 0xf0, 0x2f, 0x6c, 0x17, 0x77, 164 | 0x34, 0x11, 0xad, 0x19, 0x12, 0x93, 0xc9, 0x8f 165 | ]) 166 | 167 | const sk = Buffer.alloc(32) 168 | const pk = Buffer.alloc(32) 169 | 170 | sodium.crypto_box_seed_keypair(pk, sk, seed) 171 | 172 | t.alike(pk, expPk) 173 | t.alike(sk, expSk) 174 | 175 | t.end() 176 | }) 177 | 178 | test('crypto_box_easy', (t) => { 179 | const alicesk = new Uint8Array([ 180 | 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72, 181 | 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, 182 | 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a 183 | ]) 184 | const bobpk = new Uint8Array([ 185 | 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61, 0xc2, 186 | 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d, 187 | 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f 188 | ]) 189 | const nonce = new Uint8Array([ 190 | 0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73, 0xcd, 0x62, 0xbd, 0xa8, 191 | 0x75, 0xfc, 0x73, 0xd6, 0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37 192 | ]) 193 | const m = new Uint8Array([ 194 | 0xbe, 0x07, 0x5f, 0xc5, 0x3c, 0x81, 0xf2, 0xd5, 0xcf, 0x14, 0x13, 0x16, 195 | 0xeb, 0xeb, 0x0c, 0x7b, 0x52, 0x28, 0xc5, 0x2a, 0x4c, 0x62, 0xcb, 0xd4, 196 | 0x4b, 0x66, 0x84, 0x9b, 0x64, 0x24, 0x4f, 0xfc, 0xe5, 0xec, 0xba, 0xaf, 197 | 0x33, 0xbd, 0x75, 0x1a, 0x1a, 0xc7, 0x28, 0xd4, 0x5e, 0x6c, 0x61, 0x29, 198 | 0x6c, 0xdc, 0x3c, 0x01, 0x23, 0x35, 0x61, 0xf4, 0x1d, 0xb6, 0x6c, 0xce, 199 | 0x31, 0x4a, 0xdb, 0x31, 0x0e, 0x3b, 0xe8, 0x25, 0x0c, 0x46, 0xf0, 0x6d, 200 | 0xce, 0xea, 0x3a, 0x7f, 0xa1, 0x34, 0x80, 0x57, 0xe2, 0xf6, 0x55, 0x6a, 201 | 0xd6, 0xb1, 0x31, 0x8a, 0x02, 0x4a, 0x83, 0x8f, 0x21, 0xaf, 0x1f, 0xde, 202 | 0x04, 0x89, 0x77, 0xeb, 0x48, 0xf5, 0x9f, 0xfd, 0x49, 0x24, 0xca, 0x1c, 203 | 0x60, 0x90, 0x2e, 0x52, 0xf0, 0xa0, 0x89, 0xbc, 0x76, 0x89, 0x70, 0x40, 204 | 0xe0, 0x82, 0xf9, 0x37, 0x76, 0x38, 0x48, 0x64, 0x5e, 0x07, 0x05 205 | ]) 206 | 207 | const c = new Uint8Array(147) 208 | sodium.crypto_box_easy(c, m, nonce, bobpk, alicesk) 209 | 210 | const expected1 = new Uint8Array([ 211 | 0xf3, 0xff, 0xc7, 0x70, 0x3f, 0x94, 0x00, 0xe5, 0x2a, 0x7d, 0xfb, 0x4b, 212 | 0x3d, 0x33, 0x05, 0xd9, 0x8e, 0x99, 0x3b, 0x9f, 0x48, 0x68, 0x12, 0x73, 213 | 0xc2, 0x96, 0x50, 0xba, 0x32, 0xfc, 0x76, 0xce, 0x48, 0x33, 0x2e, 0xa7, 214 | 0x16, 0x4d, 0x96, 0xa4, 0x47, 0x6f, 0xb8, 0xc5, 0x31, 0xa1, 0x18, 0x6a, 215 | 0xc0, 0xdf, 0xc1, 0x7c, 0x98, 0xdc, 0xe8, 0x7b, 0x4d, 0xa7, 0xf0, 0x11, 216 | 0xec, 0x48, 0xc9, 0x72, 0x71, 0xd2, 0xc2, 0x0f, 0x9b, 0x92, 0x8f, 0xe2, 217 | 0x27, 0x0d, 0x6f, 0xb8, 0x63, 0xd5, 0x17, 0x38, 0xb4, 0x8e, 0xee, 0xe3, 218 | 0x14, 0xa7, 0xcc, 0x8a, 0xb9, 0x32, 0x16, 0x45, 0x48, 0xe5, 0x26, 0xae, 219 | 0x90, 0x22, 0x43, 0x68, 0x51, 0x7a, 0xcf, 0xea, 0xbd, 0x6b, 0xb3, 0x73, 220 | 0x2b, 0xc0, 0xe9, 0xda, 0x99, 0x83, 0x2b, 0x61, 0xca, 0x01, 0xb6, 0xde, 221 | 0x56, 0x24, 0x4a, 0x9e, 0x88, 0xd5, 0xf9, 0xb3, 0x79, 0x73, 0xf6, 0x22, 222 | 0xa4, 0x3d, 0x14, 0xa6, 0x59, 0x9b, 0x1f, 0x65, 0x4c, 0xb4, 0x5a, 0x74, 223 | 0xe3, 0x55, 0xa5 224 | ]) 225 | 226 | t.alike(c, expected1, 'encrypts correctly') 227 | 228 | // This test isn't found upstream, but it seems necessary to have at least 229 | // one crypto_box_open_easy() working since the next test diverges. 230 | const o = new Uint8Array(131) 231 | t.ok(sodium.crypto_box_open_easy(o, expected1, nonce, bobpk, alicesk)) 232 | t.alike(o, m, 'decrypts correctly') 233 | 234 | const guardPage = new Uint8Array(0) 235 | 236 | t.execution(() => sodium.crypto_box_easy( 237 | c.subarray(0, sodium.crypto_box_MACBYTES), 238 | guardPage, 239 | nonce, 240 | bobpk, 241 | alicesk 242 | )) 243 | 244 | const expected2 = new Uint8Array([ 245 | 0x25, 0x39, 0x12, 0x1d, 0x8e, 0x23, 0x4e, 0x65, 0x2d, 0x65, 0x1f, 0xa4, 246 | 0xc8, 0xcf, 0xf8, 0x80, 0x8e 247 | ]) 248 | 249 | t.alike(c.subarray(0, expected2.length), expected2) 250 | 251 | t.ok(sodium.crypto_box_open_easy( 252 | new Uint8Array(0), 253 | c.subarray(0, sodium.crypto_box_MACBYTES), 254 | nonce, 255 | bobpk, 256 | alicesk 257 | )) 258 | 259 | c[Math.floor(Math.random() * sodium.crypto_box_MACBYTES)] += 1 260 | 261 | t.absent(sodium.crypto_box_open_easy(new Uint8Array(0), c.subarray(0, sodium.crypto_box_MACBYTES), nonce, bobpk, alicesk)) 262 | 263 | t.end() 264 | }) 265 | 266 | /* eslint-disable camelcase */ 267 | test('crypto_box_easy2', t => { 268 | const alicepk = new Uint8Array(sodium.crypto_box_PUBLICKEYBYTES) 269 | const alicesk = new Uint8Array(sodium.crypto_box_SECRETKEYBYTES) 270 | const bobpk = new Uint8Array(sodium.crypto_box_PUBLICKEYBYTES) 271 | const bobsk = new Uint8Array(sodium.crypto_box_SECRETKEYBYTES) 272 | const nonce = new Uint8Array(sodium.crypto_box_NONCEBYTES) 273 | const m_size = 7 + Math.floor(Math.random() * 1000) 274 | const m = new Uint8Array(m_size) 275 | const m2 = new Uint8Array(m_size) 276 | const c = new Uint8Array(sodium.crypto_box_MACBYTES + m_size) 277 | 278 | sodium.crypto_box_keypair(alicepk, alicesk) 279 | sodium.crypto_box_keypair(bobpk, bobsk) 280 | 281 | const mlen = Math.floor(Math.random() * m_size) + 1 282 | sodium.randombytes_buf(m.subarray(0, mlen)) 283 | sodium.randombytes_buf(nonce.subarray(0, sodium.crypto_box_NONCEBYTES)) 284 | 285 | t.execution(() => sodium.crypto_box_easy(c.subarray(0, mlen + sodium.crypto_box_MACBYTES), m.subarray(0, mlen), nonce, bobpk, alicesk)) 286 | 287 | t.ok(sodium.crypto_box_open_easy(m2.subarray(0, mlen), c.subarray(0, mlen + sodium.crypto_box_MACBYTES), nonce, alicepk, bobsk)) 288 | t.alike(m.subarray(0, mlen), m2.subarray(0, mlen)) 289 | 290 | for (let i = sodium.crypto_box_MACBYTES; i < mlen + sodium.crypto_box_MACBYTES - 1; i++) { 291 | if (sodium.crypto_box_open_easy(m2.subarray(0, i - sodium.crypto_box_MACBYTES), c.subarray(0, i), nonce, alicepk, bobsk)) { 292 | t.fail('short open() should fail.') 293 | } 294 | } 295 | 296 | c.set(m.subarray(0, mlen)) 297 | t.execution(() => sodium.crypto_box_easy(c.subarray(0, mlen + sodium.crypto_box_MACBYTES), c.subarray(0, mlen), nonce, bobpk, alicesk)) 298 | 299 | t.unlike(m.subarray(0, mlen), c.subarray(0, mlen)) 300 | t.unlike(m.subarray(0, mlen), c.subarray(sodium.crypto_box_MACBYTES, sodium.crypto_box_MACBYTES + mlen)) 301 | 302 | t.ok(sodium.crypto_box_open_easy(c.subarray(0, mlen), c.subarray(0, mlen + sodium.crypto_box_MACBYTES), nonce, alicepk, bobsk)) 303 | 304 | t.end() 305 | }) 306 | -------------------------------------------------------------------------------- /test/crypto_generichash.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('crypto_generichash', function (t) { 6 | const buf = Buffer.from('Hello, World!') 7 | 8 | const out = Buffer.alloc(sodium.crypto_generichash_BYTES) 9 | sodium.crypto_generichash(out, buf) 10 | 11 | t.alike(out.toString('hex'), '511bc81dde11180838c562c82bb35f3223f46061ebde4a955c27b3f489cf1e03', 'hashed buffer') 12 | 13 | const min = Buffer.alloc(sodium.crypto_generichash_BYTES_MIN) 14 | sodium.crypto_generichash(min, buf) 15 | 16 | t.alike(min.toString('hex'), '3895c59e4aeb0903396b5be3fbec69fe', 'hashed buffer min') 17 | 18 | const max = Buffer.alloc(sodium.crypto_generichash_BYTES_MAX) 19 | sodium.crypto_generichash(max, buf) 20 | 21 | const res = '7dfdb888af71eae0e6a6b751e8e3413d767ef4fa52a7993daa9ef097f7aa3d949199c113caa37c94f80cf3b22f7d9d6e4f5def4ff927830cffe4857c34be3d89' 22 | t.alike(max.toString('hex'), res, 'hashed buffer max') 23 | }) 24 | 25 | test('crypto_generichash with key', function (t) { 26 | const buf = Buffer.from('Hello, World!') 27 | const key = Buffer.alloc(sodium.crypto_generichash_KEYBYTES) 28 | 29 | key.fill('lo') 30 | 31 | const out = Buffer.alloc(sodium.crypto_generichash_BYTES) 32 | sodium.crypto_generichash(out, buf, key) 33 | 34 | t.alike(out.toString('hex'), 'f4113fe33d43c24c54627d40efa1a78838d4a6d689fd6e83c213848904fffa8c', 'hashed buffer') 35 | 36 | const min = Buffer.alloc(sodium.crypto_generichash_BYTES_MIN) 37 | sodium.crypto_generichash(min, buf, key) 38 | 39 | t.alike(min.toString('hex'), 'c8226257b0d1c3dcf4bbc3ef79574689', 'hashed buffer min') 40 | 41 | const max = Buffer.alloc(sodium.crypto_generichash_BYTES_MAX) 42 | sodium.crypto_generichash(max, buf, key) 43 | 44 | const res = '763eda46f4c6c61abb4310eb8a488950e9e0667b2fca03c463dc7489e94f065b7af6063fe86b0441c3eb9052800121d55730412abb2cbe0761b1d66f9b047c1c' 45 | t.alike(max.toString('hex'), res, 'hashed buffer max') 46 | }) 47 | 48 | test.skip('crypto_generichash_state', function (t) { 49 | const state = Buffer.alloc(sodium.crypto_generichash_STATEBYTES) 50 | sodium.crypto_generichash_init(state, null, sodium.crypto_generichash_BYTES) 51 | 52 | const buf = Buffer.from('Hej, Verden') 53 | 54 | for (let i = 0; i < 10; i++) sodium.crypto_generichash_update(state, buf) 55 | 56 | const out = Buffer.alloc(sodium.crypto_generichash_BYTES) 57 | sodium.crypto_generichash_final(state, out) 58 | 59 | t.alike(out.toString('hex'), 'cbc20f347f5dfe37dc13231cbf7eaa4ec48e585ec055a96839b213f62bd8ce00', 'streaming hash') 60 | }) 61 | 62 | test.skip('crypto_generichash state with key', function (t) { 63 | const key = Buffer.alloc(sodium.crypto_generichash_KEYBYTES) 64 | key.fill('lo') 65 | 66 | const state = Buffer.alloc(sodium.crypto_generichash_STATEBYTES) 67 | sodium.crypto_generichash_init(state, key, sodium.crypto_generichash_BYTES) 68 | 69 | const buf = Buffer.from('Hej, Verden') 70 | 71 | for (let i = 0; i < 10; i++) sodium.crypto_generichash_update(state, buf) 72 | 73 | const out = Buffer.alloc(sodium.crypto_generichash_BYTES) 74 | sodium.crypto_generichash_final(state, out) 75 | 76 | t.alike(out.toString('hex'), '405f14acbeeb30396b8030f78e6a84bab0acf08cb1376aa200a500f669f675dc', 'streaming keyed hash') 77 | }) 78 | 79 | test.skip('crypto_generichash state with hash length', function (t) { 80 | const state = Buffer.alloc(sodium.crypto_generichash_STATEBYTES) 81 | sodium.crypto_generichash_init(state, null, sodium.crypto_generichash_BYTES_MIN) 82 | 83 | const buf = Buffer.from('Hej, Verden') 84 | 85 | for (let i = 0; i < 10; i++) sodium.crypto_generichash_update(state, buf) 86 | 87 | const out = Buffer.alloc(sodium.crypto_generichash_BYTES_MIN) 88 | sodium.crypto_generichash_final(state, out) 89 | 90 | t.alike(out.toString('hex'), 'decacdcc3c61948c79d9f8dee5b6aa99', 'streaming short hash') 91 | }) 92 | 93 | test.skip('crypto_generichash state with key and hash length', function (t) { 94 | const key = Buffer.alloc(sodium.crypto_generichash_KEYBYTES) 95 | key.fill('lo') 96 | 97 | const state = Buffer.alloc(sodium.crypto_generichash_STATEBYTES) 98 | sodium.crypto_generichash_init(state, key, sodium.crypto_generichash_BYTES_MIN) 99 | 100 | const buf = Buffer.from('Hej, Verden') 101 | 102 | for (let i = 0; i < 10; i++) sodium.crypto_generichash_update(state, buf) 103 | 104 | const out = Buffer.alloc(sodium.crypto_generichash_BYTES_MIN) 105 | sodium.crypto_generichash_final(state, out) 106 | 107 | t.alike(out.toString('hex'), 'fb43f0ab6872cbfd39ec4f8a1bc6fb37', 'streaming short keyed hash') 108 | }) 109 | 110 | test('crypto_generichash_batch', function (t) { 111 | const buf = Buffer.from('Hej, Verden') 112 | const batch = [] 113 | for (let i = 0; i < 10; i++) batch.push(buf) 114 | 115 | const out = Buffer.alloc(sodium.crypto_generichash_BYTES) 116 | sodium.crypto_generichash_batch(out, batch) 117 | 118 | t.alike(out.toString('hex'), 'cbc20f347f5dfe37dc13231cbf7eaa4ec48e585ec055a96839b213f62bd8ce00', 'batch hash') 119 | }) 120 | 121 | test('crypto_generichash_batch with key', function (t) { 122 | const key = Buffer.alloc(sodium.crypto_generichash_KEYBYTES) 123 | key.fill('lo') 124 | 125 | const buf = Buffer.from('Hej, Verden') 126 | const batch = [] 127 | for (let i = 0; i < 10; i++) batch.push(buf) 128 | 129 | const out = Buffer.alloc(sodium.crypto_generichash_BYTES) 130 | sodium.crypto_generichash_batch(out, batch, key) 131 | 132 | t.alike(out.toString('hex'), '405f14acbeeb30396b8030f78e6a84bab0acf08cb1376aa200a500f669f675dc', 'batch keyed hash') 133 | }) 134 | -------------------------------------------------------------------------------- /test/crypto_hash.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('crypto_hash', function (t) { 6 | const out = Buffer.alloc(sodium.crypto_hash_BYTES) 7 | const inp = Buffer.from('Hej, Verden!') 8 | 9 | t.exception.all(function () { 10 | sodium.crypto_hash(Buffer.alloc(0), inp) 11 | }, 'throws on bad input') 12 | 13 | sodium.crypto_hash(out, inp) 14 | 15 | const result = 'bcf8e6d11dec2da6e93abb99a73c8e9c387886a5f84fbca5e25af85af26ee39161b7e0c9f9cf547f2aef40523f1aab80e26ec3c630db43ce78adc8c058dc5d16' 16 | t.alike(out.toString('hex'), result, 'hashed the string') 17 | }) 18 | -------------------------------------------------------------------------------- /test/crypto_hash_sha256.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('crypto_hash_sha256', function (t) { 6 | const out = Buffer.alloc(sodium.crypto_hash_sha256_BYTES) 7 | const inp = Buffer.from('Hej, Verden!') 8 | 9 | t.exception.all(function () { 10 | sodium.crypto_hash(Buffer.alloc(0), inp) 11 | }, 'throws on bad input') 12 | 13 | sodium.crypto_hash_sha256(out, inp) 14 | 15 | const result = 'f0704b1e832b05d01223952fb2512181af4f843ce7bb6b443afd5ea028010e6c' 16 | t.alike(out.toString('hex'), result, 'hashed the string') 17 | }) 18 | 19 | test.skip('crypto_hash_sha256_state', function (t) { 20 | const state = Buffer.alloc(sodium.crypto_hash_sha256_STATEBYTES) 21 | sodium.crypto_hash_sha256_init(state) 22 | 23 | const buf = Buffer.from('Hej, Verden!') 24 | 25 | for (let i = 0; i < 10; i++) sodium.crypto_hash_sha256_update(state, buf) 26 | 27 | const out = Buffer.alloc(sodium.crypto_hash_sha256_BYTES) 28 | sodium.crypto_hash_sha256_final(state, out) 29 | 30 | const result = '14207db33c6ac7d39ca5fe0e74432fa7a2ed15caf7f6ab5ef68d24017a899974' 31 | t.alike(out.toString('hex'), result, 'hashed the string') 32 | }) 33 | -------------------------------------------------------------------------------- /test/crypto_hash_sha512.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('crypto_hash_sha512', function (t) { 6 | const out = Buffer.alloc(sodium.crypto_hash_sha512_BYTES) 7 | const inp = Buffer.from('Hej, Verden!') 8 | 9 | t.exception.all(function () { 10 | sodium.crypto_hash(Buffer.alloc(0), inp) 11 | }, 'throws on bad input') 12 | 13 | sodium.crypto_hash_sha512(out, inp) 14 | 15 | const result = 'bcf8e6d11dec2da6e93abb99a73c8e9c387886a5f84fbca5e25af85af26ee39161b7e0c9f9cf547f2aef40523f1aab80e26ec3c630db43ce78adc8c058dc5d16' 16 | t.alike(out.toString('hex'), result, 'hashed the string') 17 | }) 18 | 19 | test.skip('crypto_hash_sha512_state', function (t) { 20 | const state = Buffer.alloc(sodium.crypto_hash_sha512_STATEBYTES) 21 | sodium.crypto_hash_sha512_init(state) 22 | 23 | const buf = Buffer.from('Hej, Verden!') 24 | 25 | for (let i = 0; i < 10; i++) sodium.crypto_hash_sha512_update(state, buf) 26 | 27 | const out = Buffer.alloc(sodium.crypto_hash_sha512_BYTES) 28 | sodium.crypto_hash_sha512_final(state, out) 29 | 30 | const result = 'a0a9b965c23be41fa8c344f483da39bedcf88b7f25cdc0bc9ea335fa264dc3db51f08c1d0f5f6f0ffb08a1d8643e2a1cd0ea8f03408ca03711c751d61787a229' 31 | t.alike(out.toString('hex'), result, 'hashed the string') 32 | }) 33 | -------------------------------------------------------------------------------- /test/crypto_kdf.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('crypto_kdf_keygen', function (t) { 6 | const key = Buffer.alloc(sodium.crypto_kdf_KEYBYTES) 7 | 8 | t.exception.all(function () { 9 | sodium.crypto_kdf_keygen(Buffer.alloc(1)) 10 | }) 11 | 12 | sodium.crypto_kdf_keygen(key) 13 | 14 | t.not(key, Buffer.alloc(key.length)) 15 | }) 16 | 17 | test('crypto_kdf_derive_from_key', function (t) { 18 | const key = Buffer.alloc(sodium.crypto_kdf_KEYBYTES) 19 | 20 | sodium.crypto_kdf_keygen(key) 21 | 22 | const subkey = Buffer.alloc(sodium.crypto_kdf_BYTES_MIN) 23 | 24 | sodium.crypto_kdf_derive_from_key(subkey, 0, Buffer.from('context_'), key) 25 | t.not(subkey, Buffer.alloc(subkey.length)) 26 | 27 | const subkey2 = Buffer.alloc(sodium.crypto_kdf_BYTES_MIN) 28 | 29 | sodium.crypto_kdf_derive_from_key(subkey2, 1, Buffer.from('context_'), key) 30 | t.not(subkey, subkey2) 31 | 32 | sodium.crypto_kdf_derive_from_key(subkey2, 0, Buffer.from('context_'), key) 33 | t.alike(subkey, subkey2) 34 | }) 35 | 36 | test('test vectors', function (assert) { 37 | const fixtures = require('./fixtures/crypto_kdf.json') 38 | 39 | for (let i = 0; i < fixtures.length; i++) { 40 | const key = Buffer.from(fixtures[i].key, 'hex') 41 | const subkeyLen = fixtures[i].subkey_len 42 | const id = fixtures[i].id 43 | const context = Buffer.from(fixtures[i].context, 'hex') 44 | 45 | const shouldError = fixtures[i].error 46 | 47 | const actual = Buffer.alloc(subkeyLen) 48 | 49 | try { 50 | sodium.crypto_kdf_derive_from_key(actual, id, context, key) 51 | const expected = Buffer.from(fixtures[i].subkey, 'hex') 52 | if (Buffer.compare(actual, expected) !== 0) { 53 | assert.fail('Failed on fixture #' + i) 54 | } 55 | } catch (ex) { 56 | if (shouldError === false) assert.fail('Failed on fixture #' + i) 57 | } 58 | } 59 | 60 | assert.pass('Passed all fixtures') 61 | assert.end() 62 | }) 63 | 64 | test('constants', function (t) { 65 | t.ok(sodium.crypto_kdf_PRIMITIVE) 66 | t.ok(sodium.crypto_kdf_BYTES_MAX > 0) 67 | t.ok(sodium.crypto_kdf_BYTES_MIN <= sodium.crypto_kdf_BYTES_MAX) 68 | t.ok(sodium.crypto_kdf_CONTEXTBYTES > 0) 69 | t.ok(sodium.crypto_kdf_KEYBYTES >= 16) 70 | t.end() 71 | }) 72 | -------------------------------------------------------------------------------- /test/crypto_kx.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('crypto_kx_seed_keypair', function (t) { 6 | const pk = Buffer.alloc(sodium.crypto_kx_PUBLICKEYBYTES) 7 | const sk = Buffer.alloc(sodium.crypto_kx_SECRETKEYBYTES) 8 | const seed = Buffer.alloc(sodium.crypto_kx_SEEDBYTES, 'lo') 9 | 10 | t.exception.all(function () { 11 | sodium.crypto_kx_seed_keypair() 12 | }, 'should validate input') 13 | 14 | t.exception.all(function () { 15 | sodium.crypto_kx_seed_keypair(Buffer.alloc(0), Buffer.alloc(0), Buffer.alloc(0)) 16 | }, 'should validate input length') 17 | 18 | sodium.crypto_kx_seed_keypair(pk, sk, seed) 19 | 20 | const eSk = '768475983073421d5b1676c4aabb24fdf17c3a5f19e6e9e9cdefbfeb45ceb153' 21 | const ePk = '0cd703bbd6b1d46dc431a1fc4f1f7724c64b1d4c471e8c17de4966c9e15bf85e' 22 | 23 | t.alike(pk.toString('hex'), ePk, 'seeded public key') 24 | t.alike(sk.toString('hex'), eSk, 'seeded secret key') 25 | }) 26 | 27 | test('crypto_kx_keypair', function (t) { 28 | const pk = Buffer.alloc(sodium.crypto_kx_PUBLICKEYBYTES) 29 | const sk = Buffer.alloc(sodium.crypto_kx_SECRETKEYBYTES) 30 | 31 | sodium.crypto_kx_keypair(pk, sk) 32 | 33 | t.not(pk, Buffer.alloc(pk.length), 'made public key') 34 | t.not(sk, Buffer.alloc(sk.length), 'made secret key') 35 | 36 | t.exception.all(function () { 37 | sodium.crypto_kx_keypair() 38 | }, 'should validate input') 39 | 40 | t.exception.all(function () { 41 | sodium.crypto_kx_keypair(Buffer.alloc(0), Buffer.alloc(0)) 42 | }, 'should validate input length') 43 | }) 44 | 45 | test.skip('crypto_kx_client_session_keys', function (t) { 46 | const clientPk = Buffer.alloc(sodium.crypto_kx_PUBLICKEYBYTES) 47 | const clientSk = Buffer.alloc(sodium.crypto_kx_SECRETKEYBYTES) 48 | const serverPk = Buffer.alloc(sodium.crypto_kx_PUBLICKEYBYTES) 49 | const serverSk = Buffer.alloc(sodium.crypto_kx_SECRETKEYBYTES) 50 | 51 | const serverRx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES) 52 | const serverTx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES) 53 | 54 | const clientRx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES) 55 | const clientTx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES) 56 | 57 | sodium.crypto_kx_keypair(serverPk, serverSk) 58 | sodium.crypto_kx_keypair(clientPk, clientSk) 59 | 60 | t.exception.all(function () { 61 | sodium.crypto_kx_client_session_keys() 62 | }, 'should validate') 63 | 64 | t.exception.all(function () { 65 | sodium.crypto_kx_server_session_keys() 66 | }, 'should validate') 67 | 68 | sodium.crypto_kx_client_session_keys(clientRx, clientTx, clientPk, clientSk, serverPk) 69 | sodium.crypto_kx_server_session_keys(serverRx, serverTx, serverPk, serverSk, clientPk) 70 | 71 | t.alike(clientRx, serverTx) 72 | t.alike(clientTx, serverRx) 73 | }) 74 | 75 | test.skip('crypto_kx_client_session_keys one NULL', function (t) { 76 | const clientPk = Buffer.alloc(sodium.crypto_kx_PUBLICKEYBYTES) 77 | const clientSk = Buffer.alloc(sodium.crypto_kx_SECRETKEYBYTES) 78 | const serverPk = Buffer.alloc(sodium.crypto_kx_PUBLICKEYBYTES) 79 | const serverSk = Buffer.alloc(sodium.crypto_kx_SECRETKEYBYTES) 80 | 81 | const serverRx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES) 82 | const serverTx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES) 83 | 84 | const clientRx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES) 85 | const clientTx = Buffer.alloc(sodium.crypto_kx_SESSIONKEYBYTES) 86 | 87 | sodium.crypto_kx_keypair(serverPk, serverSk) 88 | sodium.crypto_kx_keypair(clientPk, clientSk) 89 | 90 | t.exception.all(function () { 91 | sodium.crypto_kx_client_session_keys() 92 | }, 'should validate') 93 | 94 | t.exception.all(function () { 95 | sodium.crypto_kx_server_session_keys() 96 | }, 'should validate') 97 | 98 | t.exception(function () { 99 | sodium.crypto_kx_server_session_keys(null, null, clientPk, clientSk, serverPk) 100 | }, 'should validate') 101 | 102 | t.exception(function () { 103 | sodium.crypto_kx_client_session_keys(null, null, clientPk, clientSk, serverPk) 104 | }, 'should validate') 105 | 106 | sodium.crypto_kx_client_session_keys(clientRx, null, clientPk, clientSk, serverPk) 107 | sodium.crypto_kx_server_session_keys(null, serverTx, serverPk, serverSk, clientPk) 108 | 109 | t.alike(clientRx, serverTx) 110 | 111 | sodium.crypto_kx_client_session_keys(null, clientTx, clientPk, clientSk, serverPk) 112 | sodium.crypto_kx_server_session_keys(serverRx, null, serverPk, serverSk, clientPk) 113 | t.alike(clientTx, serverRx) 114 | }) 115 | 116 | test('crypto_kx constants', function (t) { 117 | t.alike(typeof sodium.crypto_kx_SESSIONKEYBYTES, 'number') 118 | t.alike(typeof sodium.crypto_kx_PUBLICKEYBYTES, 'number') 119 | t.alike(typeof sodium.crypto_kx_SECRETKEYBYTES, 'number') 120 | t.alike(typeof sodium.crypto_kx_SEEDBYTES, 'number') 121 | t.alike(typeof sodium.crypto_kx_PRIMITIVE, 'string') 122 | 123 | t.is(sodium.crypto_kx_SEEDBYTES, 32) 124 | t.is(sodium.crypto_kx_PUBLICKEYBYTES, 32) 125 | t.is(sodium.crypto_kx_SESSIONKEYBYTES, 32) 126 | t.is(sodium.crypto_kx_SECRETKEYBYTES, 32) 127 | 128 | t.end() 129 | }) 130 | 131 | /* eslint-disable camelcase */ 132 | test.skip('libsodium', function (t) { 133 | const small_order_p = new Uint8Array([ 134 | 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 135 | 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 136 | 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00 137 | ]) 138 | 139 | const seed = new Uint8Array(sodium.crypto_kx_SEEDBYTES) 140 | const client_pk = new Uint8Array(sodium.crypto_kx_PUBLICKEYBYTES) 141 | const client_sk = new Uint8Array(sodium.crypto_kx_SECRETKEYBYTES) 142 | const client_rx = new Uint8Array(sodium.crypto_kx_SESSIONKEYBYTES) 143 | const client_tx = new Uint8Array(sodium.crypto_kx_SESSIONKEYBYTES) 144 | const server_pk = new Uint8Array(sodium.crypto_kx_PUBLICKEYBYTES) 145 | const server_sk = new Uint8Array(sodium.crypto_kx_SECRETKEYBYTES) 146 | const server_rx = new Uint8Array(sodium.crypto_kx_SESSIONKEYBYTES) 147 | const server_tx = new Uint8Array(sodium.crypto_kx_SESSIONKEYBYTES) 148 | 149 | for (let i = 0; i < sodium.crypto_kx_SEEDBYTES; i++) { 150 | seed[i] = i 151 | } 152 | 153 | sodium.crypto_kx_seed_keypair(client_pk, client_sk, seed) 154 | 155 | const exp1 = new Uint8Array([ 156 | 0x0e, 0x02, 0x16, 0x22, 0x3f, 0x14, 0x71, 0x43, 0xd3, 0x26, 0x15, 157 | 0xa9, 0x11, 0x89, 0xc2, 0x88, 0xc1, 0x72, 0x8c, 0xba, 0x3c, 0xc5, 158 | 0xf9, 0xf6, 0x21, 0xb1, 0x02, 0x6e, 0x03, 0xd8, 0x31, 0x29 159 | ]) 160 | 161 | const exp2 = new Uint8Array([ 162 | 0xcb, 0x2f, 0x51, 0x60, 0xfc, 0x1f, 0x7e, 0x05, 0xa5, 0x5e, 0xf4, 163 | 0x9d, 0x34, 0x0b, 0x48, 0xda, 0x2e, 0x5a, 0x78, 0x09, 0x9d, 0x53, 164 | 0x39, 0x33, 0x51, 0xcd, 0x57, 0x9d, 0xd4, 0x25, 0x03, 0xd6 165 | ]) 166 | 167 | t.alike(client_pk, exp1, 'client_pk') 168 | t.alike(client_sk, exp2, 'client_pk') 169 | 170 | sodium.crypto_kx_keypair(server_pk, server_sk) 171 | 172 | t.exception(() => { 173 | sodium.crypto_kx_client_session_keys(client_rx, client_tx, client_pk, client_sk, small_order_p) 174 | }) 175 | 176 | t.execution(() => { 177 | sodium.crypto_kx_client_session_keys(client_rx, client_tx, client_pk, client_sk, server_pk) 178 | }) 179 | 180 | t.exception(() => sodium.crypto_kx_server_session_keys(server_rx, server_tx, server_pk, server_sk, small_order_p)) 181 | t.execution(() => { 182 | sodium.crypto_kx_server_session_keys(server_rx, server_tx, server_pk, server_sk, client_pk) 183 | }) 184 | 185 | t.alike(server_rx, client_tx) 186 | t.alike(server_tx, client_rx) 187 | 188 | sodium.sodium_increment(client_pk) 189 | 190 | t.execution(() => { 191 | sodium.crypto_kx_server_session_keys(server_rx, server_tx, server_pk, server_sk, client_pk) 192 | }) 193 | 194 | t.unlike(server_rx, client_tx) 195 | t.unlike(server_tx, client_rx) 196 | 197 | sodium.crypto_kx_keypair(client_pk, client_sk) 198 | 199 | t.execution(() => { 200 | sodium.crypto_kx_server_session_keys(server_rx, server_tx, server_pk, server_sk, client_pk) 201 | }) 202 | 203 | t.unlike(server_rx, client_tx) 204 | t.unlike(server_tx, client_rx) 205 | 206 | sodium.crypto_kx_seed_keypair(client_pk, client_sk, seed) 207 | sodium.sodium_increment(seed) 208 | 209 | sodium.crypto_kx_seed_keypair(server_pk, server_sk, seed) 210 | t.execution(() => { 211 | sodium.crypto_kx_server_session_keys(server_rx, server_tx, server_pk, server_sk, client_pk) 212 | }) 213 | 214 | const exp3 = new Uint8Array([ 215 | 0x62, 0xc8, 0xf4, 0xfa, 0x81, 0x80, 0x0a, 0xbd, 0x05, 0x77, 0xd9, 216 | 0x99, 0x18, 0xd1, 0x29, 0xb6, 0x5d, 0xeb, 0x78, 0x9a, 0xf8, 0xc8, 217 | 0x35, 0x1f, 0x39, 0x1f, 0xeb, 0x0c, 0xbf, 0x23, 0x86, 0x04 218 | ]) 219 | 220 | const exp4 = new Uint8Array([ 221 | 0x74, 0x95, 0x19, 0xc6, 0x80, 0x59, 0xbc, 0xe6, 0x9f, 0x7c, 0xfc, 222 | 0xc7, 0xb3, 0x87, 0xa3, 0xde, 0x1a, 0x1e, 0x82, 0x37, 0xd1, 0x10, 223 | 0x99, 0x13, 0x23, 0xbf, 0x62, 0x87, 0x01, 0x15, 0x73, 0x1a 224 | ]) 225 | 226 | t.alike(server_rx, exp3) 227 | t.alike(server_tx, exp4) 228 | 229 | t.execution(() => { 230 | sodium.crypto_kx_client_session_keys(client_rx, client_tx, client_pk, client_sk, server_pk) 231 | }) 232 | 233 | const exp5 = new Uint8Array([ 234 | 0x74, 0x95, 0x19, 0xc6, 0x80, 0x59, 0xbc, 0xe6, 0x9f, 0x7c, 0xfc, 235 | 0xc7, 0xb3, 0x87, 0xa3, 0xde, 0x1a, 0x1e, 0x82, 0x37, 0xd1, 0x10, 236 | 0x99, 0x13, 0x23, 0xbf, 0x62, 0x87, 0x01, 0x15, 0x73, 0x1a 237 | ]) 238 | 239 | const exp6 = new Uint8Array([ 240 | 0x62, 0xc8, 0xf4, 0xfa, 0x81, 0x80, 0x0a, 0xbd, 0x05, 0x77, 0xd9, 241 | 0x99, 0x18, 0xd1, 0x29, 0xb6, 0x5d, 0xeb, 0x78, 0x9a, 0xf8, 0xc8, 242 | 0x35, 0x1f, 0x39, 0x1f, 0xeb, 0x0c, 0xbf, 0x23, 0x86, 0x04 243 | ]) 244 | 245 | t.alike(client_rx, exp5) 246 | t.alike(client_tx, exp6) 247 | 248 | sodium.randombytes_buf(client_rx) 249 | sodium.randombytes_buf(client_tx) 250 | sodium.randombytes_buf(server_rx) 251 | sodium.randombytes_buf(server_tx) 252 | 253 | t.execution(() => sodium.crypto_kx_client_session_keys(client_rx, null, 254 | client_pk, client_sk, server_pk)) 255 | t.execution(() => sodium.crypto_kx_client_session_keys(null, client_tx, 256 | client_pk, client_sk, server_pk)) 257 | t.execution(() => sodium.crypto_kx_server_session_keys(server_rx, null, 258 | server_pk, server_sk, client_pk)) 259 | t.execution(() => sodium.crypto_kx_server_session_keys(null, server_tx, 260 | server_pk, server_sk, client_pk)) 261 | 262 | t.alike(client_rx, client_tx) 263 | t.alike(client_tx, server_rx) 264 | t.alike(server_rx, server_tx) 265 | }) 266 | -------------------------------------------------------------------------------- /test/crypto_onetimeauth.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('crypto_onetimeauth', function (t) { 6 | const key = Buffer.alloc(sodium.crypto_onetimeauth_KEYBYTES) 7 | const mac = Buffer.alloc(sodium.crypto_onetimeauth_BYTES) 8 | const value = Buffer.from('Hello, World!') 9 | 10 | sodium.randombytes_buf(key) 11 | sodium.crypto_onetimeauth(mac, value, key) 12 | 13 | t.not(mac, Buffer.alloc(mac.length), 'not blank') 14 | t.absent(sodium.crypto_onetimeauth_verify(Buffer.alloc(mac.length), value, key), 'does not verify') 15 | t.ok(sodium.crypto_onetimeauth_verify(mac, value, key), 'verifies') 16 | }) 17 | 18 | test.skip('crypto_onetimeauth_state', function (t) { 19 | const key = Buffer.alloc(sodium.crypto_onetimeauth_KEYBYTES, 'lo') 20 | const state = Buffer.alloc(sodium.crypto_onetimeauth_STATEBYTES) 21 | 22 | t.exception.all(function () { 23 | sodium.crypto_onetimeauth_init(state) 24 | }, 'key required') 25 | 26 | key[0] = 42 27 | 28 | sodium.crypto_onetimeauth_init(state, key) 29 | const value = Buffer.from('Hello, World!') 30 | 31 | for (let i = 0; i < 10; i++) sodium.crypto_onetimeauth_update(state, value) 32 | 33 | const mac = Buffer.alloc(sodium.crypto_onetimeauth_BYTES) 34 | sodium.crypto_onetimeauth_final(state, mac) 35 | 36 | t.alike(mac.toString('hex'), 'ac35df70e6b95051e015de11a6cbf4ab', 'streaming mac') 37 | }) 38 | -------------------------------------------------------------------------------- /test/crypto_scalarmult.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('crypto_scalarmult_base', function (t) { 6 | const keys = keyPair() 7 | 8 | t.not(keys.secretKey, Buffer.alloc(keys.secretKey.length), 'secret key not blank') 9 | t.not(keys.publicKey, Buffer.alloc(keys.publicKey.length), 'public key not blank') 10 | }) 11 | 12 | test('crypto_scalarmult', function (t) { 13 | const peer1 = keyPair() 14 | const peer2 = keyPair() 15 | 16 | t.not(peer1.secretKey, peer2.secretKey, 'diff secret keys') 17 | t.not(peer1.publicKey, peer2.publicKey, 'diff public keys') 18 | 19 | const shared1 = Buffer.alloc(sodium.crypto_scalarmult_BYTES) 20 | const shared2 = Buffer.alloc(sodium.crypto_scalarmult_BYTES) 21 | 22 | sodium.crypto_scalarmult(shared1, peer1.secretKey, peer2.publicKey) 23 | sodium.crypto_scalarmult(shared2, peer2.secretKey, peer1.publicKey) 24 | 25 | t.alike(shared1, shared2, 'same shared secret') 26 | }) 27 | 28 | function keyPair () { 29 | const secretKey = Buffer.alloc(sodium.crypto_scalarmult_SCALARBYTES) 30 | sodium.randombytes_buf(secretKey) 31 | 32 | const publicKey = Buffer.alloc(sodium.crypto_scalarmult_BYTES) 33 | sodium.crypto_scalarmult_base(publicKey, secretKey) 34 | 35 | return { 36 | publicKey, 37 | secretKey 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/crypto_secretbox.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('crypto_secretbox_easy', function (t) { 6 | const message = Buffer.from('Hej, Verden!') 7 | const output = Buffer.alloc(message.length + sodium.crypto_secretbox_MACBYTES) 8 | 9 | const key = Buffer.alloc(sodium.crypto_secretbox_KEYBYTES) 10 | sodium.randombytes_buf(key) 11 | 12 | const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES) 13 | sodium.randombytes_buf(nonce) 14 | 15 | t.exception.all(function () { 16 | sodium.crypto_secretbox_easy(Buffer.alloc(0), message, nonce, key) 17 | }, 'throws if output is too small') 18 | 19 | t.exception.all(function () { 20 | sodium.crypto_secretbox_easy(Buffer.alloc(message.length), message, nonce, key) 21 | }, 'throws if output is too small') 22 | 23 | sodium.crypto_secretbox_easy(output, message, nonce, key) 24 | t.not(output, Buffer.alloc(output.length)) 25 | 26 | const result = Buffer.alloc(output.length - sodium.crypto_secretbox_MACBYTES) 27 | t.absent(sodium.crypto_secretbox_open_easy(result, output, Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES), key), 'could not decrypt') 28 | t.ok(sodium.crypto_secretbox_open_easy(result, output, nonce, key), 'could decrypt') 29 | 30 | t.alike(result, message, 'decrypted message is correct') 31 | }) 32 | 33 | test('crypto_secretbox_easy overwrite buffer', function (t) { 34 | const output = Buffer.alloc(Buffer.byteLength('Hej, Verden!') + sodium.crypto_secretbox_MACBYTES) 35 | output.write('Hej, Verden!', sodium.crypto_secretbox_MACBYTES) 36 | 37 | const key = Buffer.alloc(sodium.crypto_secretbox_KEYBYTES) 38 | sodium.randombytes_buf(key) 39 | 40 | const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES) 41 | sodium.randombytes_buf(nonce) 42 | 43 | sodium.crypto_secretbox_easy(output, output.slice(sodium.crypto_secretbox_MACBYTES), nonce, key) 44 | t.not(output, Buffer.alloc(output.length)) 45 | 46 | t.ok(sodium.crypto_secretbox_open_easy(output.slice(sodium.crypto_secretbox_MACBYTES), output, nonce, key), 'could decrypt') 47 | t.alike(output.slice(sodium.crypto_secretbox_MACBYTES), Buffer.from('Hej, Verden!'), 'decrypted message is correct') 48 | }) 49 | 50 | test('crypto_secretbox_detached', function (t) { 51 | const message = Buffer.from('Hej, Verden!') 52 | const output = Buffer.alloc(message.length) 53 | const mac = Buffer.alloc(sodium.crypto_secretbox_MACBYTES) 54 | 55 | const key = Buffer.alloc(sodium.crypto_secretbox_KEYBYTES) 56 | sodium.randombytes_buf(key) 57 | 58 | const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES) 59 | sodium.randombytes_buf(nonce) 60 | 61 | sodium.crypto_secretbox_detached(output, mac, message, nonce, key) 62 | 63 | t.not(mac, Buffer.alloc(mac.length), 'mac not blank') 64 | t.not(output, Buffer.alloc(output.length), 'output not blank') 65 | 66 | const result = Buffer.alloc(output.length) 67 | 68 | t.absent(sodium.crypto_secretbox_open_detached(result, output, mac, nonce, Buffer.alloc(key.length)), 'could not decrypt') 69 | t.ok(sodium.crypto_secretbox_open_detached(result, output, mac, nonce, key), 'could decrypt') 70 | 71 | t.alike(result, message, 'decrypted message is correct') 72 | }) 73 | -------------------------------------------------------------------------------- /test/crypto_secretstream.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('constants', function (t) { 6 | t.alike(typeof sodium.crypto_secretstream_xchacha20poly1305_ABYTES, 'number', 'crypto_secretstream_xchacha20poly1305_ABYTES is number') 7 | t.alike(typeof sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES, 'number', 'crypto_secretstream_xchacha20poly1305_HEADERBYTES is number') 8 | t.alike(typeof sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES, 'number', 'crypto_secretstream_xchacha20poly1305_KEYBYTES is number') 9 | t.alike(typeof sodium.crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX, 'bigint', 'crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX is number') 10 | 11 | t.ok(typeof sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE === 'number', 'crypto_secretstream_xchacha20poly1305_TAG_MESSAGE is Buffer') 12 | t.ok(typeof sodium.crypto_secretstream_xchacha20poly1305_TAG_PUSH === 'number', 'crypto_secretstream_xchacha20poly1305_TAG_PUSH is Buffer') 13 | t.ok(typeof sodium.crypto_secretstream_xchacha20poly1305_TAG_REKEY === 'number', 'crypto_secretstream_xchacha20poly1305_TAG_REKEY is Buffer') 14 | t.ok(typeof sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL === 'number', 'crypto_secretstream_xchacha20poly1305_TAG_FINAL is Buffer') 15 | }) 16 | 17 | test.skip('crypto_secretstream', function (t) { 18 | const state = Buffer.alloc(sodium.crypto_secretstream_xchacha20poly1305_STATEBYTES) 19 | 20 | const header = Buffer.alloc(sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES) 21 | const ad = Buffer.alloc(Math.floor(Math.random() * 100)) 22 | sodium.randombytes_buf(ad) 23 | 24 | const m1 = Buffer.alloc(Math.floor(Math.random() * 1000)) 25 | sodium.randombytes_buf(m1) 26 | 27 | const m2 = Buffer.alloc(Math.floor(Math.random() * 1000)) 28 | sodium.randombytes_buf(m2) 29 | 30 | const m3 = Buffer.alloc(Math.floor(Math.random() * 1000)) 31 | sodium.randombytes_buf(m3) 32 | 33 | const m4 = Buffer.alloc(Math.floor(Math.random() * 1000)) 34 | sodium.randombytes_buf(m4) 35 | 36 | const m1_ = Buffer.from(m1) 37 | const m2_ = Buffer.from(m2) 38 | const m3_ = Buffer.from(m3) 39 | const m4_ = Buffer.from(m4) 40 | 41 | const c1 = Buffer.alloc(m1.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES) 42 | const c2 = Buffer.alloc(m2.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES) 43 | const c3 = Buffer.alloc(m3.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES) 44 | const c4 = Buffer.alloc(m4.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES) 45 | 46 | const key = Buffer.alloc(sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES) 47 | let ret 48 | const tag = Buffer.alloc(sodium.crypto_secretstream_xchacha20poly1305_TAGBYTES, 0xdb) 49 | 50 | sodium.crypto_secretstream_xchacha20poly1305_keygen(key) 51 | 52 | sodium.crypto_secretstream_xchacha20poly1305_init_push(state, header, key) 53 | t.unlike(header.toString('hex'), '000000000000000000000000000000000000000000000000') 54 | ret = sodium.crypto_secretstream_xchacha20poly1305_push(state, c1, m1, null, sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE) 55 | t.alike(ret, m1.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES) 56 | ret = sodium.crypto_secretstream_xchacha20poly1305_push(state, c2, m2, ad.slice(0, 0), sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE) 57 | t.alike(ret, m2.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES) 58 | ret = sodium.crypto_secretstream_xchacha20poly1305_push(state, c3, m3, ad, sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE) 59 | t.alike(ret, m3.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES) 60 | ret = sodium.crypto_secretstream_xchacha20poly1305_push(state, c4, m4, null, sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL) 61 | t.alike(ret, m4.length + sodium.crypto_secretstream_xchacha20poly1305_ABYTES) 62 | 63 | sodium.crypto_secretstream_xchacha20poly1305_init_pull(state, header, key) 64 | m1.fill(0) 65 | tag.fill(0xdb) 66 | ret = sodium.crypto_secretstream_xchacha20poly1305_pull(state, m1, tag, c1, null) 67 | t.alike(ret, c1.length - sodium.crypto_secretstream_xchacha20poly1305_ABYTES) 68 | t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE) 69 | t.ok(m1.equals(m1_)) 70 | 71 | m2.fill(0) 72 | tag.fill(0xdb) 73 | ret = sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2, null) 74 | t.alike(ret, c2.length - sodium.crypto_secretstream_xchacha20poly1305_ABYTES) 75 | t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE) 76 | t.ok(m2.equals(m2_)) 77 | 78 | if (ad.length > 0) { 79 | t.exception.all(function () { 80 | sodium.crypto_secretstream_xchacha20poly1305_pull(state, m3, tag, c3, null) 81 | }) 82 | } 83 | 84 | m3.fill(0) 85 | tag.fill(0xdb) 86 | ret = sodium.crypto_secretstream_xchacha20poly1305_pull(state, m3, tag, c3, ad) 87 | t.alike(ret, c3.length - sodium.crypto_secretstream_xchacha20poly1305_ABYTES) 88 | t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE) 89 | t.ok(m3.equals(m3_)) 90 | 91 | m4.fill(0) 92 | tag.fill(0xdb) 93 | ret = sodium.crypto_secretstream_xchacha20poly1305_pull(state, m4, tag, c4, null) 94 | t.alike(ret, c4.length - sodium.crypto_secretstream_xchacha20poly1305_ABYTES) 95 | t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL) 96 | t.ok(m4.equals(m4_)) 97 | 98 | t.exception.all(function () { 99 | sodium.crypto_secretstream_xchacha20poly1305_pull(state, m4, tag, c4, null) 100 | }, 'previous with FINAL tag') 101 | 102 | t.exception.all(function () { 103 | sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2, null) 104 | }, 'previous with without tag') 105 | 106 | t.exception.all(function () { 107 | sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2.slice(0, Math.random() * sodium.crypto_secretstream_xchacha20poly1305_ABYTES | 0), null) // fixme 108 | }, 'short ciphertext') 109 | 110 | t.exception.all(function () { 111 | sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2.slice(0, sodium.crypto_secretstream_xchacha20poly1305_ABYTES), null) 112 | }, 'empty ciphertext') 113 | 114 | /* without explicit rekeying */ 115 | 116 | sodium.crypto_secretstream_xchacha20poly1305_init_push(state, header, key) 117 | sodium.crypto_secretstream_xchacha20poly1305_push(state, c1, m1, null, sodium.crypto_secretstream_xchacha20poly1305_TAG_REKEY) 118 | sodium.crypto_secretstream_xchacha20poly1305_push(state, c2, m2, null, sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE) 119 | 120 | sodium.crypto_secretstream_xchacha20poly1305_init_pull(state, header, key) 121 | tag.fill(0xdb) 122 | sodium.crypto_secretstream_xchacha20poly1305_pull(state, m1, tag, c1, null) 123 | t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_REKEY) 124 | tag.fill(0xdb) 125 | sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2, null) 126 | t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE) 127 | 128 | /* with explicit rekeying */ 129 | 130 | sodium.crypto_secretstream_xchacha20poly1305_init_push(state, header, key) 131 | sodium.crypto_secretstream_xchacha20poly1305_push(state, c1, m1, null, sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE) 132 | sodium.crypto_secretstream_xchacha20poly1305_rekey(state) 133 | sodium.crypto_secretstream_xchacha20poly1305_push(state, c2, m2, null, sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE) 134 | 135 | sodium.crypto_secretstream_xchacha20poly1305_init_pull(state, header, key) 136 | tag.fill(0xdb) 137 | sodium.crypto_secretstream_xchacha20poly1305_pull(state, m1, tag, c1, null) 138 | t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE) 139 | 140 | t.exception.all(function () { 141 | sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2, null) 142 | }) 143 | 144 | sodium.crypto_secretstream_xchacha20poly1305_rekey(state) 145 | tag.fill(0xdb) 146 | sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, tag, c2, null) 147 | t.alike(tag[0], sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE) 148 | }) 149 | -------------------------------------------------------------------------------- /test/crypto_sign.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | const fixtures = require('./fixtures/crypto_sign.json') 5 | 6 | test('crypto_sign_ed25519_sk_to_pk', function (t) { 7 | const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES) 8 | const pke = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES) 9 | const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES) 10 | 11 | sodium.crypto_sign_keypair(pk, sk) 12 | sodium.crypto_sign_ed25519_sk_to_pk(pke, sk) 13 | 14 | t.ok(pk.equals(pke)) 15 | }) 16 | 17 | test('crypto_sign_seed_keypair', function (t) { 18 | const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES) 19 | const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES) 20 | const seed = Buffer.alloc(sodium.crypto_sign_SEEDBYTES, 'lo') 21 | 22 | t.exception.all(function () { 23 | sodium.crypto_sign_seed_keypair() 24 | }, 'should validate input') 25 | 26 | t.exception.all(function () { 27 | sodium.crypto_sign_seed_keypair(Buffer.alloc(0), Buffer.alloc(0), Buffer.alloc(0)) 28 | }, 'should validate input length') 29 | 30 | sodium.crypto_sign_seed_keypair(pk, sk, seed) 31 | 32 | const eSk = '6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f41eb5b4dba29b19e391d9a4d1a4a879b27958ff3734e10cfbf1f46d68f4d3038' 33 | const ePk = '41eb5b4dba29b19e391d9a4d1a4a879b27958ff3734e10cfbf1f46d68f4d3038' 34 | 35 | t.alike(pk.toString('hex'), ePk, 'seeded public key') 36 | t.alike(sk.toString('hex'), eSk, 'seeded secret key') 37 | }) 38 | 39 | test('crypto_sign_keypair', function (t) { 40 | const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES) 41 | const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES) 42 | 43 | sodium.crypto_sign_keypair(pk, sk) 44 | 45 | t.not(pk, Buffer.alloc(pk.length), 'made public key') 46 | t.not(sk, Buffer.alloc(sk.length), 'made secret key') 47 | 48 | t.exception.all(function () { 49 | sodium.crypto_sign_keypair() 50 | }, 'should validate input') 51 | 52 | t.exception.all(function () { 53 | sodium.crypto_sign_keypair(Buffer.alloc(0), Buffer.alloc(0)) 54 | }, 'should validate input length') 55 | }) 56 | 57 | test('crypto_sign', function (t) { 58 | const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES) 59 | const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES) 60 | 61 | sodium.crypto_sign_keypair(pk, sk) 62 | 63 | const message = Buffer.from('Hello, World!') 64 | const signedMessage = Buffer.alloc(message.length + sodium.crypto_sign_BYTES) 65 | 66 | sodium.crypto_sign(signedMessage, message, sk) 67 | 68 | t.alike(signedMessage.slice(-message.length), message, 'contains message') 69 | 70 | const output = Buffer.alloc(message.length) 71 | 72 | t.absent(sodium.crypto_sign_open(output, Buffer.alloc(signedMessage.length), pk), 'was not signed') 73 | t.ok(sodium.crypto_sign_open(output, signedMessage, pk), 'was signed') 74 | 75 | t.alike(output, message, 'same message') 76 | }) 77 | 78 | test('crypto_sign_detached', function (t) { 79 | const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES) 80 | const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES) 81 | 82 | sodium.crypto_sign_keypair(pk, sk) 83 | 84 | const message = Buffer.from('Hello, World!') 85 | const signature = Buffer.alloc(sodium.crypto_sign_BYTES) 86 | 87 | sodium.crypto_sign_detached(signature, message, sk) 88 | 89 | t.absent(sodium.crypto_sign_verify_detached(Buffer.concat([Buffer.alloc(1), signature]), message, pk), 'was not signed') 90 | t.ok(sodium.crypto_sign_verify_detached(signature, message, pk), 'was signed') 91 | }) 92 | 93 | test('crypto_sign_open fixtures', function (t) { 94 | for (let i = 0; i < fixtures.length; i++) { 95 | const publicKey = new Uint8Array(fixtures[i][1]) 96 | const message = new Uint8Array(fixtures[i][3]) 97 | const signed = new Uint8Array([].concat(fixtures[i][2], fixtures[i][3])) 98 | 99 | if (!sodium.crypto_sign_open(message, signed, publicKey)) { 100 | t.fail('Failed on fixture #' + i) 101 | t.end() 102 | return 103 | } 104 | } 105 | 106 | t.pass('Passed all fixtures') 107 | t.end() 108 | }) 109 | 110 | test('crypto_sign fixtures', function (t) { 111 | const fixtures = require('./fixtures/crypto_sign.json') 112 | 113 | for (let i = 0; i < fixtures.length; i++) { 114 | const secretKey = new Uint8Array([].concat(fixtures[i][0], fixtures[i][1])) 115 | const message = new Uint8Array(fixtures[i][3]) 116 | 117 | const expected = new Uint8Array([].concat(fixtures[i][2], fixtures[i][3])) 118 | const actual = new Uint8Array(sodium.crypto_sign_BYTES + message.length) 119 | 120 | sodium.crypto_sign(actual, message, secretKey) 121 | 122 | if (Buffer.compare(actual, expected) !== 0) { 123 | t.fail('Failed on fixture #' + i) 124 | t.end() 125 | return 126 | } 127 | } 128 | 129 | t.pass('Passed all fixtures') 130 | t.end() 131 | }) 132 | 133 | test('crypto_sign_verify_detached fixtures', function (t) { 134 | const fixtures = require('./fixtures/crypto_sign.json') 135 | 136 | for (let i = 0; i < fixtures.length; i++) { 137 | const publicKey = new Uint8Array(fixtures[i][1]) 138 | const message = new Uint8Array(fixtures[i][3]) 139 | const signature = new Uint8Array(fixtures[i][2]) 140 | 141 | if (!sodium.crypto_sign_verify_detached(signature, message, publicKey)) { 142 | t.fail('Failed on fixture #' + i) 143 | t.end() 144 | return 145 | } 146 | } 147 | 148 | t.pass('Passed all fixtures') 149 | t.end() 150 | }) 151 | 152 | test('crypto_sign_detached fixtures', function (t) { 153 | const fixtures = require('./fixtures/crypto_sign.json') 154 | 155 | for (let i = 0; i < fixtures.length; i++) { 156 | const secretKey = new Uint8Array([].concat(fixtures[i][0], fixtures[i][1])) 157 | const message = new Uint8Array(fixtures[i][3]) 158 | 159 | const expected = new Uint8Array(fixtures[i][2]) 160 | const actual = new Uint8Array(sodium.crypto_sign_BYTES) 161 | 162 | sodium.crypto_sign_detached(actual, message, secretKey) 163 | 164 | if (Buffer.compare(actual, expected) !== 0) { 165 | t.fail('Failed on fixture #' + i) 166 | t.end() 167 | return 168 | } 169 | } 170 | 171 | t.pass('Passed all fixtures') 172 | t.end() 173 | }) 174 | 175 | /* eslint-disable camelcase */ 176 | test('libsodium', function (t) { 177 | const sig = new Uint8Array(sodium.crypto_sign_BYTES) 178 | const sm = new Uint8Array(1024 + sodium.crypto_sign_BYTES) 179 | const skpk = new Uint8Array(sodium.crypto_sign_SECRETKEYBYTES) 180 | const pk = new Uint8Array(sodium.crypto_sign_PUBLICKEYBYTES) 181 | const sk = new Uint8Array(sodium.crypto_sign_SECRETKEYBYTES) 182 | 183 | let smlen 184 | let i 185 | let test 186 | 187 | sig.fill(0) 188 | 189 | let pass = true 190 | for (i = 0; i < fixtures.length; i++) { 191 | test = parseTest(fixtures[i]) 192 | 193 | skpk.set(test.sk) 194 | skpk.set(test.pk, sodium.crypto_sign_SEEDBYTES) 195 | 196 | smlen = sodium.crypto_sign_BYTES + test.m.byteLength 197 | 198 | sodium.crypto_sign(sm.subarray(0, test.m.byteLength + sodium.crypto_sign_BYTES), test.m, skpk) 199 | pass &= Buffer.compare(test.sig, sm.subarray(0, 64)) === 0 200 | pass &= sodium.crypto_sign_open(test.m, sm.subarray(0, smlen), test.pk) 201 | 202 | sodium.crypto_sign_detached(sig, test.m, skpk) 203 | 204 | pass &= sig.byteLength !== 0 && sig.byteLength <= sodium.crypto_sign_BYTES 205 | pass &= Buffer.compare(test.sig, sig) === 0 206 | pass &= sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), test.pk) 207 | 208 | if (!pass) t.fail('failed on fixture #' + i) 209 | } 210 | t.pass('passed all fixtures') 211 | 212 | for (let j = 1; j < 8; j++) { 213 | sig[63] ^= (j << 5) 214 | 215 | t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), test.pk)) 216 | 217 | sig[63] ^= (j << 5) 218 | } 219 | 220 | pk.fill(0) 221 | t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk)) 222 | 223 | sig.subarray(0, 32).fill(0xff) 224 | sig[0] = 0xdb 225 | 226 | t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk)) 227 | sodium.crypto_sign_detached(sig, test.m.subarray(0, i), skpk) 228 | 229 | hex2bin(pk, '3eee494fb9eac773144e34b0c755affaf33ea782c0722e5ea8b150e61209ab36') 230 | t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk)) 231 | 232 | hex2bin(pk, '0200000000000000000000000000000000000000000000000000000000000000') 233 | t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk)) 234 | 235 | hex2bin(pk, '0500000000000000000000000000000000000000000000000000000000000000') 236 | t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk)) 237 | 238 | const keypair_seed = new Uint8Array([ 239 | 0x42, 0x11, 0x51, 0xa4, 0x59, 0xfa, 0xea, 0xde, 0x3d, 0x24, 0x71, 240 | 0x15, 0xf9, 0x4a, 0xed, 0xae, 0x42, 0x31, 0x81, 0x24, 0x09, 0x5a, 241 | 0xfa, 0xbe, 0x4d, 0x14, 0x51, 0xa5, 0x59, 0xfa, 0xed, 0xee 242 | ]) 243 | 244 | t.execution(() => sodium.crypto_sign_seed_keypair(pk, sk, keypair_seed)) 245 | t.execution(() => sodium.crypto_sign_keypair(pk, sk)) 246 | 247 | t.ok(sodium.crypto_sign_BYTES > 0) 248 | t.ok(sodium.crypto_sign_SEEDBYTES > 0) 249 | t.ok(sodium.crypto_sign_PUBLICKEYBYTES > 0) 250 | t.ok(sodium.crypto_sign_SECRETKEYBYTES > 0) 251 | t.is(sodium.crypto_sign_BYTES, 64) 252 | t.is(sodium.crypto_sign_SEEDBYTES, 32) 253 | t.is(sodium.crypto_sign_PUBLICKEYBYTES, 32) 254 | t.is(sodium.crypto_sign_SECRETKEYBYTES, 64) 255 | 256 | t.end() 257 | }) 258 | 259 | test('ed25519 convert', function (t) { 260 | const keypair_seed = new Uint8Array([ 261 | 0x42, 0x11, 0x51, 0xa4, 0x59, 0xfa, 0xea, 0xde, 0x3d, 0x24, 0x71, 262 | 0x15, 0xf9, 0x4a, 0xed, 0xae, 0x42, 0x31, 0x81, 0x24, 0x09, 0x5a, 263 | 0xfa, 0xbe, 0x4d, 0x14, 0x51, 0xa5, 0x59, 0xfa, 0xed, 0xee 264 | ]) 265 | 266 | const ed25519_pk = new Uint8Array(sodium.crypto_sign_PUBLICKEYBYTES) 267 | const ed25519_skpk = new Uint8Array(sodium.crypto_sign_SECRETKEYBYTES) 268 | const curve25519_pk = new Uint8Array(sodium.crypto_scalarmult_BYTES) 269 | const curve25519_pk2 = new Uint8Array(sodium.crypto_scalarmult_BYTES) 270 | const curve25519_sk = new Uint8Array(sodium.crypto_scalarmult_BYTES) 271 | 272 | t.ok(sodium.crypto_sign_SEEDBYTES <= sodium.crypto_hash_sha512_BYTES) 273 | 274 | sodium.crypto_sign_seed_keypair(ed25519_pk, ed25519_skpk, keypair_seed) 275 | sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk) 276 | sodium.crypto_sign_ed25519_sk_to_curve25519(curve25519_sk, ed25519_skpk) 277 | 278 | const expected_pk = new Uint8Array([ 279 | 0xf1, 0x81, 0x4f, 0x0e, 0x8f, 0xf1, 0x04, 0x3d, 0x8a, 0x44, 0xd2, 0x5b, 280 | 0xab, 0xff, 0x3c, 0xed, 0xca, 0xe6, 0xc2, 0x2c, 0x3e, 0xda, 0xa4, 0x8f, 281 | 0x85, 0x7a, 0xe7, 0x0d, 0xe2, 0xba, 0xae, 0x50 282 | ]) 283 | 284 | const expected_sk = new Uint8Array([ 285 | 0x80, 0x52, 0x03, 0x03, 0x76, 0xd4, 0x71, 0x12, 0xbe, 0x7f, 0x73, 0xed, 286 | 0x7a, 0x01, 0x92, 0x93, 0xdd, 0x12, 0xad, 0x91, 0x0b, 0x65, 0x44, 0x55, 287 | 0x79, 0x8b, 0x46, 0x67, 0xd7, 0x3d, 0xe1, 0x66 288 | ]) 289 | 290 | t.alike(curve25519_pk, expected_pk) 291 | t.alike(curve25519_sk, expected_sk) 292 | 293 | for (let i = 0; i < 500; i++) { 294 | sodium.crypto_sign_keypair(ed25519_pk, ed25519_skpk) 295 | sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk) 296 | 297 | sodium.crypto_sign_ed25519_sk_to_curve25519(curve25519_sk, ed25519_skpk) 298 | sodium.crypto_scalarmult_base(curve25519_pk2, curve25519_sk) 299 | if (Buffer.compare(curve25519_pk, curve25519_pk2) !== 0) t.fail() 300 | } 301 | t.pass('passed all cases') 302 | 303 | ed25519_pk.fill(0) 304 | t.exception(() => { 305 | sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk) 306 | }) 307 | 308 | t.exception(() => { 309 | ed25519_pk[0] = 2 310 | sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk) 311 | }) 312 | 313 | t.exception(() => { 314 | ed25519_pk[0] = 5 315 | sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk) 316 | }) 317 | 318 | t.end() 319 | }) 320 | 321 | function parseTest (t) { 322 | return { 323 | sk: new Uint8Array(t[0]), 324 | pk: new Uint8Array(t[1]), 325 | sig: new Uint8Array(t[2]), 326 | m: new Uint8Array(t[3]) 327 | } 328 | } 329 | 330 | function hex2bin (buf, hex) { 331 | for (let i = 0; i < hex.length / 2; i++) { 332 | buf[i] = Number('0x' + hex.slice(2 * i, 2 * i + 1)) 333 | } 334 | } 335 | -------------------------------------------------------------------------------- /test/crypto_stream.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('crypto_stream', function (t) { 6 | const buf = Buffer.alloc(50) 7 | const nonce = random(sodium.crypto_stream_NONCEBYTES) 8 | const key = random(sodium.crypto_stream_KEYBYTES) 9 | 10 | sodium.crypto_stream(buf, nonce, key) 11 | 12 | t.not(buf, Buffer.alloc(50), 'contains noise now') 13 | const copy = Buffer.from(buf.toString('hex'), 'hex') 14 | 15 | sodium.crypto_stream(buf, nonce, key) 16 | t.alike(buf, copy, 'predictable from nonce, key') 17 | }) 18 | 19 | test('crypto_stream_xor', function (t) { 20 | const message = Buffer.from('Hello, World!') 21 | const nonce = random(sodium.crypto_stream_NONCEBYTES) 22 | const key = random(sodium.crypto_stream_KEYBYTES) 23 | 24 | sodium.crypto_stream_xor(message, message, nonce, key) 25 | 26 | t.not(message, Buffer.from('Hello, World!'), 'encrypted') 27 | 28 | sodium.crypto_stream_xor(message, message, nonce, key) 29 | 30 | t.alike(message, Buffer.from('Hello, World!'), 'decrypted') 31 | }) 32 | 33 | test.skip('crypto_stream_xor state', function (t) { 34 | const message = Buffer.from('Hello, world!') 35 | const nonce = random(sodium.crypto_stream_NONCEBYTES) 36 | const key = random(sodium.crypto_stream_KEYBYTES) 37 | 38 | const out = Buffer.alloc(message.length) 39 | 40 | const state = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES) 41 | sodium.crypto_stream_xor_init(state, nonce, key) 42 | 43 | for (let i = 0; i < message.length; i++) { 44 | sodium.crypto_stream_xor_update(state, out.slice(i, i + 1), message.slice(i, i + 1)) 45 | } 46 | 47 | sodium.crypto_stream_xor_final(state) 48 | sodium.crypto_stream_xor(out, out, nonce, key) 49 | t.alike(out, message, 'decrypted') 50 | }) 51 | 52 | test.skip('crypto_stream_xor state with empty buffers', function (t) { 53 | const message = Buffer.from('Hello, world!') 54 | const nonce = random(sodium.crypto_stream_NONCEBYTES) 55 | const key = random(sodium.crypto_stream_KEYBYTES) 56 | 57 | const out = Buffer.alloc(message.length) 58 | 59 | const state = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES) 60 | sodium.crypto_stream_xor_init(state, nonce, key) 61 | 62 | sodium.crypto_stream_xor_update(state, Buffer.alloc(0), Buffer.alloc(0)) 63 | 64 | for (let i = 0; i < message.length; i++) { 65 | sodium.crypto_stream_xor_update(state, out.slice(i, i + 1), message.slice(i, i + 1)) 66 | sodium.crypto_stream_xor_update(state, Buffer.alloc(0), Buffer.alloc(0)) 67 | } 68 | 69 | sodium.crypto_stream_xor_final(state) 70 | sodium.crypto_stream_xor(out, out, nonce, key) 71 | t.alike(out, message, 'decrypted') 72 | }) 73 | 74 | test.skip('crypto_stream_xor state long stream', function (t) { 75 | const nonce = random(sodium.crypto_stream_NONCEBYTES) 76 | const key = random(sodium.crypto_stream_KEYBYTES) 77 | 78 | const encState = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES) 79 | const decState = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES) 80 | 81 | sodium.crypto_stream_xor_init(encState, nonce, key) 82 | sodium.crypto_stream_xor_init(decState, nonce, key) 83 | const plain = [] 84 | const encrypted = [] 85 | const decrypted = [] 86 | 87 | for (let i = 0; i < 1000; i++) { 88 | const next = random(61) 89 | plain.push(next) 90 | 91 | const enc = Buffer.alloc(61) 92 | sodium.crypto_stream_xor_update(encState, enc, next) 93 | encrypted.push(enc) 94 | 95 | const dec = Buffer.alloc(61) 96 | sodium.crypto_stream_xor_update(decState, dec, enc) 97 | decrypted.push(dec) 98 | } 99 | 100 | const enc2 = Buffer.alloc(1000 * 61) 101 | sodium.crypto_stream_xor(enc2, Buffer.concat(plain), nonce, key) 102 | 103 | t.alike(Buffer.concat(encrypted), enc2, 'same as encrypting all at once') 104 | t.alike(Buffer.concat(decrypted), Buffer.concat(plain), 'decrypts') 105 | }) 106 | 107 | test.skip('crypto_stream_xor state long stream (random chunks)', function (t) { 108 | const nonce = random(sodium.crypto_stream_NONCEBYTES) 109 | const key = random(sodium.crypto_stream_KEYBYTES) 110 | 111 | const encState = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES) 112 | const decState = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES) 113 | 114 | sodium.crypto_stream_xor_init(encState, nonce, key) 115 | sodium.crypto_stream_xor_init(decState, nonce, key) 116 | const plain = [] 117 | const encrypted = [] 118 | const decrypted = [] 119 | 120 | for (let i = 0; i < 10000; i++) { 121 | const len = Math.floor(Math.random() * 256) 122 | const next = random(len) 123 | plain.push(next) 124 | 125 | const enc = Buffer.alloc(len) 126 | sodium.crypto_stream_xor_update(encState, enc, next) 127 | encrypted.push(enc) 128 | 129 | const dec = Buffer.alloc(len) 130 | sodium.crypto_stream_xor_update(decState, dec, enc) 131 | decrypted.push(dec) 132 | } 133 | 134 | const enc2 = Buffer.alloc(Buffer.concat(plain).length) 135 | sodium.crypto_stream_xor(enc2, Buffer.concat(plain), nonce, key) 136 | 137 | t.alike(Buffer.concat(encrypted), enc2, 'same as encrypting all at once') 138 | t.alike(Buffer.concat(decrypted), Buffer.concat(plain), 'decrypts') 139 | }) 140 | 141 | test.skip('crypto_stream_xor state long stream (random chunks) with empty buffers', function (t) { 142 | const nonce = random(sodium.crypto_stream_NONCEBYTES) 143 | const key = random(sodium.crypto_stream_KEYBYTES) 144 | 145 | const encState = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES) 146 | const decState = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES) 147 | 148 | sodium.crypto_stream_xor_init(encState, nonce, key) 149 | sodium.crypto_stream_xor_init(decState, nonce, key) 150 | const plain = [] 151 | const encrypted = [] 152 | const decrypted = [] 153 | 154 | for (let i = 0; i < 10000; i++) { 155 | const len = Math.floor(Math.random() * 256) 156 | const next = random(len) 157 | plain.push(next) 158 | 159 | sodium.crypto_stream_xor_update(encState, Buffer.alloc(0), Buffer.alloc(0)) 160 | 161 | const enc = Buffer.alloc(len) 162 | sodium.crypto_stream_xor_update(encState, enc, next) 163 | encrypted.push(enc) 164 | 165 | const dec = Buffer.alloc(len) 166 | sodium.crypto_stream_xor_update(decState, dec, enc) 167 | decrypted.push(dec) 168 | sodium.crypto_stream_xor_update(decState, Buffer.alloc(0), Buffer.alloc(0)) 169 | } 170 | 171 | const enc2 = Buffer.alloc(Buffer.concat(plain).length) 172 | sodium.crypto_stream_xor(enc2, Buffer.concat(plain), nonce, key) 173 | 174 | t.alike(Buffer.concat(encrypted), enc2, 'same as encrypting all at once') 175 | t.alike(Buffer.concat(decrypted), Buffer.concat(plain), 'decrypts') 176 | }) 177 | 178 | test.skip('crypto_stream_xor state after GC', function (t) { 179 | const message = Buffer.from('Hello, world!') 180 | let nonce = random(sodium.crypto_stream_NONCEBYTES) 181 | let key = random(sodium.crypto_stream_KEYBYTES) 182 | 183 | const out = Buffer.alloc(message.length) 184 | 185 | const state = Buffer.alloc(sodium.crypto_stream_xor_STATEBYTES) 186 | sodium.crypto_stream_xor_init(state, nonce, key) 187 | 188 | const nonceCopy = Buffer.from(nonce.toString('hex'), 'hex') 189 | const keyCopy = Buffer.from(key.toString('hex'), 'hex') 190 | nonce = null 191 | key = null 192 | 193 | forceGC() 194 | 195 | for (let i = 0; i < message.length; i++) { 196 | sodium.crypto_stream_xor_update(state, out.slice(i, i + 1), message.slice(i, i + 1)) 197 | } 198 | 199 | sodium.crypto_stream_xor_final(state) 200 | sodium.crypto_stream_xor(out, out, nonceCopy, keyCopy) 201 | t.alike(out, message, 'decrypted') 202 | }) 203 | 204 | function random (n) { 205 | const buf = Buffer.alloc(n) 206 | sodium.randombytes_buf(buf) 207 | return buf 208 | } 209 | 210 | function forceGC () { 211 | require('v8').setFlagsFromString('--expose-gc') 212 | require('vm').runInNewContext('gc')() 213 | } 214 | -------------------------------------------------------------------------------- /test/fixtures/crypto_kdf.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"error": false, "id":0, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"a0c724404728c8bb95e5433eb6a9716171144d61efb23e74b873fcbeda51d8071b5d70aae12066dfc94ce943f145aa176c055040c3dd73b0a15e36254d450614"}, 3 | {"error": false, "id":1, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"02507f144fa9bf19010bf7c70b235b4c2663cc00e074f929602a5e2c10a780757d2a3993d06debc378a90efdac196dd841817b977d67b786804f6d3cd585bab5"}, 4 | {"error": false, "id":2, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"1944da61ff18dc2028c3578ac85be904931b83860896598f62468f1cb5471c6a344c945dbc62c9aaf70feb62472d17775ea5db6ed5494c68b7a9a59761f39614"}, 5 | {"error": false, "id":3, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"131c0ca1633ed074986215b264f6e0474f362c52b029effc7b0f75977ee89cc95d85c3db87f7e399197a25411592beeeb7e5128a74646a460ecd6deb4994b71e"}, 6 | {"error": false, "id":4, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"a7023a0bf9be245d078aed26bcde0465ff0cc0961196a5482a0ff4ff8b4015971e13611f50529cb408f5776b14a90e7c3dd9160a22211db64ff4b5c0b9953680"}, 7 | {"error": false, "id":5, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"50f49313f3a05b2e565c13feedb44daa675cafd42c2b2cf9edbce9c949fbfc3f175dcb738671509ae2ea66fb85e552394d479afa7fa3affe8791744796b94176"}, 8 | {"error": false, "id":6, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"13b58d6d69780089293862cd59a1a8a4ef79bb850e3f3ba41fb22446a7dd1dc4da4667d37b33bf1225dcf8173c4c349a5d911c5bd2db9c5905ed70c11e809e3b"}, 9 | {"error": false, "id":7, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"15d44b4b44ffa006eeceeb508c98a970aaa573d65905687b9e15854dec6d49c612757e149f78268f727660dedf9abce22a9691feb20a01b0525f4b47a3cf19db"}, 10 | {"error": false, "id":8, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"9aebba11c5428ae8225716369e30a48943be39159a899f804e9963ef78822e186c21fe95bb0b85e60ef03a6f58d0b9d06e91f79d0ab998450b8810c73ca935b4"}, 11 | {"error": false, "id":9, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"70f9b83e463fb441e7a4c43275125cd5b19d8e2e4a5d179a39f5db10bbce745a199104563d308cf8d4c6b27bbb759ded232f5bdb7c367dd632a9677320dfe416"}, 12 | {"error": true, "id":0, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":0, "subkey":null}, 13 | {"error": true, "id":1, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":1, "subkey":null}, 14 | {"error": true, "id":2, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":2, "subkey":null}, 15 | {"error": true, "id":3, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":3, "subkey":null}, 16 | {"error": true, "id":4, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":4, "subkey":null}, 17 | {"error": true, "id":5, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":5, "subkey":null}, 18 | {"error": true, "id":6, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":6, "subkey":null}, 19 | {"error": true, "id":7, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":7, "subkey":null}, 20 | {"error": true, "id":8, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":8, "subkey":null}, 21 | {"error": true, "id":9, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":9, "subkey":null}, 22 | {"error": true, "id":10, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":10, "subkey":null}, 23 | {"error": true, "id":11, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":11, "subkey":null}, 24 | {"error": true, "id":12, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":12, "subkey":null}, 25 | {"error": true, "id":13, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":13, "subkey":null}, 26 | {"error": true, "id":14, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":14, "subkey":null}, 27 | {"error": true, "id":15, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":15, "subkey":null}, 28 | {"error": false, "id":16, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":16, "subkey":"a529216624ef9161e4cf117272aafff2"}, 29 | {"error": false, "id":17, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":17, "subkey":"068bd6940b80c6cc2530a68c31d9f4e323"}, 30 | {"error": false, "id":18, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":18, "subkey":"0acf4f6c74a590c8a1c0997ec9a1a3f48b2a"}, 31 | {"error": false, "id":19, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":19, "subkey":"ac17a37ce74c0efece75f9337de20795dbadcc"}, 32 | {"error": false, "id":20, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":20, "subkey":"268214dc9477a2e3c1022829f934ab992a5a3d84"}, 33 | {"error": false, "id":21, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":21, "subkey":"33b76197b4531665e494760909eda1cc570e7da9bb"}, 34 | {"error": false, "id":22, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":22, "subkey":"3d4efbc569ca7f858ad4f49c56b820986a406e6eebbc"}, 35 | {"error": false, "id":23, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":23, "subkey":"983fea27520f507c40231f9557908f07c095bdf4a4ce5d"}, 36 | {"error": false, "id":24, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":24, "subkey":"94d678717625e011995c7355f2092267dee47bf0722dd380"}, 37 | {"error": false, "id":25, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":25, "subkey":"198901896c4f51e74ffa8b2805415c6eaba5accfc85a6e6b34"}, 38 | {"error": false, "id":26, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":26, "subkey":"4ffabb81d49021f85ef5d2a713ab02ae86bc2e7d1522f5e077fe"}, 39 | {"error": false, "id":27, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":27, "subkey":"eebc3d55b3f4fc8b64d2474063254da7db98e7398dfdd510e28075"}, 40 | {"error": false, "id":28, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":28, "subkey":"22c134b9d664e1bdb14dc309a936bf1512b19e4f5175642efb1a0df7"}, 41 | {"error": false, "id":29, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":29, "subkey":"4b179762bfc8e27a9e575113faa76247b9c046d6f22d5a02e2910a299b"}, 42 | {"error": false, "id":30, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":30, "subkey":"abc45eb2b031307b8822c7e59a43f4108850c34a7445936bc848422251c4"}, 43 | {"error": false, "id":31, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":31, "subkey":"d6565bd3265b6373f4f6a6b6458e981006da5e9d532ce94ca4737e188995e9"}, 44 | {"error": false, "id":32, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":32, "subkey":"154b291f11196737f8b7f491e4ca11764e0227d34f94295408a869f007aa8618"}, 45 | {"error": false, "id":33, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":33, "subkey":"e9dd395570e09ebb523ffc6ba098a38b17bc4944f14bd3725bdd7edbd8bcff54fb"}, 46 | {"error": false, "id":34, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":34, "subkey":"7248294d37159e85bacde68c7762a673794c91b811e05f4e3b9e3ecc82bfcf63a2cd"}, 47 | {"error": false, "id":35, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":35, "subkey":"d060ee4d93f8de6d9ae60fca9596413455183a1f83c7a2381227cec8f7a217e4072f85"}, 48 | {"error": false, "id":36, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":36, "subkey":"20790290347b9b0f413a954f40e52e270b3b45417e96c8733161672188701c08dd76cc3d"}, 49 | {"error": false, "id":37, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":37, "subkey":"7674188112a1ab8d3926d468be8e51d788ce4144bb20ff842034e4d1ddab3929a4f1a13a74"}, 50 | {"error": false, "id":38, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":38, "subkey":"a2ab1f980a47472d8a539f20410cc9bf143d941331ab2259ea73684c0608939c5b23e9cbcb3d"}, 51 | {"error": false, "id":39, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":39, "subkey":"f4cfbe3050f15ebbaf8d2f3bf3a678c01fc21ee1f4be07d0744c7fbf4835ea9d9472a3d785c24c"}, 52 | {"error": false, "id":40, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":40, "subkey":"66efa5dfe3efd4cc8ca25f2d622c97a20a192d7add965f26b002b7eb81aae4203c0e5f07fd945845"}, 53 | {"error": false, "id":41, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":41, "subkey":"ad5d8031055c96dc9db10285206d7edc38d3af85736df8a3b5fdd30a318e80c28d9b26c95a60fa3e68"}, 54 | {"error": false, "id":42, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":42, "subkey":"9107c8a57a2c9ca40158f33ca0bfb64c095d2f21ca98bb7138477599330a36cdfc2ae5751e370d0e024e"}, 55 | {"error": false, "id":43, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":43, "subkey":"b0c190177358b955ebebc5e0b86ec91dde3b6f1982ea4d68ec5ec3bdd6527c362e5275600b263601c98452"}, 56 | {"error": false, "id":44, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":44, "subkey":"31bfaaad4adde0f87d87372e398c42cb7befe065ab2957ebb91ef9dc534b410783899b2e1e84221286f3bab4"}, 57 | {"error": false, "id":45, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":45, "subkey":"2258dd1f3e516cb8e3d1f6c45808573c365192f073698939721af8961a02a8bdd002a31fd239b9498663a01f27"}, 58 | {"error": false, "id":46, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":46, "subkey":"7c7a88016610493bb44a9432a88b50f97e2e94383972ff95da826692d96c52d82f86899b3561ec9c95a8b1bf3213"}, 59 | {"error": false, "id":47, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":47, "subkey":"3929dc7473be4c633be9e08801a8abd284dc0c6154c5c81a4c18259699dd86753c5e14fbd723be46ebb04f4ab3058c"}, 60 | {"error": false, "id":48, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":48, "subkey":"30b720220015fa60daa69c83f9754d772b1b2dd12ab6baaa2f4edab458d4d251c1cddb8c4a554f3eb13969316b890fbd"}, 61 | {"error": false, "id":49, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":49, "subkey":"33fa2412a5c3294d49e964419e96d043a2099a72b3351e3bed0f07e12255c95b509ea9bf2963a4c0fe9cc2314dbc44f673"}, 62 | {"error": false, "id":50, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":50, "subkey":"ca891d2c82a6a8f833dc1a05f190bab6de221307eab1dd2c88341d4d2537a2fc0056b0d04d8104fd3fe89e1ea20877893e81"}, 63 | {"error": false, "id":51, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":51, "subkey":"fd78ac89a64d03672ad99d663f2613d15277cda1636e334a1706b7211ff1f3a3b3d2e671e391c75e3d242c482ce7e1b8b427ed"}, 64 | {"error": false, "id":52, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":52, "subkey":"36a6072743d3aafd3ee89344b9ef92cb58a2853ae92b20283520439fcb55afffd3d4b5e4e8c92a85d3cf74497bdcf68bbf1fcf93"}, 65 | {"error": false, "id":53, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":53, "subkey":"a90afcfaffec1105ad05fdaa9473fb5daf1bf8fb376b7326db46ef4c120c553188c69131933371d409eb56d66d5adca618e1dac65b"}, 66 | {"error": false, "id":54, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":54, "subkey":"9b990d1fcddbdb5e5c7a48a6a2a666e02e7d4d4a814ece40660d99e1c02d5f023c56ae82526fc6dc8c933d0add92fc376efcddd55a42"}, 67 | {"error": false, "id":55, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":55, "subkey":"ec545dcf456d1b0907c07418a42bf2b3d668b4797ba6874bf0d563f5f429a820f02177dd4d05e639a06807c9619fee54ffe07712493543"}, 68 | {"error": false, "id":56, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":56, "subkey":"b0106957626894586682a275f69ed4533e2f94334cc0430394b68d82679aca00dd579e712bdd2d7f5bbce9a050269739bd8427b75b06027f"}, 69 | {"error": false, "id":57, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":57, "subkey":"05751bfeebb480c9bca0d25d8197e2673845f405d7fb9793e29169ac19956c525f6e637f3d5ea50597b04342afed4ca16f988b4f21a34f1902"}, 70 | {"error": false, "id":58, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":58, "subkey":"7b4e4294d3f64085b5c09be73548f1f5cb5c6f04e57ce6cdd3077e2fb37640bf1ca0c6393b87d48a6b7e3e42628bd30fca132ded03ce51f71d9d"}, 71 | {"error": false, "id":59, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":59, "subkey":"082d248862cbfd71a634769a4b1cf52a4af47ace5b9ea4d583ca52207efc7234a6d321788130cbdec122579ad03afe00bc68c9fb3f68dd0532a96f"}, 72 | {"error": false, "id":60, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":60, "subkey":"a2b39b4428d981013e8a9c0e41b3eed504983fc18dc4b60332b1ab28b9705228147bdb95cc17889d5f0f9cfb7fd16f9d414b1a829346a8922e945b40"}, 73 | {"error": false, "id":61, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":61, "subkey":"efbf0f8bda1b9ef24fe389f1cf0c0c8a08bca03fc95badabb79a487d8ce1351683f59183aa6229f880d69ad60114ac128f69b2be250109972ab1f3fc3b"}, 74 | {"error": false, "id":62, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":62, "subkey":"dfe0ba2a6de25fa06b47375e9d9cf6c6fa1493a8a2a81c28d6e09bc161057b445659db76e92e349ff44f34a2a9e3bcaa6b84b21bae56f1499c170ab81af0"}, 75 | {"error": false, "id":63, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":63, "subkey":"02f9cbdb10759314515b01379c474ad74a1b575137bd3949776dbcfc3e18060cb13ee1f6dcf86035768fc7be63e01de321cacbfade209900dd94273fd8e176"}, 76 | {"error": false, "id":64, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":64, "subkey":"06ae14308eeeda62a00cb6d5edf18d1707029515db98f472bbf0617419301b1d4f4f2ab65849446be46f87e1d31c6c74283897b9976f70d8a16253ac927e0d9f"}, 77 | {"error": true, "id":65, "context":"4b44462074657374", "key":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "subkey_len":65, "subkey":null} 78 | ] 79 | -------------------------------------------------------------------------------- /test/fixtures/mprotect_noaccess.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const sodium = require('../..') 3 | const buf = sodium.sodium_malloc(1) 4 | sodium.sodium_mprotect_noaccess(buf) 5 | buf[0] 6 | process.send('read') 7 | -------------------------------------------------------------------------------- /test/fixtures/mprotect_readonly.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const sodium = require('../..') 3 | const buf = sodium.sodium_malloc(1) 4 | sodium.sodium_mprotect_readonly(buf) 5 | buf[0] 6 | process.send('read') 7 | buf[0] = 1 8 | process.send('write') 9 | -------------------------------------------------------------------------------- /test/fixtures/mprotect_readwrite.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const sodium = require('../..') 3 | const buf = sodium.sodium_malloc(1) 4 | sodium.sodium_mprotect_noaccess(buf) 5 | sodium.sodium_mprotect_readwrite(buf) 6 | buf[0] 7 | process.send('read') 8 | buf[0] = 1 9 | process.send('write') 10 | sodium.sodium_mprotect_readonly(buf) 11 | process.send(buf[0] === 1 ? 'did_write' : 'did_not_write') 12 | -------------------------------------------------------------------------------- /test/helpers.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test('sodium_memcmp', function (t) { 6 | const b1 = Buffer.from([0, 1, 2, 3]) 7 | const b2 = Buffer.from([3, 2, 1, 0]) 8 | 9 | t.exception.all(_ => sodium.sodium_memcmp(), 'no args') 10 | t.exception.all(_ => sodium.sodium_memcmp(b1), 'arg mismatch') 11 | t.exception.all(_ => sodium.sodium_memcmp(b1, b2.slice(1)), 'length mismatch') 12 | t.ok(sodium.sodium_memcmp(Buffer.alloc(0), Buffer.alloc(0))) 13 | t.ok(sodium.sodium_memcmp(Buffer.alloc(5), Buffer.alloc(5))) 14 | t.ok(sodium.sodium_memcmp(b1, b1)) 15 | t.absent(sodium.sodium_memcmp(b2, b1)) 16 | t.absent(sodium.sodium_memcmp(b1, b2)) 17 | }) 18 | 19 | test.skip('sodium_compare', function (t) { 20 | const one = Buffer.from([1]) 21 | const two = Buffer.from([2]) 22 | const three = Buffer.from([3]) 23 | 24 | t.is(sodium.sodium_compare(Buffer.alloc(0), Buffer.alloc(0)), 0) 25 | t.is(sodium.sodium_compare(one, one), 0) 26 | t.is(sodium.sodium_compare(two, two), 0) 27 | t.is(sodium.sodium_compare(three, three), 0) 28 | 29 | t.is(sodium.sodium_compare(one, two), -1) 30 | t.is(sodium.sodium_compare(one, three), -1) 31 | t.is(sodium.sodium_compare(two, one), 1) 32 | t.is(sodium.sodium_compare(three, one), 1) 33 | 34 | t.is(sodium.sodium_compare(two, three), -1) 35 | t.is(sodium.sodium_compare(three, two), 1) 36 | }) 37 | 38 | test.skip('sodium_add', function (t) { 39 | const large = Buffer.alloc(32) 40 | large[23] = 0b00000011 41 | const largeLessOne = Buffer.alloc(32) 42 | largeLessOne[23] = 0b00000001 43 | 44 | const c = Buffer.from(large) 45 | 46 | sodium.sodium_add(c, largeLessOne) 47 | t.ok(large[23], 4) 48 | 49 | const overflow = Buffer.alloc(56, 0xff) 50 | const one = Buffer.alloc(56) 51 | one[0] = 1 52 | sodium.sodium_add(overflow, one) 53 | 54 | t.ok(sodium.sodium_is_zero(overflow)) 55 | }) 56 | 57 | test.skip('sub', function (t) { 58 | const large = Buffer.alloc(32) 59 | large[23] = 0b00000011 60 | const largeLessOne = Buffer.alloc(32) 61 | largeLessOne[23] = 0b00000001 62 | 63 | const c = Buffer.from(large) 64 | 65 | sodium.sodium_sub(c, largeLessOne) 66 | t.ok(large[23], 2) 67 | 68 | const overflow = Buffer.alloc(56, 0x00) 69 | const one = Buffer.alloc(56) 70 | one[0] = 1 71 | sodium.sodium_sub(overflow, one) 72 | 73 | t.ok(sodium.sodium_memcmp(overflow, Buffer.alloc(56, 0xff))) 74 | }) 75 | 76 | test('sodium_increment', function (t) { 77 | const zero = Buffer.alloc(4) 78 | sodium.sodium_increment(zero) 79 | 80 | t.ok(zero[0], 1) 81 | 82 | const overflow = Buffer.alloc(56, 0xff) 83 | sodium.sodium_increment(overflow) 84 | 85 | t.ok(sodium.sodium_is_zero(overflow)) 86 | }) 87 | 88 | test('sodium_is_zero', function (t) { 89 | const buf = Buffer.from([0, 0, 0, 1]) 90 | 91 | t.exception.all(_ => sodium.sodium_is_zero(), 'no args') 92 | t.exception.all(_ => sodium.sodium_is_zero(null), 'missing buf') 93 | 94 | t.ok(sodium.sodium_is_zero(Buffer.alloc(0)), 'empty buffer') 95 | t.ok(sodium.sodium_is_zero(buf.subarray(0, 0)), 'zero bytes') 96 | t.ok(sodium.sodium_is_zero(buf.subarray(0, 1)), 'one byte') 97 | t.ok(sodium.sodium_is_zero(buf.subarray(0, 2)), 'two bytes') 98 | t.ok(sodium.sodium_is_zero(buf.subarray(0, 3)), '3 bytes') 99 | t.absent(sodium.sodium_is_zero(buf), 'first non-zero byte') 100 | t.ok(sodium.sodium_is_zero(buf.subarray(1, 2)), 'view') 101 | t.ok(sodium.sodium_is_zero(buf.subarray(1, 2)), 'view') 102 | t.absent(sodium.sodium_is_zero(buf.subarray(3)), 'view') 103 | }) 104 | -------------------------------------------------------------------------------- /test/memory.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | const fork = require('child_process').fork 5 | 6 | test.skip('sodium_mprotect_noaccess', function (t) { 7 | t.plan(1) 8 | const p = fork(require.resolve('./fixtures/mprotect_noaccess')) 9 | 10 | p.on('message', function () { 11 | t.fail() 12 | }) 13 | p.on('exit', function (code, signal) { 14 | t.ok(p.signalCode !== null || p.exitCode > 0) 15 | }) 16 | }) 17 | 18 | test.skip('sodium_mprotect_readonly', function (t) { 19 | t.plan(2) 20 | const p = fork(require.resolve('./fixtures/mprotect_readonly')) 21 | 22 | p.on('message', function (msg) { 23 | t.ok(msg === 'read') 24 | }) 25 | p.on('exit', function (code, signal) { 26 | t.ok(p.signalCode !== null || p.exitCode > 0) 27 | }) 28 | }) 29 | 30 | test.skip('sodium_mprotect_readwrite', function (t) { 31 | t.plan(4) 32 | const p = fork(require.resolve('./fixtures/mprotect_readwrite')) 33 | 34 | p.on('message', function (msg) { 35 | switch (msg) { 36 | case 'read': t.pass() 37 | break 38 | case 'write': t.pass() 39 | break 40 | case 'did_write': t.pass() 41 | break 42 | case 'did_not_write': t.fail() 43 | break 44 | default: t.fail() 45 | break 46 | } 47 | }) 48 | p.on('exit', function (code, signal) { 49 | t.ok(p.signalCode === null || p.exitCode === 0) 50 | }) 51 | }) 52 | 53 | test('sodium_memzero', function (t) { 54 | const buf = Buffer.alloc(10, 0xab) 55 | const exp = Buffer.alloc(10, 0xab) 56 | const zero = Buffer.alloc(10) 57 | 58 | t.alike(buf, exp, 'buffers start out with same content') 59 | t.unlike(buf, zero, 'buffer is not zero') 60 | 61 | sodium.sodium_memzero(buf) 62 | t.unlike(buf, exp, 'buffers are not longer the same') 63 | t.alike(buf, zero, 'buffer is now zeroed') 64 | }) 65 | 66 | test.skip('sodium_mlock / sodium_munlock', function (t) { 67 | const buf = Buffer.alloc(10, 0x18) 68 | const exp = Buffer.alloc(10, 0x18) 69 | 70 | sodium.sodium_mlock(buf) 71 | t.absent(buf.secure) 72 | t.alike(buf, exp, 'mlock did not corrupt data') 73 | sodium.sodium_munlock(buf) 74 | t.absent(buf.secure) 75 | t.alike(buf, Buffer.alloc(10), 'munlock did zero data') 76 | }) 77 | 78 | test('sodium_malloc', function (t) { 79 | const empty = sodium.sodium_malloc(0) 80 | const small = sodium.sodium_malloc(1) 81 | const large = sodium.sodium_malloc(1e8) 82 | 83 | // sodium-javascript does not set secure prop 84 | 85 | // t.ok(empty.secure) 86 | // t.ok(small.secure) 87 | // t.ok(large.secure) 88 | 89 | t.ok(empty.length === 0, 'has correct size') 90 | t.ok(small.length === 1, 'has correct size') 91 | t.ok(large.length === 1e8, 'has correct size') 92 | 93 | // const expected = Buffer.from([0xdb]) 94 | // expected.secure = true 95 | // t.alike(small, expected, 'has canary content') 96 | 97 | // test gc 98 | for (let i = 0; i < 1e3; i++) { 99 | if (sodium.sodium_malloc(256).length !== 256) { 100 | t.fail('allocated incorrect size') 101 | } 102 | } 103 | t.ok(empty.length === 0, 'retained correct size') 104 | t.ok(small.length === 1, 'retained correct size') 105 | t.ok(large.length === 1e8, 'retained correct size') 106 | }) 107 | 108 | test('sodium_free', function (t) { 109 | if (process.version.startsWith('v10')) { 110 | t.comment('Skipping free test on v10') 111 | return 112 | } 113 | const buf = sodium.sodium_malloc(1) 114 | t.ok(buf.byteLength === 1) 115 | sodium.sodium_free(buf) 116 | t.ok(buf.byteLength === 0) 117 | }) 118 | 119 | test.skip('sodium_malloc bounds', function (t) { 120 | t.throws(function () { 121 | sodium.sodium_malloc(-1) 122 | }, 'too small') 123 | t.throws(function () { 124 | sodium.sodium_malloc(Number.MAX_SAFE_INTEGER) 125 | }, 'too large') 126 | }) 127 | -------------------------------------------------------------------------------- /test/randombytes.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const test = require('brittle') 3 | const sodium = require('..') 4 | 5 | test.skip('constants', function (t) { 6 | t.alike(typeof sodium.randombytes_SEEDBYTES, 'number', 'randombytes_SEEDBYTES is number') 7 | }) 8 | 9 | test.skip('randombytes_random', function (t) { 10 | for (let i = 0; i < 1e6; i++) { 11 | const n = sodium.randombytes_random() 12 | if (n > 0xffffffff || n < 0) t.fail() 13 | } 14 | }) 15 | 16 | test.skip('randombytes_uniform', function (t) { 17 | const p = 5381 18 | for (let i = 0; i < 1e6; i++) { 19 | const n = sodium.randombytes_uniform(5381) 20 | if (n >= p || n < 0) t.fail() 21 | } 22 | }) 23 | 24 | test('randombytes_buf', function (t) { 25 | let buf = null 26 | 27 | buf = Buffer.alloc(10) 28 | sodium.randombytes_buf(buf) 29 | t.not(buf, Buffer.alloc(10), 'not blank') 30 | 31 | buf = Buffer.alloc(1024) 32 | sodium.randombytes_buf(buf) 33 | t.not(buf, Buffer.alloc(1024), 'large not blank') 34 | }) 35 | 36 | test.skip('randombytes_deterministic', function (t) { 37 | const seed1 = Buffer.allocUnsafe(sodium.randombytes_SEEDBYTES) 38 | const seed2 = Buffer.allocUnsafe(sodium.randombytes_SEEDBYTES) 39 | const buf1 = Buffer.alloc(10) 40 | const buf2 = Buffer.alloc(10) 41 | 42 | for (let i = 0; i < 1e6; i++) { 43 | sodium.randombytes_buf(seed1) 44 | sodium.randombytes_buf(seed2) 45 | 46 | sodium.randombytes_buf_deterministic(buf1, seed1) 47 | sodium.randombytes_buf_deterministic(buf2, seed1) 48 | if (!buf1.equals(buf2)) t.fail('should equal') 49 | 50 | sodium.randombytes_buf_deterministic(buf1, seed1) 51 | sodium.randombytes_buf_deterministic(buf2, seed2) 52 | if (buf1.equals(buf2)) t.fail('should not equal') 53 | 54 | sodium.randombytes_buf_deterministic(buf1, seed2) 55 | sodium.randombytes_buf_deterministic(buf2, seed1) 56 | if (buf1.equals(buf2)) t.fail('should not equal') 57 | 58 | sodium.randombytes_buf_deterministic(buf1, seed2) 59 | sodium.randombytes_buf_deterministic(buf2, seed2) 60 | if (!buf1.equals(buf2)) t.fail('should equal') 61 | } 62 | }) 63 | 64 | test.skip('Various test cases', function (t) { 65 | sodium.randombytes_buf(Buffer.alloc(0)) 66 | sodium.randombytes_buf(new Uint8Array(16)) 67 | 68 | t.throws(function () { 69 | sodium.randombytes_buf([]) 70 | }) 71 | 72 | t.end() 73 | }) 74 | 75 | test('Generates random bytes', function (t) { 76 | const bufConst = Buffer.alloc(64) 77 | sodium.randombytes_buf(bufConst) 78 | 79 | const buf1 = Buffer.alloc(64) 80 | for (let i = 0; i < 1e4; i++) { 81 | sodium.randombytes_buf(buf1) 82 | if (Buffer.compare(buf1, bufConst) === 0) { 83 | t.fail('Constant buffer should not be equal') 84 | t.end() 85 | return 86 | } 87 | } 88 | 89 | t.pass('Generated unique buffers') 90 | t.end() 91 | }) 92 | 93 | test('Exceed quota', function (t) { 94 | const buf = Buffer.alloc(1 << 17) 95 | sodium.randombytes_buf(buf) 96 | 97 | const scores = new Array(256) 98 | scores.fill(0) 99 | 100 | for (const b of buf) { 101 | scores[b]++ 102 | } 103 | 104 | scores 105 | .map(cnt => cnt / 256) 106 | .forEach(cnt => { 107 | if (cnt < 1 && cnt > 3) t.fail('Statistically unreasonable') 108 | }) 109 | 110 | t.end() 111 | }) 112 | --------------------------------------------------------------------------------