sodium-javascript/crypto_box.js
2020-09-01 14:17:03 -07:00

207 lines
6.5 KiB
JavaScript

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