UNPKG

js-nacl

Version:

High-level API to libsodium.

560 lines (479 loc) 22.2 kB
function nacl_cooked(nacl_raw) { 'use strict'; var exports = {}; //--------------------------------------------------------------------------- // Horrifying UTF-8 and hex codecs function encode_utf8(s) { return encode_latin1(unescape(encodeURIComponent(s))); } function encode_latin1(s) { var result = new Uint8Array(s.length); for (var i = 0; i < s.length; i++) { var c = s.charCodeAt(i); if ((c & 0xff) !== c) throw {message: "Cannot encode string in Latin1", str: s}; result[i] = (c & 0xff); } return result; } function decode_utf8(bs) { return decodeURIComponent(escape(decode_latin1(bs))); } function decode_latin1(bs) { var encoded = []; for (var i = 0; i < bs.length; i++) { encoded.push(String.fromCharCode(bs[i])); } return encoded.join(''); } function to_hex(bs) { var encoded = []; for (var i = 0; i < bs.length; i++) { encoded.push("0123456789abcdef"[(bs[i] >> 4) & 15]); encoded.push("0123456789abcdef"[bs[i] & 15]); } return encoded.join(''); } function from_hex(s) { var result = new Uint8Array(s.length / 2); for (var i = 0; i < s.length / 2; i++) { result[i] = parseInt(s.substr(2*i,2),16); } return result; } //--------------------------------------------------------------------------- // Allocation function MALLOC(nbytes) { var result = nacl_raw._malloc(nbytes); if (result === 0) { throw {message: "malloc() failed", nbytes: nbytes}; } return result; } function FREE(pointer) { nacl_raw._free(pointer); } //--------------------------------------------------------------------------- function injectBytes(bs, leftPadding) { var p = leftPadding || 0; var address = MALLOC(bs.length + p); nacl_raw.HEAPU8.set(bs, address + p); for (var i = address; i < address + p; i++) { nacl_raw.HEAPU8[i] = 0; } return address; } function check_injectBytes(function_name, what, thing, expected_length, leftPadding) { check_length(function_name, what, thing, expected_length); return injectBytes(thing, leftPadding); } function extractBytes(address, length) { var result = new Uint8Array(length); result.set(nacl_raw.HEAPU8.subarray(address, address + length)); return result; } //--------------------------------------------------------------------------- function check(function_name, result) { if (result !== 0) { throw {message: "nacl_raw." + function_name + " signalled an error"}; } } function check_length(function_name, what, thing, expected_length) { if (thing.length !== expected_length) { throw {message: "nacl." + function_name + " expected " + expected_length + "-byte " + what + " but got length " + thing.length}; } } function Target(length) { this.length = length; this.address = MALLOC(length); } Target.prototype.extractBytes = function (offset) { var result = extractBytes(this.address + (offset || 0), this.length - (offset || 0)); FREE(this.address); this.address = null; return result; }; function free_all(addresses) { for (var i = 0; i < addresses.length; i++) { FREE(addresses[i]); } } //--------------------------------------------------------------------------- // Randomness function random_bytes(count) { var bs = new Target(count); nacl_raw._randombytes_buf(bs.address, count); return bs.extractBytes(); } nacl_raw._randombytes_stir(); //--------------------------------------------------------------------------- // Boxing function crypto_box_keypair() { var pk = new Target(nacl_raw._crypto_box_publickeybytes()); var sk = new Target(nacl_raw._crypto_box_secretkeybytes()); check("_crypto_box_keypair", nacl_raw._crypto_box_keypair(pk.address, sk.address)); return {boxPk: pk.extractBytes(), boxSk: sk.extractBytes()}; } function crypto_box_random_nonce() { return random_bytes(nacl_raw._crypto_box_noncebytes()); } function crypto_box(msg, nonce, pk, sk) { var m = injectBytes(msg, nacl_raw._crypto_box_zerobytes()); var na = check_injectBytes("crypto_box", "nonce", nonce, nacl_raw._crypto_box_noncebytes()); var pka = check_injectBytes("crypto_box", "pk", pk, nacl_raw._crypto_box_publickeybytes()); var ska = check_injectBytes("crypto_box", "sk", sk, nacl_raw._crypto_box_secretkeybytes()); var c = new Target(msg.length + nacl_raw._crypto_box_zerobytes()); check("_crypto_box", nacl_raw._crypto_box(c.address, m, c.length, 0, na, pka, ska)); free_all([m, na, pka, ska]); return c.extractBytes(nacl_raw._crypto_box_boxzerobytes()); } function crypto_box_open(ciphertext, nonce, pk, sk) { var c = injectBytes(ciphertext, nacl_raw._crypto_box_boxzerobytes()); var na = check_injectBytes("crypto_box_open", "nonce", nonce, nacl_raw._crypto_box_noncebytes()); var pka = check_injectBytes("crypto_box_open", "pk", pk, nacl_raw._crypto_box_publickeybytes()); var ska = check_injectBytes("crypto_box_open", "sk", sk, nacl_raw._crypto_box_secretkeybytes()); var m = new Target(ciphertext.length + nacl_raw._crypto_box_boxzerobytes()); check("_crypto_box_open", nacl_raw._crypto_box_open(m.address, c, m.length, 0, na, pka, ska)); free_all([c, na, pka, ska]); return m.extractBytes(nacl_raw._crypto_box_zerobytes()); } function crypto_box_precompute(pk, sk) { var pka = check_injectBytes("crypto_box_precompute", "pk", pk, nacl_raw._crypto_box_publickeybytes()); var ska = check_injectBytes("crypto_box_precompute", "sk", sk, nacl_raw._crypto_box_secretkeybytes()); var k = new Target(nacl_raw._crypto_box_beforenmbytes()); check("_crypto_box_beforenm", nacl_raw._crypto_box_beforenm(k.address, pka, ska)); free_all([pka, ska]); return {boxK: k.extractBytes()}; } function crypto_box_precomputed(msg, nonce, state) { var m = injectBytes(msg, nacl_raw._crypto_box_zerobytes()); var na = check_injectBytes("crypto_box_precomputed", "nonce", nonce, nacl_raw._crypto_box_noncebytes()); var ka = check_injectBytes("crypto_box_precomputed", "boxK", state.boxK, nacl_raw._crypto_box_beforenmbytes()); var c = new Target(msg.length + nacl_raw._crypto_box_zerobytes()); check("_crypto_box_afternm", nacl_raw._crypto_box_afternm(c.address, m, c.length, 0, na, ka)); free_all([m, na, ka]); return c.extractBytes(nacl_raw._crypto_box_boxzerobytes()); } function crypto_box_open_precomputed(ciphertext, nonce, state) { var c = injectBytes(ciphertext, nacl_raw._crypto_box_boxzerobytes()); var na = check_injectBytes("crypto_box_open_precomputed", "nonce", nonce, nacl_raw._crypto_box_noncebytes()); var ka = check_injectBytes("crypto_box_open_precomputed", "boxK", state.boxK, nacl_raw._crypto_box_beforenmbytes()); var m = new Target(ciphertext.length + nacl_raw._crypto_box_boxzerobytes()); check("_crypto_box_open_afternm", nacl_raw._crypto_box_open_afternm(m.address, c, m.length, 0, na, ka)); free_all([c, na, ka]); return m.extractBytes(nacl_raw._crypto_box_zerobytes()); } //--------------------------------------------------------------------------- // Hashing function crypto_hash(bs) { var address = injectBytes(bs); var hash = new Target(nacl_raw._crypto_hash_bytes()); check("_crypto_hash", nacl_raw._crypto_hash(hash.address, address, bs.length, 0)); FREE(address); return hash.extractBytes(); } function crypto_hash_sha256(bs) { var address = injectBytes(bs); var hash = new Target(nacl_raw._crypto_hash_sha256_bytes()); check("_crypto_hash_sha256", nacl_raw._crypto_hash_sha256(hash.address, address, bs.length, 0)); FREE(address); return hash.extractBytes(); } function crypto_hash_string(s) { return crypto_hash(encode_utf8(s)); } //--------------------------------------------------------------------------- // Symmetric-key encryption function crypto_stream_random_nonce() { return random_bytes(nacl_raw._crypto_stream_noncebytes()); } function crypto_stream(len, nonce, key) { var na = check_injectBytes("crypto_stream", "nonce", nonce, nacl_raw._crypto_stream_noncebytes()); var ka = check_injectBytes("crypto_stream", "key", key, nacl_raw._crypto_stream_keybytes()); var out = new Target(len); check("_crypto_stream", nacl_raw._crypto_stream(out.address, len, 0, na, ka)); free_all([na, ka]); return out.extractBytes(); } function crypto_stream_xor(msg, nonce, key) { var na = check_injectBytes("crypto_stream_xor", "nonce", nonce, nacl_raw._crypto_stream_noncebytes()); var ka = check_injectBytes("crypto_stream_xor", "key", key, nacl_raw._crypto_stream_keybytes()); var ma = injectBytes(msg); var out = new Target(msg.length); check("_crypto_stream_xor", nacl_raw._crypto_stream_xor(out.address, ma, msg.length, 0, na, ka)); free_all([na, ka, ma]); return out.extractBytes(); } //--------------------------------------------------------------------------- // One-time authentication function crypto_onetimeauth(msg, key) { var ka = check_injectBytes("crypto_onetimeauth", "key", key, nacl_raw._crypto_onetimeauth_keybytes()); var ma = injectBytes(msg); var authenticator = new Target(nacl_raw._crypto_onetimeauth_bytes()); check("_crypto_onetimeauth", nacl_raw._crypto_onetimeauth(authenticator.address, ma, msg.length, 0, ka)); free_all([ka, ma]); return authenticator.extractBytes(); } function crypto_onetimeauth_verify(authenticator, msg, key) { if (authenticator.length != nacl_raw._crypto_onetimeauth_bytes()) return false; var ka = check_injectBytes("crypto_onetimeauth_verify", "key", key, nacl_raw._crypto_onetimeauth_keybytes()); var ma = injectBytes(msg); var aa = injectBytes(authenticator); var result = nacl_raw._crypto_onetimeauth_verify(aa, ma, msg.length, 0, ka); free_all([ka, ma, aa]); return (result == 0); } //--------------------------------------------------------------------------- // Authentication function crypto_auth(msg, key) { var ka = check_injectBytes("crypto_auth", "key", key, nacl_raw._crypto_auth_keybytes()); var ma = injectBytes(msg); var authenticator = new Target(nacl_raw._crypto_auth_bytes()); check("_crypto_auth", nacl_raw._crypto_auth(authenticator.address, ma, msg.length, 0, ka)); free_all([ka, ma]); return authenticator.extractBytes(); } function crypto_auth_verify(authenticator, msg, key) { if (authenticator.length != nacl_raw._crypto_auth_bytes()) return false; var ka = check_injectBytes("crypto_auth_verify", "key", key, nacl_raw._crypto_auth_keybytes()); var ma = injectBytes(msg); var aa = injectBytes(authenticator); var result = nacl_raw._crypto_auth_verify(aa, ma, msg.length, 0, ka); free_all([ka, ma, aa]); return (result == 0); } //--------------------------------------------------------------------------- // Authenticated symmetric-key encryption function crypto_secretbox_random_nonce() { return random_bytes(nacl_raw._crypto_secretbox_noncebytes()); } function crypto_secretbox(msg, nonce, key) { var m = injectBytes(msg, nacl_raw._crypto_secretbox_zerobytes()); var na = check_injectBytes("crypto_secretbox", "nonce", nonce, nacl_raw._crypto_secretbox_noncebytes()); var ka = check_injectBytes("crypto_secretbox", "key", key, nacl_raw._crypto_secretbox_keybytes()); var c = new Target(msg.length + nacl_raw._crypto_secretbox_zerobytes()); check("_crypto_secretbox", nacl_raw._crypto_secretbox(c.address, m, c.length, 0, na, ka)); free_all([m, na, ka]); return c.extractBytes(nacl_raw._crypto_secretbox_boxzerobytes()); } function crypto_secretbox_open(ciphertext, nonce, key) { var c = injectBytes(ciphertext, nacl_raw._crypto_secretbox_boxzerobytes()); var na = check_injectBytes("crypto_secretbox_open", "nonce", nonce, nacl_raw._crypto_secretbox_noncebytes()); var ka = check_injectBytes("crypto_secretbox_open", "key", key, nacl_raw._crypto_secretbox_keybytes()); var m = new Target(ciphertext.length + nacl_raw._crypto_secretbox_boxzerobytes()); check("_crypto_secretbox_open", nacl_raw._crypto_secretbox_open(m.address, c, m.length, 0, na, ka)); free_all([c, na, ka]); return m.extractBytes(nacl_raw._crypto_secretbox_zerobytes()); } //--------------------------------------------------------------------------- // Boxing with ephemeral keys function crypto_box_seal(msg, pk) { var m = injectBytes(msg); var pka = check_injectBytes("crypto_box_seal", "pk", pk, nacl_raw._crypto_box_publickeybytes()); var c = new Target(msg.length + nacl_raw._crypto_box_sealbytes()); check("_crypto_box_seal", nacl_raw._crypto_box_seal(c.address, m, msg.length, 0, pka)); free_all([m, pka]); return c.extractBytes(); } function crypto_box_seal_open(ciphertext, pk, sk) { var c = injectBytes(ciphertext); var pka = check_injectBytes("crypto_box_seal_open", "pk", pk, nacl_raw._crypto_box_publickeybytes()); var ska = check_injectBytes("crypto_box_seal_open", "sk", sk, nacl_raw._crypto_box_secretkeybytes()); var m = new Target(ciphertext.length - nacl_raw._crypto_box_sealbytes()); check("_crypto_box_seal_open", nacl_raw._crypto_box_seal_open(m.address, c, ciphertext.length, 0, pka, ska)); free_all([c, pka, ska]); return m.extractBytes(); } //--------------------------------------------------------------------------- // Signing function crypto_sign_keypair() { var pk = new Target(nacl_raw._crypto_sign_publickeybytes()); var sk = new Target(nacl_raw._crypto_sign_secretkeybytes()); check("_crypto_sign_keypair", nacl_raw._crypto_sign_keypair(pk.address, sk.address)); return {signPk: pk.extractBytes(), signSk: sk.extractBytes()}; } function crypto_sign(msg, sk) { var ma = injectBytes(msg); var ska = check_injectBytes("crypto_sign", "sk", sk, nacl_raw._crypto_sign_secretkeybytes()); var sm = new Target(msg.length + nacl_raw._crypto_sign_bytes()); var smlen = new Target(8); check("_crypto_sign", nacl_raw._crypto_sign(sm.address, smlen.address, ma, msg.length, 0, ska)); free_all([ma, ska]); sm.length = nacl_raw.HEAPU32[smlen.address >> 2]; FREE(smlen.address); return sm.extractBytes(); } function crypto_sign_detached(msg, sk) { // WARNING: Experimental. Works for ed25519 but not necessarily other implementations. var signed_msg = crypto_sign(msg, sk); return signed_msg.subarray(0, nacl_raw._crypto_sign_bytes()); } function crypto_sign_open(sm, pk) { var sma = injectBytes(sm); var pka = check_injectBytes("crypto_sign_open", "pk", pk, nacl_raw._crypto_sign_publickeybytes()); var m = new Target(sm.length); var mlen = new Target(8); if (nacl_raw._crypto_sign_open(m.address, mlen.address, sma, sm.length, 0, pka) === 0) { free_all([sma, pka]); m.length = nacl_raw.HEAPU32[mlen.address >> 2]; FREE(mlen.address); return m.extractBytes(); } else { free_all([sma, pka, m.address, mlen.address]); return null; } } function crypto_sign_verify_detached(detached_signature, msg, pk) { // WARNING: Experimental. Works for ed25519 but not necessarily other implementations. var signed_msg = new Uint8Array(detached_signature.length + msg.length); signed_msg.set(detached_signature, 0); signed_msg.set(msg, detached_signature.length); return crypto_sign_open(signed_msg, pk) !== null; } //--------------------------------------------------------------------------- // Keys function crypto_sign_seed_keypair(bs) { var seeda = check_injectBytes("crypto_sign_seed_keypair", "seed", bs, nacl_raw._crypto_sign_secretkeybytes() / 2); var pk = new Target(nacl_raw._crypto_sign_publickeybytes()); var sk = new Target(nacl_raw._crypto_sign_secretkeybytes()); check("_crypto_sign_seed_keypair", nacl_raw._crypto_sign_seed_keypair(pk.address, sk.address, seeda)); FREE(seeda); return {signPk: pk.extractBytes(), signSk: sk.extractBytes()}; } function crypto_box_seed_keypair(bs) { var hash = new Uint8Array(crypto_hash(bs)); return crypto_box_keypair_from_raw_sk(hash.subarray(0, nacl_raw._crypto_box_secretkeybytes())); } function crypto_box_keypair_from_raw_sk(sk) { return {boxPk: crypto_scalarmult_base(sk), boxSk: sk}; } //--------------------------------------------------------------------------- // Scalarmult function crypto_scalarmult(n,p) { var na = check_injectBytes("crypto_scalarmult", "n", n, nacl_raw._crypto_scalarmult_curve25519_scalarbytes()); var pa = check_injectBytes("crypto_scalarmult", "p", p, nacl_raw._crypto_scalarmult_curve25519_bytes()); var q = new Target(nacl_raw._crypto_scalarmult_curve25519_bytes()); check("_crypto_scalarmult_curve25519", nacl_raw._crypto_scalarmult_curve25519(q.address, na, pa)); FREE(na); FREE(pa); return q.extractBytes(); } function crypto_scalarmult_base(n) { var na = check_injectBytes("crypto_scalarmult_base", "n", n, nacl_raw._crypto_scalarmult_curve25519_scalarbytes()); var q = new Target(nacl_raw._crypto_scalarmult_curve25519_bytes()); check("_crypto_scalarmult_curve25519_base", nacl_raw._crypto_scalarmult_curve25519_base(q.address, na)); FREE(na); return q.extractBytes(); } //--------------------------------------------------------------------------- exports.crypto_auth_BYTES = nacl_raw._crypto_auth_bytes(); exports.crypto_auth_KEYBYTES = nacl_raw._crypto_auth_keybytes(); exports.crypto_box_BEFORENMBYTES = nacl_raw._crypto_box_beforenmbytes(); exports.crypto_box_BOXZEROBYTES = nacl_raw._crypto_box_boxzerobytes(); exports.crypto_box_NONCEBYTES = nacl_raw._crypto_box_noncebytes(); exports.crypto_box_PUBLICKEYBYTES = nacl_raw._crypto_box_publickeybytes(); exports.crypto_box_SECRETKEYBYTES = nacl_raw._crypto_box_secretkeybytes(); exports.crypto_box_ZEROBYTES = nacl_raw._crypto_box_zerobytes(); exports.crypto_hash_BYTES = nacl_raw._crypto_hash_bytes(); exports.crypto_hash_sha256_BYTES = nacl_raw._crypto_hash_sha256_bytes(); // exports.crypto_hashblocks_BLOCKBYTES = nacl_raw._crypto_hashblocks_blockbytes(); // exports.crypto_hashblocks_STATEBYTES = nacl_raw._crypto_hashblocks_statebytes(); exports.crypto_onetimeauth_BYTES = nacl_raw._crypto_onetimeauth_bytes(); exports.crypto_onetimeauth_KEYBYTES = nacl_raw._crypto_onetimeauth_keybytes(); exports.crypto_secretbox_BOXZEROBYTES = nacl_raw._crypto_secretbox_boxzerobytes(); exports.crypto_secretbox_KEYBYTES = nacl_raw._crypto_secretbox_keybytes(); exports.crypto_secretbox_NONCEBYTES = nacl_raw._crypto_secretbox_noncebytes(); exports.crypto_secretbox_ZEROBYTES = nacl_raw._crypto_secretbox_zerobytes(); exports.crypto_sign_BYTES = nacl_raw._crypto_sign_bytes(); exports.crypto_sign_PUBLICKEYBYTES = nacl_raw._crypto_sign_publickeybytes(); exports.crypto_sign_SECRETKEYBYTES = nacl_raw._crypto_sign_secretkeybytes(); // exports.crypto_stream_BEFORENMBYTES = nacl_raw._crypto_stream_beforenmbytes(); exports.crypto_stream_KEYBYTES = nacl_raw._crypto_stream_keybytes(); exports.crypto_stream_NONCEBYTES = nacl_raw._crypto_stream_noncebytes(); exports.crypto_scalarmult_SCALARBYTES = nacl_raw._crypto_scalarmult_curve25519_scalarbytes(); exports.crypto_scalarmult_BYTES = nacl_raw._crypto_scalarmult_curve25519_bytes(); exports.encode_utf8 = encode_utf8; exports.encode_latin1 = encode_latin1; exports.decode_utf8 = decode_utf8; exports.decode_latin1 = decode_latin1; exports.to_hex = to_hex; exports.from_hex = from_hex; exports.random_bytes = random_bytes; exports.crypto_box_keypair = crypto_box_keypair; exports.crypto_box_random_nonce = crypto_box_random_nonce; exports.crypto_box = crypto_box; exports.crypto_box_open = crypto_box_open; exports.crypto_box_precompute = crypto_box_precompute; exports.crypto_box_precomputed = crypto_box_precomputed; exports.crypto_box_open_precomputed = crypto_box_open_precomputed; exports.crypto_stream_random_nonce = crypto_stream_random_nonce; exports.crypto_stream = crypto_stream; exports.crypto_stream_xor = crypto_stream_xor; exports.crypto_onetimeauth = crypto_onetimeauth; exports.crypto_onetimeauth_verify = crypto_onetimeauth_verify; exports.crypto_auth = crypto_auth; exports.crypto_auth_verify = crypto_auth_verify; exports.crypto_secretbox_random_nonce = crypto_secretbox_random_nonce; exports.crypto_secretbox = crypto_secretbox; exports.crypto_secretbox_open = crypto_secretbox_open; exports.crypto_box_seal = crypto_box_seal; exports.crypto_box_seal_open = crypto_box_seal_open; exports.crypto_sign_keypair = crypto_sign_keypair; exports.crypto_sign = crypto_sign; exports.crypto_sign_detached = crypto_sign_detached; exports.crypto_sign_open = crypto_sign_open; exports.crypto_sign_verify_detached = crypto_sign_verify_detached; exports.crypto_hash = crypto_hash; exports.crypto_hash_sha256 = crypto_hash_sha256; exports.crypto_hash_string = crypto_hash_string; exports.crypto_sign_seed_keypair = crypto_sign_seed_keypair; exports.crypto_box_seed_keypair = crypto_box_seed_keypair; exports.crypto_box_keypair_from_raw_sk = crypto_box_keypair_from_raw_sk; // Backwards-compatibility: exports.crypto_sign_keypair_from_seed = crypto_sign_seed_keypair; exports.crypto_box_keypair_from_seed = crypto_box_seed_keypair; exports.crypto_scalarmult = crypto_scalarmult; exports.crypto_scalarmult_base = crypto_scalarmult_base; return exports; }