-
Notifications
You must be signed in to change notification settings - Fork 24
/
crypto_aead.js
160 lines (122 loc) · 6.46 KB
/
crypto_aead.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/* eslint-disable camelcase */
const { crypto_stream_chacha20_ietf, crypto_stream_chacha20_ietf_xor_ic } = require('./crypto_stream_chacha20')
const { crypto_verify_16 } = require('./crypto_verify')
const Poly1305 = require('./internal/poly1305')
const assert = require('nanoassert')
const crypto_aead_chacha20poly1305_ietf_KEYBYTES = 32
const crypto_aead_chacha20poly1305_ietf_NSECBYTES = 0
const crypto_aead_chacha20poly1305_ietf_NPUBBYTES = 12
const crypto_aead_chacha20poly1305_ietf_ABYTES = 16
const crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX = Number.MAX_SAFE_INTEGER
const _pad0 = new Uint8Array(16)
function crypto_aead_chacha20poly1305_ietf_encrypt (c, m, ad, nsec, npub, k) {
if (ad === null) return crypto_aead_chacha20poly1305_ietf_encrypt(c, m, new Uint8Array(0), nsec, npub, k)
assert(c.byteLength === m.byteLength + crypto_aead_chacha20poly1305_ietf_ABYTES,
"ciphertext should be 'crypto_aead_chacha20poly1305_ietf_ABYTES' longer than message")
assert(npub.byteLength === crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
"npub should be 'crypto_aead_chacha20poly1305_ietf_NPUBBYTES' long")
assert(k.byteLength === crypto_aead_chacha20poly1305_ietf_KEYBYTES,
"k should be 'crypto_aead_chacha20poly1305_ietf_KEYBYTES' long")
assert(m.byteLength <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'message is too large')
const ret = crypto_aead_chacha20poly1305_ietf_encrypt_detached(c.subarray(0, m.byteLength),
c.subarray(m.byteLength), m, ad, nsec, npub, k)
return m.byteLength + ret
}
function crypto_aead_chacha20poly1305_ietf_encrypt_detached (c, mac, m, ad, nsec, npub, k) {
if (ad === null) return crypto_aead_chacha20poly1305_ietf_encrypt_detached(c, mac, m, new Uint8Array(0), nsec, npub, k)
assert(c.byteLength === m.byteLength, 'ciphertext should be same length than message')
assert(npub.byteLength === crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
"npub should be 'crypto_aead_chacha20poly1305_ietf_NPUBBYTES' long")
assert(k.byteLength === crypto_aead_chacha20poly1305_ietf_KEYBYTES,
"k should be 'crypto_aead_chacha20poly1305_ietf_KEYBYTES' long")
assert(m.byteLength <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'message is too large')
assert(mac.byteLength <= crypto_aead_chacha20poly1305_ietf_ABYTES,
"mac should be 'crypto_aead_chacha20poly1305_ietf_ABYTES' long")
const block0 = new Uint8Array(64)
var slen = new Uint8Array(8)
crypto_stream_chacha20_ietf(block0, npub, k)
const poly = new Poly1305(block0)
block0.fill(0)
poly.update(ad, 0, ad.byteLength)
poly.update(_pad0, 0, (0x10 - ad.byteLength) & 0xf)
crypto_stream_chacha20_ietf_xor_ic(c, m, npub, 1, k)
poly.update(c, 0, m.byteLength)
poly.update(_pad0, 0, (0x10 - m.byteLength) & 0xf)
write64LE(slen, 0, ad.byteLength)
poly.update(slen, 0, slen.byteLength)
write64LE(slen, 0, m.byteLength)
poly.update(slen, 0, slen.byteLength)
poly.finish(mac, 0)
slen.fill(0)
return crypto_aead_chacha20poly1305_ietf_ABYTES
}
function crypto_aead_chacha20poly1305_ietf_decrypt (m, nsec, c, ad, npub, k) {
if (ad === null) return crypto_aead_chacha20poly1305_ietf_decrypt(m, nsec, c, new Uint8Array(0), npub, k)
assert(m.byteLength === c.byteLength - crypto_aead_chacha20poly1305_ietf_ABYTES,
"message should be 'crypto_aead_chacha20poly1305_ietf_ABYTES' shorter than ciphertext")
assert(npub.byteLength === crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
"npub should be 'crypto_aead_chacha20poly1305_ietf_NPUBBYTES' long")
assert(k.byteLength === crypto_aead_chacha20poly1305_ietf_KEYBYTES,
"k should be 'crypto_aead_chacha20poly1305_ietf_KEYBYTES' long")
assert(m.byteLength <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'message is too large')
if (c.byteLength < crypto_aead_chacha20poly1305_ietf_ABYTES) throw new Error('could not verify data')
crypto_aead_chacha20poly1305_ietf_decrypt_detached(
m, nsec,
c.subarray(0, c.byteLength - crypto_aead_chacha20poly1305_ietf_ABYTES),
c.subarray(c.byteLength - crypto_aead_chacha20poly1305_ietf_ABYTES),
ad, npub, k)
return c.byteLength - crypto_aead_chacha20poly1305_ietf_ABYTES
}
function crypto_aead_chacha20poly1305_ietf_decrypt_detached (m, nsec, c, mac, ad, npub, k) {
if (ad === null) return crypto_aead_chacha20poly1305_ietf_decrypt_detached(m, nsec, c, mac, new Uint8Array(0), npub, k)
assert(c.byteLength === m.byteLength, 'message should be same length than ciphertext')
assert(npub.byteLength === crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
"npub should be 'crypto_aead_chacha20poly1305_ietf_NPUBBYTES' long")
assert(k.byteLength === crypto_aead_chacha20poly1305_ietf_KEYBYTES,
"k should be 'crypto_aead_chacha20poly1305_ietf_KEYBYTES' long")
assert(m.byteLength <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX, 'message is too large')
assert(mac.byteLength <= crypto_aead_chacha20poly1305_ietf_ABYTES,
"mac should be 'crypto_aead_chacha20poly1305_ietf_ABYTES' long")
const block0 = new Uint8Array(64)
const slen = new Uint8Array(8)
const computed_mac = new Uint8Array(crypto_aead_chacha20poly1305_ietf_ABYTES)
crypto_stream_chacha20_ietf(block0, npub, k)
const poly = new Poly1305(block0)
block0.fill(0)
poly.update(ad, 0, ad.byteLength)
poly.update(_pad0, 0, (0x10 - ad.byteLength) & 0xf)
const mlen = c.byteLength
poly.update(c, 0, mlen)
poly.update(_pad0, 0, (0x10 - mlen) & 0xf)
write64LE(slen, 0, ad.byteLength)
poly.update(slen, 0, slen.byteLength)
write64LE(slen, 0, mlen)
poly.update(slen, 0, slen.byteLength)
poly.finish(computed_mac, 0)
assert(computed_mac.byteLength === 16)
const ret = crypto_verify_16(computed_mac, 0, mac, 0)
computed_mac.fill(0)
slen.fill(0)
if (!ret) {
m.fill(0)
throw new Error('could not verify data')
}
crypto_stream_chacha20_ietf_xor_ic(m, c, npub, 1, k)
}
function write64LE (buf, offset, int) {
buf.fill(0, 0, 8)
const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength)
view.setUint32(offset, int & 0xffffffff, true)
view.setUint32(offset + 4, (int / 2 ** 32) & 0xffffffff, true)
}
module.exports = {
crypto_aead_chacha20poly1305_ietf_encrypt,
crypto_aead_chacha20poly1305_ietf_encrypt_detached,
crypto_aead_chacha20poly1305_ietf_decrypt,
crypto_aead_chacha20poly1305_ietf_decrypt_detached,
crypto_aead_chacha20poly1305_ietf_ABYTES,
crypto_aead_chacha20poly1305_ietf_KEYBYTES,
crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
crypto_aead_chacha20poly1305_ietf_NSECBYTES,
crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX
}