226 lines
6.7 KiB
JavaScript
226 lines
6.7 KiB
JavaScript
'use strict';
|
|
|
|
// Based on https://github.com/dchest/tweetnacl-js/blob/6dcbcaf5f5cbfd313f2dcfe763db35c828c8ff5b/nacl-fast.js.
|
|
|
|
var sodium = module.exports
|
|
|
|
// Ported in 2014 by Dmitry Chestnykh and Devi Mandiri.
|
|
// Public domain.
|
|
//
|
|
// Implementation derived from TweetNaCl version 20140427.
|
|
// See for details: http://tweetnacl.cr.yp.to/
|
|
|
|
// also forwarded at the bottom but randombytes is non-enumerable
|
|
var randombytes = require('./randombytes').randombytes
|
|
|
|
function vn(x, xi, y, yi, n) {
|
|
var i,d = 0;
|
|
for (i = 0; i < n; i++) d |= x[xi+i]^y[yi+i];
|
|
return (1 & ((d - 1) >>> 8)) - 1;
|
|
}
|
|
|
|
function crypto_verify_16(x, xi, y, yi) {
|
|
return vn(x,xi,y,yi,16);
|
|
}
|
|
|
|
|
|
function crypto_stream_xor (c, cpos, m, mpos, clen, n, k) {
|
|
cs.crypto_stream_xor(c, m, n, k)
|
|
}
|
|
|
|
function crypto_stream (c, cpos, clen, n, k) {
|
|
cs.crypto_stream(c, n, k)
|
|
}
|
|
|
|
function crypto_onetimeauth(out, outpos, m, mpos, n, k) {
|
|
var s = new poly1305(k);
|
|
s.update(m, mpos, n);
|
|
s.finish(out, outpos);
|
|
return 0;
|
|
}
|
|
|
|
function crypto_onetimeauth_verify(h, hpos, m, mpos, n, k) {
|
|
var x = new Uint8Array(16);
|
|
crypto_onetimeauth(x,0,m,mpos,n,k);
|
|
return crypto_verify_16(h,hpos,x,0);
|
|
}
|
|
|
|
function crypto_secretbox(c,m,d,n,k) {
|
|
var i;
|
|
if (d < 32) return -1;
|
|
crypto_stream_xor(c,0,m,0,d,n,k);
|
|
crypto_onetimeauth(c, 16, c, 32, d - 32, c);
|
|
for (i = 0; i < 16; i++) c[i] = 0;
|
|
return 0;
|
|
}
|
|
|
|
function crypto_secretbox_open(m,c,d,n,k) {
|
|
var i;
|
|
var x = new Uint8Array(32);
|
|
if (d < 32) return -1;
|
|
crypto_stream(x,0,32,n,k);
|
|
if (crypto_onetimeauth_verify(c, 16,c, 32,d - 32,x) !== 0) return -1;
|
|
crypto_stream_xor(m,0,c,0,d,n,k);
|
|
for (i = 0; i < 32; i++) m[i] = 0;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
function crypto_secretbox_detached (o, mac, msg, n, k) {
|
|
check(mac, sodium.crypto_secretbox_MACBYTES)
|
|
var tmp = new Uint8Array(msg.length + mac.length)
|
|
crypto_secretbox_easy(tmp, msg, n, k)
|
|
o.set(tmp.subarray(0, msg.length))
|
|
mac.set(tmp.subarray(msg.length))
|
|
}
|
|
|
|
function crypto_secretbox_open_detached (msg, o, mac, n, k) {
|
|
check(mac, sodium.crypto_secretbox_MACBYTES)
|
|
var tmp = new Uint8Array(o.length + mac.length)
|
|
tmp.set(o)
|
|
tmp.set(mac, msg.length)
|
|
return crypto_secretbox_open_easy(msg, tmp, n, k)
|
|
}
|
|
|
|
function crypto_secretbox_easy(o, msg, n, k) {
|
|
check(msg, 0)
|
|
check(o, msg.length + sodium.crypto_secretbox_MACBYTES)
|
|
check(n, crypto_secretbox_NONCEBYTES)
|
|
check(k, crypto_secretbox_KEYBYTES)
|
|
|
|
var i
|
|
var m = new Uint8Array(crypto_secretbox_ZEROBYTES + msg.length);
|
|
var c = new Uint8Array(m.length);
|
|
for (i = 0; i < msg.length; i++) m[i+crypto_secretbox_ZEROBYTES] = msg[i];
|
|
crypto_secretbox(c, m, m.length, n, k);
|
|
for (i = crypto_secretbox_BOXZEROBYTES; i < c.length; i++) o[i - crypto_secretbox_BOXZEROBYTES] = c[i]
|
|
}
|
|
|
|
function crypto_secretbox_open_easy(msg, box, n, k) {
|
|
check(box, sodium.crypto_secretbox_MACBYTES)
|
|
check(msg, box.length - sodium.crypto_secretbox_MACBYTES)
|
|
check(n, crypto_secretbox_NONCEBYTES)
|
|
check(k, crypto_secretbox_KEYBYTES)
|
|
|
|
var i
|
|
var c = new Uint8Array(crypto_secretbox_BOXZEROBYTES + box.length);
|
|
var m = new Uint8Array(c.length);
|
|
for (i = 0; i < box.length; i++) c[i+crypto_secretbox_BOXZEROBYTES] = box[i];
|
|
if (c.length < 32) return false;
|
|
if (crypto_secretbox_open(m, c, c.length, n, k) !== 0) return false;
|
|
|
|
for (i = crypto_secretbox_ZEROBYTES; i < m.length; i++) msg[i - crypto_secretbox_ZEROBYTES] = m[i]
|
|
return true
|
|
}
|
|
|
|
function crypto_box_keypair(pk, sk) {
|
|
check(pk, crypto_box_PUBLICKEYBYTES)
|
|
check(sk, crypto_box_SECRETKEYBYTES)
|
|
randombytes(sk, 32)
|
|
return crypto_scalarmult_base(pk, sk)
|
|
}
|
|
|
|
function crypto_box_seal(c, m, pk) {
|
|
check(c, crypto_box_SEALBYTES + m.length)
|
|
check(pk, crypto_box_PUBLICKEYBYTES)
|
|
|
|
var epk = c.subarray(0, crypto_box_PUBLICKEYBYTES)
|
|
var esk = new Uint8Array(crypto_box_SECRETKEYBYTES)
|
|
crypto_box_keypair(epk, esk)
|
|
|
|
var n = new Uint8Array(crypto_box_NONCEBYTES)
|
|
sodium.crypto_generichash_batch(n, [ epk, pk ])
|
|
|
|
var s = new Uint8Array(crypto_box_PUBLICKEYBYTES)
|
|
crypto_scalarmult(s, esk, pk)
|
|
|
|
var k = new Uint8Array(crypto_box_BEFORENMBYTES)
|
|
var zero = new Uint8Array(16)
|
|
xsalsa20.core_hsalsa20(k, zero, s, xsalsa20.SIGMA)
|
|
|
|
crypto_secretbox_easy(c.subarray(epk.length), m, n, k)
|
|
|
|
cleanup(esk)
|
|
}
|
|
|
|
function crypto_box_seal_open(m, c, pk, sk) {
|
|
check(c, crypto_box_SEALBYTES)
|
|
check(m, c.length - crypto_box_SEALBYTES)
|
|
check(pk, crypto_box_PUBLICKEYBYTES)
|
|
check(sk, crypto_box_SECRETKEYBYTES)
|
|
|
|
var epk = c.subarray(0, crypto_box_PUBLICKEYBYTES)
|
|
|
|
var n = new Uint8Array(crypto_box_NONCEBYTES)
|
|
sodium.crypto_generichash_batch(n, [ epk, pk ])
|
|
|
|
var s = new Uint8Array(crypto_box_PUBLICKEYBYTES)
|
|
crypto_scalarmult(s, sk, epk)
|
|
|
|
var k = new Uint8Array(crypto_box_BEFORENMBYTES)
|
|
var zero = new Uint8Array(16)
|
|
xsalsa20.core_hsalsa20(k, zero, s, xsalsa20.SIGMA)
|
|
|
|
return crypto_secretbox_open_easy(m, c.subarray(epk.length), n, k)
|
|
}
|
|
|
|
var crypto_secretbox_KEYBYTES = 32,
|
|
crypto_secretbox_NONCEBYTES = 24,
|
|
crypto_secretbox_ZEROBYTES = 32,
|
|
crypto_secretbox_BOXZEROBYTES = 16,
|
|
crypto_box_PUBLICKEYBYTES = 32,
|
|
crypto_box_SECRETKEYBYTES = 32,
|
|
crypto_box_BEFORENMBYTES = 32,
|
|
crypto_box_NONCEBYTES = crypto_secretbox_NONCEBYTES,
|
|
crypto_box_ZEROBYTES = crypto_secretbox_ZEROBYTES,
|
|
crypto_box_BOXZEROBYTES = crypto_secretbox_BOXZEROBYTES,
|
|
crypto_box_SEALBYTES = 48,
|
|
crypto_box_BEFORENMBYTES = 32,
|
|
sodium.memzero = function (len, offset) {
|
|
for (var i = offset; i < len; i++) arr[i] = 0;
|
|
}
|
|
|
|
|
|
forward(require('./crypto_generichash'))
|
|
forward(require('./crypto_kdf'))
|
|
forward(require('./crypto_shorthash'))
|
|
forward(require('./randombytes'))
|
|
forward(require('./crypto_stream'))
|
|
|
|
|
|
sodium.crypto_secretbox_KEYBYTES = crypto_secretbox_KEYBYTES,
|
|
sodium.crypto_secretbox_NONCEBYTES = crypto_secretbox_NONCEBYTES,
|
|
sodium.crypto_secretbox_MACBYTES = 16
|
|
sodium.crypto_secretbox_easy = crypto_secretbox_easy
|
|
sodium.crypto_secretbox_open_easy = crypto_secretbox_open_easy
|
|
sodium.crypto_secretbox_detached = crypto_secretbox_detached
|
|
sodium.crypto_secretbox_open_detached = crypto_secretbox_open_detached
|
|
|
|
sodium.crypto_box_PUBLICKEYBYTES = crypto_box_PUBLICKEYBYTES
|
|
sodium.crypto_box_SECRETKEYBYTES = crypto_box_SECRETKEYBYTES
|
|
sodium.crypto_box_SEALBYTES = crypto_box_SEALBYTES
|
|
sodium.crypto_box_BEFORENMBYTES = crypto_box_BEFORENMBYTES
|
|
sodium.crypto_box_keypair = crypto_box_keypair
|
|
sodium.crypto_box_seal = crypto_box_seal
|
|
sodium.crypto_box_seal_open = crypto_box_seal_open
|
|
|
|
sodium.sodium_malloc = function (n) {
|
|
return new Uint8Array(n)
|
|
}
|
|
|
|
function cleanup(arr) {
|
|
for (var i = 0; i < arr.length; i++) arr[i] = 0;
|
|
}
|
|
|
|
forward(require('./crypto_hash'))
|
|
forward(require('./crypto_scalarmult'))
|
|
forward(require('./crypto_sign'))
|
|
forward(require('./crypto_stream'))
|
|
|
|
function forward (submodule) {
|
|
Object.keys(submodule).forEach(function (prop) {
|
|
module.exports[prop] = submodule[prop]
|
|
})
|
|
}
|