Add crypto_box_easy (#29)

* Fix backward crypto_secretbox_detached bug

* Add crypto_box_easy
This commit is contained in:
Christian Bundy 2020-09-22 05:47:36 -07:00 committed by GitHub
parent ab004d8022
commit 61b6e6916a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 104 additions and 7 deletions

View File

@ -3,7 +3,13 @@ const { crypto_hash_sha512 } = require('./crypto_hash')
const { crypto_scalarmult, crypto_scalarmult_base } = require('./crypto_scalarmult') const { crypto_scalarmult, crypto_scalarmult_base } = require('./crypto_scalarmult')
const { randombytes } = require('./randombytes') const { randombytes } = require('./randombytes')
const { crypto_generichash_batch } = require('./crypto_generichash') const { crypto_generichash_batch } = require('./crypto_generichash')
const { crypto_secretbox_open_easy, crypto_secretbox_easy } = require('./crypto_secretbox') const { crypto_stream_xsalsa20_MESSAGEBYTES_MAX } = require('./crypto_stream')
const {
crypto_secretbox_open_easy,
crypto_secretbox_easy,
crypto_secretbox_detached,
crypto_secretbox_open_detached
} = require('./crypto_secretbox')
const xsalsa20 = require('xsalsa20') const xsalsa20 = require('xsalsa20')
const assert = require('nanoassert') const assert = require('nanoassert')
@ -15,8 +21,17 @@ const crypto_box_BOXZEROBYTES = 16
const crypto_box_SEALBYTES = 48 const crypto_box_SEALBYTES = 48
const crypto_box_SEEDBYTES = 32 const crypto_box_SEEDBYTES = 32
const crypto_box_BEFORENMBYTES = 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 = { module.exports = {
crypto_box_easy,
crypto_box_open_easy,
crypto_box_keypair, crypto_box_keypair,
crypto_box_seed_keypair, crypto_box_seed_keypair,
crypto_box_seal, crypto_box_seal,
@ -28,7 +43,8 @@ module.exports = {
crypto_box_BOXZEROBYTES, crypto_box_BOXZEROBYTES,
crypto_box_SEALBYTES, crypto_box_SEALBYTES,
crypto_box_SEEDBYTES, crypto_box_SEEDBYTES,
crypto_box_BEFORENMBYTES crypto_box_BEFORENMBYTES,
crypto_box_MACBYTES
} }
function crypto_box_keypair (pk, sk) { function crypto_box_keypair (pk, sk) {
@ -37,7 +53,6 @@ function crypto_box_keypair (pk, sk) {
randombytes(sk, 32) randombytes(sk, 32)
return crypto_scalarmult_base(pk, sk) return crypto_scalarmult_base(pk, sk)
} }
function crypto_box_seed_keypair (pk, sk, seed) { function crypto_box_seed_keypair (pk, sk, seed) {
assert(pk.byteLength === crypto_box_PUBLICKEYBYTES, "pk should be 'crypto_box_PUBLICKEYBYTES' bytes") 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_SECRETKEYBYTES, "sk should be 'crypto_box_SECRETKEYBYTES' bytes")
@ -95,6 +110,87 @@ function crypto_box_seal_open (m, c, pk, sk) {
return crypto_secretbox_open_easy(m, c.subarray(epk.length), n, k) return crypto_secretbox_open_easy(m, c.subarray(epk.length), n, k)
} }
function crypto_box_beforenm (k, pk, sk) {
const zero = new Uint8Array(16)
const s = new Uint8Array(32)
assert(crypto_scalarmult(s, sk, pk) === 0)
xsalsa20.core_hsalsa20(k, zero, s, xsalsa20.SIGMA)
return true
}
function crypto_box_detached_afternm (c, mac, m, n, k) {
return crypto_secretbox_detached(c, mac, m, n, k)
}
function crypto_box_detached (c, mac, m, n, pk, sk) {
check(mac, crypto_box_MACBYTES)
check(n, crypto_box_NONCEBYTES)
check(pk, crypto_box_PUBLICKEYBYTES)
check(sk, crypto_box_SECRETKEYBYTES)
const k = new Uint8Array(crypto_box_BEFORENMBYTES)
assert(crypto_box_beforenm(k, pk, sk))
const ret = crypto_box_detached_afternm(c, mac, m, n, k)
cleanup(k)
return ret
}
function crypto_box_easy (c, m, n, pk, sk) {
assert(
c.length >= m.length + crypto_box_MACBYTES,
"c should be at least 'm.length + crypto_box_MACBYTES' bytes"
)
assert(
m.length <= crypto_box_MESSAGEBYTES_MAX,
"m should be at most 'crypto_box_MESSAGEBYTES_MAX' bytes"
)
return crypto_box_detached(
c.subarray(crypto_box_MACBYTES, m.length + crypto_box_MACBYTES),
c.subarray(0, crypto_box_MACBYTES),
m,
n,
pk,
sk
)
}
function crypto_box_open_detached_afternm (m, c, mac, n, k) {
return crypto_secretbox_open_detached(m, c, mac, n, k)
}
function crypto_box_open_detached (m, c, mac, n, pk, sk) {
const k = new Uint8Array(crypto_box_BEFORENMBYTES)
assert(crypto_box_beforenm(k, pk, sk))
const ret = crypto_box_open_detached_afternm(m, c, mac, n, k)
cleanup(k)
return ret
}
function crypto_box_open_easy (m, c, n, pk, sk) {
assert(
c.length >= m.length + crypto_box_MACBYTES,
"c should be at least 'm.length + crypto_box_MACBYTES' bytes"
)
return crypto_box_open_detached(
m,
c.subarray(crypto_box_MACBYTES, m.length + crypto_box_MACBYTES),
c.subarray(0, crypto_box_MACBYTES),
n,
pk,
sk
)
}
function check (buf, len) { function check (buf, len) {
if (!buf || (len && buf.length < len)) throw new Error('Argument must be a buffer' + (len ? ' of length ' + len : '')) if (!buf || (len && buf.length < len)) throw new Error('Argument must be a buffer' + (len ? ' of length ' + len : ''))
} }

View File

@ -68,8 +68,8 @@ function crypto_secretbox_detached (o, mac, msg, n, k) {
const tmp = new Uint8Array(msg.byteLength + mac.byteLength) const tmp = new Uint8Array(msg.byteLength + mac.byteLength)
crypto_secretbox_easy(tmp, msg, n, k) crypto_secretbox_easy(tmp, msg, n, k)
o.set(tmp.subarray(0, msg.byteLength)) mac.set(tmp.subarray(0, mac.byteLength))
mac.set(tmp.subarray(msg.byteLength)) o.set(tmp.subarray(mac.byteLength))
return true return true
} }
@ -80,8 +80,8 @@ function crypto_secretbox_open_detached (msg, o, mac, n, k) {
assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes") assert(k.byteLength === crypto_secretbox_KEYBYTES, "k must be 'crypto_secretbox_KEYBYTES' bytes")
const tmp = new Uint8Array(o.byteLength + mac.byteLength) const tmp = new Uint8Array(o.byteLength + mac.byteLength)
tmp.set(o) tmp.set(mac)
tmp.set(mac, msg.byteLength) tmp.set(o, mac.byteLength)
return crypto_secretbox_open_easy(msg, tmp, n, k) return crypto_secretbox_open_easy(msg, tmp, n, k)
} }

View File

@ -6,6 +6,7 @@ if (new Uint16Array([1])[0] !== 1) throw new Error('Big endian architecture is n
exports.crypto_stream_KEYBYTES = 32 exports.crypto_stream_KEYBYTES = 32
exports.crypto_stream_NONCEBYTES = 24 exports.crypto_stream_NONCEBYTES = 24
exports.crypto_stream_PRIMITIVE = 'xsalsa20' exports.crypto_stream_PRIMITIVE = 'xsalsa20'
exports.crypto_stream_xsalsa20_MESSAGEBYTES_MAX = Number.MAX_SAFE_INTEGER
exports.crypto_stream = function (c, nonce, key) { exports.crypto_stream = function (c, nonce, key) {
c.fill(0) c.fill(0)