1 |
|
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_secretbox_open_easy, crypto_secretbox_easy } = require('./crypto_secretbox')
|
7 | const xsalsa20 = require('xsalsa20')
|
8 | const assert = require('nanoassert')
|
9 |
|
10 | const crypto_box_PUBLICKEYBYTES = 32
|
11 | const crypto_box_SECRETKEYBYTES = 32
|
12 | const crypto_box_NONCEBYTES = 24
|
13 | const crypto_box_ZEROBYTES = 32
|
14 | const crypto_box_BOXZEROBYTES = 16
|
15 | const crypto_box_SEALBYTES = 48
|
16 | const crypto_box_SEEDBYTES = 32
|
17 | const crypto_box_BEFORENMBYTES = 32
|
18 |
|
19 | module.exports = {
|
20 | crypto_box_keypair,
|
21 | crypto_box_seed_keypair,
|
22 | crypto_box_seal,
|
23 | crypto_box_seal_open,
|
24 | crypto_box_PUBLICKEYBYTES,
|
25 | crypto_box_SECRETKEYBYTES,
|
26 | crypto_box_NONCEBYTES,
|
27 | crypto_box_ZEROBYTES,
|
28 | crypto_box_BOXZEROBYTES,
|
29 | crypto_box_SEALBYTES,
|
30 | crypto_box_SEEDBYTES,
|
31 | crypto_box_BEFORENMBYTES
|
32 | }
|
33 |
|
34 | function crypto_box_keypair (pk, sk) {
|
35 | check(pk, crypto_box_PUBLICKEYBYTES)
|
36 | check(sk, crypto_box_SECRETKEYBYTES)
|
37 | randombytes(sk, 32)
|
38 | return crypto_scalarmult_base(pk, sk)
|
39 | }
|
40 |
|
41 | function crypto_box_seed_keypair (pk, sk, seed) {
|
42 | assert(pk.byteLength === crypto_box_PUBLICKEYBYTES, "pk should be 'crypto_box_PUBLICKEYBYTES' bytes")
|
43 | assert(sk.byteLength === crypto_box_SECRETKEYBYTES, "sk should be 'crypto_box_SECRETKEYBYTES' bytes")
|
44 | assert(sk.byteLength === crypto_box_SEEDBYTES, "sk should be 'crypto_box_SEEDBYTES' bytes")
|
45 |
|
46 | const hash = new Uint8Array(64)
|
47 | crypto_hash_sha512(hash, seed, 32)
|
48 | sk.set(hash.subarray(0, 32))
|
49 | hash.fill(0)
|
50 |
|
51 | return crypto_scalarmult_base(pk, sk)
|
52 | }
|
53 |
|
54 | function crypto_box_seal (c, m, pk) {
|
55 | check(c, crypto_box_SEALBYTES + m.length)
|
56 | check(pk, crypto_box_PUBLICKEYBYTES)
|
57 |
|
58 | var epk = c.subarray(0, crypto_box_PUBLICKEYBYTES)
|
59 | var esk = new Uint8Array(crypto_box_SECRETKEYBYTES)
|
60 | crypto_box_keypair(epk, esk)
|
61 |
|
62 | var n = new Uint8Array(crypto_box_NONCEBYTES)
|
63 | crypto_generichash_batch(n, [epk, pk])
|
64 |
|
65 | var s = new Uint8Array(crypto_box_PUBLICKEYBYTES)
|
66 | crypto_scalarmult(s, esk, pk)
|
67 |
|
68 | var k = new Uint8Array(crypto_box_BEFORENMBYTES)
|
69 | var zero = new Uint8Array(16)
|
70 | xsalsa20.core_hsalsa20(k, zero, s, xsalsa20.SIGMA)
|
71 |
|
72 | crypto_secretbox_easy(c.subarray(epk.length), m, n, k)
|
73 |
|
74 | cleanup(esk)
|
75 | }
|
76 |
|
77 | function crypto_box_seal_open (m, c, pk, sk) {
|
78 | check(c, crypto_box_SEALBYTES)
|
79 | check(m, c.length - crypto_box_SEALBYTES)
|
80 | check(pk, crypto_box_PUBLICKEYBYTES)
|
81 | check(sk, crypto_box_SECRETKEYBYTES)
|
82 |
|
83 | var epk = c.subarray(0, crypto_box_PUBLICKEYBYTES)
|
84 |
|
85 | var n = new Uint8Array(crypto_box_NONCEBYTES)
|
86 | crypto_generichash_batch(n, [epk, pk])
|
87 |
|
88 | var s = new Uint8Array(crypto_box_PUBLICKEYBYTES)
|
89 | crypto_scalarmult(s, sk, epk)
|
90 |
|
91 | var k = new Uint8Array(crypto_box_BEFORENMBYTES)
|
92 | var zero = new Uint8Array(16)
|
93 | xsalsa20.core_hsalsa20(k, zero, s, xsalsa20.SIGMA)
|
94 |
|
95 | return crypto_secretbox_open_easy(m, c.subarray(epk.length), n, k)
|
96 | }
|
97 |
|
98 | function check (buf, len) {
|
99 | if (!buf || (len && buf.length < len)) throw new Error('Argument must be a buffer' + (len ? ' of length ' + len : ''))
|
100 | }
|
101 |
|
102 | function cleanup (arr) {
|
103 | for (let i = 0; i < arr.length; i++) arr[i] = 0
|
104 | }
|