Skip to content

Commit 34e3d30

Browse files
smp web: implement protocol encodings and encryption end-to-end (#1778)
* smp web: protocol encodings and x3dh * fix * strnup761 compiled to wasm * AES-256-GCM, comatibility tests * core of double ratchet * PQ double ratchet * test typescript ratchets * agent encoding/encryption stack with test --------- Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
1 parent a0af737 commit 34e3d30

15 files changed

Lines changed: 3077 additions & 27 deletions

smp-web/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
node_modules/
22
dist/
3+
dist-test/
34
package-lock.json

smp-web/cbits/js_random.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
addToLibrary({
2+
js_random_bytes: function(buf, len) {
3+
var bytes = new Uint8Array(len);
4+
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
5+
crypto.getRandomValues(bytes);
6+
} else {
7+
// Node.js fallback
8+
var nodeCrypto = require('crypto');
9+
var nodeBytes = nodeCrypto.randomBytes(len);
10+
bytes.set(nodeBytes);
11+
}
12+
HEAPU8.set(bytes, buf);
13+
}
14+
});

smp-web/cbits/sha512.c

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
/*
2+
20080913
3+
D. J. Bernstein
4+
Public domain.
5+
6+
SHA-512 implementation from SUPERCOP/NaCl.
7+
Source: https://bench.cr.yp.to/supercop.html
8+
crypto_hashblocks/sha512/ref/blocks.c
9+
crypto_hash/sha512/ref/hash.c
10+
11+
Combined into a single file for WASM compilation alongside sntrup761.
12+
*/
13+
14+
#include "sha512.h"
15+
16+
typedef unsigned long long uint64;
17+
18+
/* -- crypto_hashblocks_sha512 (blocks.c) -- */
19+
20+
static uint64 load_bigendian(const unsigned char *x)
21+
{
22+
return
23+
(uint64) (x[7]) \
24+
| (((uint64) (x[6])) << 8) \
25+
| (((uint64) (x[5])) << 16) \
26+
| (((uint64) (x[4])) << 24) \
27+
| (((uint64) (x[3])) << 32) \
28+
| (((uint64) (x[2])) << 40) \
29+
| (((uint64) (x[1])) << 48) \
30+
| (((uint64) (x[0])) << 56)
31+
;
32+
}
33+
34+
static void store_bigendian(unsigned char *x,uint64 u)
35+
{
36+
x[7] = u; u >>= 8;
37+
x[6] = u; u >>= 8;
38+
x[5] = u; u >>= 8;
39+
x[4] = u; u >>= 8;
40+
x[3] = u; u >>= 8;
41+
x[2] = u; u >>= 8;
42+
x[1] = u; u >>= 8;
43+
x[0] = u;
44+
}
45+
46+
#define SHR(x,c) ((x) >> (c))
47+
#define ROTR(x,c) (((x) >> (c)) | ((x) << (64 - (c))))
48+
49+
#define Ch(x,y,z) ((x & y) ^ (~x & z))
50+
#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z))
51+
#define Sigma0(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39))
52+
#define Sigma1(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41))
53+
#define sigma0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x,7))
54+
#define sigma1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x,6))
55+
56+
#define M(w0,w14,w9,w1) w0 = sigma1(w14) + w9 + sigma0(w1) + w0;
57+
58+
#define EXPAND \
59+
M(w0 ,w14,w9 ,w1 ) \
60+
M(w1 ,w15,w10,w2 ) \
61+
M(w2 ,w0 ,w11,w3 ) \
62+
M(w3 ,w1 ,w12,w4 ) \
63+
M(w4 ,w2 ,w13,w5 ) \
64+
M(w5 ,w3 ,w14,w6 ) \
65+
M(w6 ,w4 ,w15,w7 ) \
66+
M(w7 ,w5 ,w0 ,w8 ) \
67+
M(w8 ,w6 ,w1 ,w9 ) \
68+
M(w9 ,w7 ,w2 ,w10) \
69+
M(w10,w8 ,w3 ,w11) \
70+
M(w11,w9 ,w4 ,w12) \
71+
M(w12,w10,w5 ,w13) \
72+
M(w13,w11,w6 ,w14) \
73+
M(w14,w12,w7 ,w15) \
74+
M(w15,w13,w8 ,w0 )
75+
76+
#define F(w,k) \
77+
T1 = h + Sigma1(e) + Ch(e,f,g) + k + w; \
78+
T2 = Sigma0(a) + Maj(a,b,c); \
79+
h = g; \
80+
g = f; \
81+
f = e; \
82+
e = d + T1; \
83+
d = c; \
84+
c = b; \
85+
b = a; \
86+
a = T1 + T2;
87+
88+
static int crypto_hashblocks_sha512(unsigned char *statebytes,const unsigned char *in,unsigned long long inlen)
89+
{
90+
uint64 state[8];
91+
uint64 a;
92+
uint64 b;
93+
uint64 c;
94+
uint64 d;
95+
uint64 e;
96+
uint64 f;
97+
uint64 g;
98+
uint64 h;
99+
uint64 T1;
100+
uint64 T2;
101+
102+
a = load_bigendian(statebytes + 0); state[0] = a;
103+
b = load_bigendian(statebytes + 8); state[1] = b;
104+
c = load_bigendian(statebytes + 16); state[2] = c;
105+
d = load_bigendian(statebytes + 24); state[3] = d;
106+
e = load_bigendian(statebytes + 32); state[4] = e;
107+
f = load_bigendian(statebytes + 40); state[5] = f;
108+
g = load_bigendian(statebytes + 48); state[6] = g;
109+
h = load_bigendian(statebytes + 56); state[7] = h;
110+
111+
while (inlen >= 128) {
112+
uint64 w0 = load_bigendian(in + 0);
113+
uint64 w1 = load_bigendian(in + 8);
114+
uint64 w2 = load_bigendian(in + 16);
115+
uint64 w3 = load_bigendian(in + 24);
116+
uint64 w4 = load_bigendian(in + 32);
117+
uint64 w5 = load_bigendian(in + 40);
118+
uint64 w6 = load_bigendian(in + 48);
119+
uint64 w7 = load_bigendian(in + 56);
120+
uint64 w8 = load_bigendian(in + 64);
121+
uint64 w9 = load_bigendian(in + 72);
122+
uint64 w10 = load_bigendian(in + 80);
123+
uint64 w11 = load_bigendian(in + 88);
124+
uint64 w12 = load_bigendian(in + 96);
125+
uint64 w13 = load_bigendian(in + 104);
126+
uint64 w14 = load_bigendian(in + 112);
127+
uint64 w15 = load_bigendian(in + 120);
128+
129+
F(w0 ,0x428a2f98d728ae22ULL)
130+
F(w1 ,0x7137449123ef65cdULL)
131+
F(w2 ,0xb5c0fbcfec4d3b2fULL)
132+
F(w3 ,0xe9b5dba58189dbbcULL)
133+
F(w4 ,0x3956c25bf348b538ULL)
134+
F(w5 ,0x59f111f1b605d019ULL)
135+
F(w6 ,0x923f82a4af194f9bULL)
136+
F(w7 ,0xab1c5ed5da6d8118ULL)
137+
F(w8 ,0xd807aa98a3030242ULL)
138+
F(w9 ,0x12835b0145706fbeULL)
139+
F(w10,0x243185be4ee4b28cULL)
140+
F(w11,0x550c7dc3d5ffb4e2ULL)
141+
F(w12,0x72be5d74f27b896fULL)
142+
F(w13,0x80deb1fe3b1696b1ULL)
143+
F(w14,0x9bdc06a725c71235ULL)
144+
F(w15,0xc19bf174cf692694ULL)
145+
146+
EXPAND
147+
148+
F(w0 ,0xe49b69c19ef14ad2ULL)
149+
F(w1 ,0xefbe4786384f25e3ULL)
150+
F(w2 ,0x0fc19dc68b8cd5b5ULL)
151+
F(w3 ,0x240ca1cc77ac9c65ULL)
152+
F(w4 ,0x2de92c6f592b0275ULL)
153+
F(w5 ,0x4a7484aa6ea6e483ULL)
154+
F(w6 ,0x5cb0a9dcbd41fbd4ULL)
155+
F(w7 ,0x76f988da831153b5ULL)
156+
F(w8 ,0x983e5152ee66dfabULL)
157+
F(w9 ,0xa831c66d2db43210ULL)
158+
F(w10,0xb00327c898fb213fULL)
159+
F(w11,0xbf597fc7beef0ee4ULL)
160+
F(w12,0xc6e00bf33da88fc2ULL)
161+
F(w13,0xd5a79147930aa725ULL)
162+
F(w14,0x06ca6351e003826fULL)
163+
F(w15,0x142929670a0e6e70ULL)
164+
165+
EXPAND
166+
167+
F(w0 ,0x27b70a8546d22ffcULL)
168+
F(w1 ,0x2e1b21385c26c926ULL)
169+
F(w2 ,0x4d2c6dfc5ac42aedULL)
170+
F(w3 ,0x53380d139d95b3dfULL)
171+
F(w4 ,0x650a73548baf63deULL)
172+
F(w5 ,0x766a0abb3c77b2a8ULL)
173+
F(w6 ,0x81c2c92e47edaee6ULL)
174+
F(w7 ,0x92722c851482353bULL)
175+
F(w8 ,0xa2bfe8a14cf10364ULL)
176+
F(w9 ,0xa81a664bbc423001ULL)
177+
F(w10,0xc24b8b70d0f89791ULL)
178+
F(w11,0xc76c51a30654be30ULL)
179+
F(w12,0xd192e819d6ef5218ULL)
180+
F(w13,0xd69906245565a910ULL)
181+
F(w14,0xf40e35855771202aULL)
182+
F(w15,0x106aa07032bbd1b8ULL)
183+
184+
EXPAND
185+
186+
F(w0 ,0x19a4c116b8d2d0c8ULL)
187+
F(w1 ,0x1e376c085141ab53ULL)
188+
F(w2 ,0x2748774cdf8eeb99ULL)
189+
F(w3 ,0x34b0bcb5e19b48a8ULL)
190+
F(w4 ,0x391c0cb3c5c95a63ULL)
191+
F(w5 ,0x4ed8aa4ae3418acbULL)
192+
F(w6 ,0x5b9cca4f7763e373ULL)
193+
F(w7 ,0x682e6ff3d6b2b8a3ULL)
194+
F(w8 ,0x748f82ee5defb2fcULL)
195+
F(w9 ,0x78a5636f43172f60ULL)
196+
F(w10,0x84c87814a1f0ab72ULL)
197+
F(w11,0x8cc702081a6439ecULL)
198+
F(w12,0x90befffa23631e28ULL)
199+
F(w13,0xa4506cebde82bde9ULL)
200+
F(w14,0xbef9a3f7b2c67915ULL)
201+
F(w15,0xc67178f2e372532bULL)
202+
203+
EXPAND
204+
205+
F(w0 ,0xca273eceea26619cULL)
206+
F(w1 ,0xd186b8c721c0c207ULL)
207+
F(w2 ,0xeada7dd6cde0eb1eULL)
208+
F(w3 ,0xf57d4f7fee6ed178ULL)
209+
F(w4 ,0x06f067aa72176fbaULL)
210+
F(w5 ,0x0a637dc5a2c898a6ULL)
211+
F(w6 ,0x113f9804bef90daeULL)
212+
F(w7 ,0x1b710b35131c471bULL)
213+
F(w8 ,0x28db77f523047d84ULL)
214+
F(w9 ,0x32caab7b40c72493ULL)
215+
F(w10,0x3c9ebe0a15c9bebcULL)
216+
F(w11,0x431d67c49c100d4cULL)
217+
F(w12,0x4cc5d4becb3e42b6ULL)
218+
F(w13,0x597f299cfc657e2aULL)
219+
F(w14,0x5fcb6fab3ad6faecULL)
220+
F(w15,0x6c44198c4a475817ULL)
221+
222+
a += state[0];
223+
b += state[1];
224+
c += state[2];
225+
d += state[3];
226+
e += state[4];
227+
f += state[5];
228+
g += state[6];
229+
h += state[7];
230+
231+
state[0] = a;
232+
state[1] = b;
233+
state[2] = c;
234+
state[3] = d;
235+
state[4] = e;
236+
state[5] = f;
237+
state[6] = g;
238+
state[7] = h;
239+
240+
in += 128;
241+
inlen -= 128;
242+
}
243+
244+
store_bigendian(statebytes + 0,state[0]);
245+
store_bigendian(statebytes + 8,state[1]);
246+
store_bigendian(statebytes + 16,state[2]);
247+
store_bigendian(statebytes + 24,state[3]);
248+
store_bigendian(statebytes + 32,state[4]);
249+
store_bigendian(statebytes + 40,state[5]);
250+
store_bigendian(statebytes + 48,state[6]);
251+
store_bigendian(statebytes + 56,state[7]);
252+
253+
return inlen;
254+
}
255+
256+
/* -- crypto_hash_sha512 (hash.c) -- */
257+
258+
static const unsigned char iv[64] = {
259+
0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08,
260+
0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b,
261+
0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b,
262+
0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1,
263+
0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1,
264+
0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f,
265+
0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b,
266+
0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79
267+
};
268+
269+
void crypto_hash_sha512(unsigned char *out,
270+
const unsigned char *in,
271+
unsigned long long inlen)
272+
{
273+
unsigned char h[64];
274+
unsigned char padded[256];
275+
int i;
276+
unsigned long long bytes = inlen;
277+
278+
for (i = 0;i < 64;++i) h[i] = iv[i];
279+
280+
crypto_hashblocks_sha512(h,in,inlen);
281+
in += inlen;
282+
inlen &= 127;
283+
in -= inlen;
284+
285+
for (i = 0;i < (int)inlen;++i) padded[i] = in[i];
286+
padded[inlen] = 0x80;
287+
288+
if (inlen < 112) {
289+
for (i = inlen + 1;i < 119;++i) padded[i] = 0;
290+
padded[119] = bytes >> 61;
291+
padded[120] = bytes >> 53;
292+
padded[121] = bytes >> 45;
293+
padded[122] = bytes >> 37;
294+
padded[123] = bytes >> 29;
295+
padded[124] = bytes >> 21;
296+
padded[125] = bytes >> 13;
297+
padded[126] = bytes >> 5;
298+
padded[127] = bytes << 3;
299+
crypto_hashblocks_sha512(h,padded,128);
300+
} else {
301+
for (i = inlen + 1;i < 247;++i) padded[i] = 0;
302+
padded[247] = bytes >> 61;
303+
padded[248] = bytes >> 53;
304+
padded[249] = bytes >> 45;
305+
padded[250] = bytes >> 37;
306+
padded[251] = bytes >> 29;
307+
padded[252] = bytes >> 21;
308+
padded[253] = bytes >> 13;
309+
padded[254] = bytes >> 5;
310+
padded[255] = bytes << 3;
311+
crypto_hashblocks_sha512(h,padded,256);
312+
}
313+
314+
for (i = 0;i < 64;++i) out[i] = h[i];
315+
}

smp-web/cbits/sntrup761.d.mts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
interface Sntrup761Module {
2+
_sntrup761_wasm_keypair(pk: number, sk: number): void
3+
_sntrup761_wasm_enc(c: number, k: number, pk: number): void
4+
_sntrup761_wasm_dec(k: number, c: number, sk: number): void
5+
_malloc(size: number): number
6+
_free(ptr: number): void
7+
HEAPU8: Uint8Array
8+
}
9+
10+
declare function createSntrup761(): Promise<Sntrup761Module>
11+
export default createSntrup761

smp-web/cbits/sntrup761_wasm.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* WASM wrapper for sntrup761.
3+
* Provides JS-callable functions with RNG from JS imports.
4+
*
5+
* Build: emcc sntrup761_wasm.c sntrup761.c sha512.c -O2 -o sntrup761.js \
6+
* -s EXPORTED_FUNCTIONS='["_sntrup761_wasm_keypair","_sntrup761_wasm_enc","_sntrup761_wasm_dec","_malloc","_free"]' \
7+
* -s EXPORTED_RUNTIME_METHODS='["ccall","cwrap"]'
8+
*/
9+
10+
#include "sntrup761.h"
11+
#include <stdlib.h>
12+
13+
/* Import RNG from JS environment */
14+
extern void js_random_bytes(unsigned char *buf, int len);
15+
16+
/* RNG callback adapter for sntrup761 */
17+
static void wasm_random(void *ctx, size_t length, uint8_t *dst) {
18+
(void)ctx;
19+
js_random_bytes(dst, (int)length);
20+
}
21+
22+
/* JS-callable wrappers */
23+
24+
void sntrup761_wasm_keypair(unsigned char *pk, unsigned char *sk) {
25+
sntrup761_keypair(pk, sk, NULL, wasm_random);
26+
}
27+
28+
void sntrup761_wasm_enc(unsigned char *c, unsigned char *k, const unsigned char *pk) {
29+
sntrup761_enc(c, k, pk, NULL, wasm_random);
30+
}
31+
32+
void sntrup761_wasm_dec(unsigned char *k, const unsigned char *c, const unsigned char *sk) {
33+
sntrup761_dec(k, c, sk);
34+
}

0 commit comments

Comments
 (0)