]> gitweb.ps.run Git - matrix_esp_thesis/blob - esp32/esp_project/main/Verify.c
use global static buffers to save memory, get Verify example working on ESP32
[matrix_esp_thesis] / esp32 / esp_project / main / Verify.c
1 #include <matrix.h>
2 #include <mjson.h>
3 #include <olm/sas.h>
4
5 #include <stdio.h>
6
7 #define SERVER       "https://matrix.org"
8 #define USER_ID      "@pscho:matrix.org"
9
10 #define DEVICE_ID    "ULZZOKJBYN"
11 #define SENDER_KEY   "cjP41XzRlY+pd8DoiBuKQJj9o15mrx6gkrpqTkAPZ2c"
12 #define ROOM_ID      "!XKFUjAsGrSSrpDFIxB:matrix.org"
13 #define EVENT_ID     "$vOS09eUaI0CduqAcaIU5ZVk6ljLQfLspz7UThP8vaUM"
14 #define SESSION_ID   "90UbGLue3ADVhvW7hFjoA2c6yg0JJKs/lPdMDZXnZAk"
15
16 // main stack size: 3584
17
18 bool verified = false;
19 char transactionId[64];
20 OlmSAS * olmSas = NULL;
21
22 #define STATIC static
23
24 STATIC char encrypted[2048];
25 STATIC char decrypted[2048];
26
27 void
28 HandleEvent(
29     MatrixClient * client,
30     const char * event, int eventLen
31 ) {
32     STATIC char eventType[128];
33     memset(eventType, 0, sizeof(eventType));
34     mjson_get_string(event, eventLen, "$.type", eventType, 128);
35
36     if (strcmp(eventType, "m.key.verification.request") == 0) {
37         mjson_get_string(event, eventLen, "$.content.transaction_id", transactionId, 256);
38         
39         char verificationReadyBuffer[2048];
40         snprintf(verificationReadyBuffer, 2048,
41             "{"
42             "\"from_device\":\"%s\","
43             "\"methods\":[\"m.sas.v1\"],"
44             "\"transaction_id\":\"%s\""
45             "}",
46             client->deviceId,
47             transactionId);
48         
49         MatrixClientSendToDevice(client,
50             USER_ID,
51             DEVICE_ID,
52             verificationReadyBuffer,
53             "m.key.verification.ready");
54     }
55     else if (strcmp(eventType, "m.key.verification.start") == 0) {
56         olmSas = olm_sas(malloc(olm_sas_size()));
57         void * sasRandomBytes = malloc(olm_create_sas_random_length(olmSas));
58         olm_create_sas(olmSas,
59             sasRandomBytes,
60             olm_create_sas_random_length(olmSas));
61         
62         OlmUtility * olmUtil = olm_utility(malloc(olm_utility_size()));
63         
64         STATIC char publicKey[64];
65         STATIC char keyStartJsonCanonical[512];
66         STATIC char concat[512+64];
67         STATIC char commitment[1024];
68         olm_sas_get_pubkey(olmSas,
69             publicKey,
70             64);
71         printf("public key: %.*s\n", olm_sas_pubkey_length(olmSas), publicKey);
72
73         const char * keyStartJson;
74         int keyStartJsonLen;
75         mjson_find(event, eventLen, "$.content", &keyStartJson, &keyStartJsonLen);
76         JsonCanonicalize(keyStartJson, keyStartJsonLen, keyStartJsonCanonical, 512);
77
78         printf("json:\n%.*s\ncanonical json:\n%s\n", keyStartJsonLen, keyStartJson, keyStartJsonCanonical);
79
80         int concatLen =
81             snprintf(concat, 512+64, "%.*s%s", olm_sas_pubkey_length(olmSas), publicKey, keyStartJsonCanonical);
82
83         int commitmentLen =
84             olm_sha256(olmUtil, concat, concatLen, commitment, 1024);
85         
86         STATIC char verificationAcceptBuffer[512];
87         snprintf(verificationAcceptBuffer, 512,
88             "{"
89             "\"commitment\":\"%.*s\","
90             "\"hash\":\"sha256\","
91             "\"key_agreement_protocol\":\"curve25519\","
92             "\"message_authentication_code\":\"hkdf-hmac-sha256.v2\","
93             "\"method\":\"m.sas.v1\","
94             "\"short_authentication_string\":[\"decimal\"],"
95             "\"transaction_id\":\"%s\""
96             "}",
97             commitmentLen, commitment,
98             transactionId);
99         
100         MatrixClientSendToDevice(client,
101             USER_ID,
102             DEVICE_ID,
103             verificationAcceptBuffer,
104             "m.key.verification.accept");
105     }
106     else if (strcmp(eventType, "m.key.verification.key") == 0) {
107         STATIC char publicKey[128];
108         olm_sas_get_pubkey(olmSas,
109             publicKey,
110             128);
111
112         STATIC char theirPublicKey[128];
113         int theirPublicKeyLen =
114             mjson_get_string(event, eventLen, "$.content.key", theirPublicKey, 128);
115         
116         printf("event: %.*s\n", eventLen, event);
117         printf("theirPublicKey: %.*s\n", theirPublicKeyLen, theirPublicKey);
118         printf("publicKey: %.*s\n", olm_sas_pubkey_length(olmSas), publicKey);
119
120         olm_sas_set_their_key(olmSas, theirPublicKey, theirPublicKeyLen);
121         
122         STATIC char verificationKeyBuffer[256];
123         snprintf(verificationKeyBuffer, 256,
124             "{"
125             "\"key\":\"%.*s\","
126             "\"transaction_id\":\"%s\""
127             "}",
128             olm_sas_pubkey_length(olmSas), publicKey,
129             transactionId);
130         
131         MatrixClientSendToDevice(client,
132             USER_ID,
133             DEVICE_ID,
134             verificationKeyBuffer,
135             "m.key.verification.key");
136         
137         // sas
138         STATIC char hkdfInfo[1024];
139         int hkdfInfoLen =
140             snprintf(hkdfInfo, 1024,
141                 "MATRIX_KEY_VERIFICATION_SAS%s%s%s%s%s",
142                 USER_ID,
143                 DEVICE_ID,
144                 USER_ID,
145                 client->deviceId,
146                 transactionId);
147
148         unsigned char sasBytes[5];
149         olm_sas_generate_bytes(olmSas,
150             hkdfInfo, hkdfInfoLen,
151             sasBytes, 5);
152         int b0 = sasBytes[0];
153         int b1 = sasBytes[1];
154         int b2 = sasBytes[2];
155         int b3 = sasBytes[3];
156         int b4 = sasBytes[4];
157         
158         printf("%d %d %d %d %d\n", b0, b1, b2, b3, b4);
159
160         // https://spec.matrix.org/v1.7/client-server-api/#sas-method-decimal
161         printf("%d | %d | %d\n",
162             (b0 << 5 | b1 >> 3) + 1000,
163             ((b1 & 0x7) << 10 | b2 << 2 | b3 >> 6) + 1000,
164             ((b3 & 0x3F) << 7 | b4 >> 1) + 1000);
165         printf("%d | %d | %d\n",
166             ((b0 << 5) | (b1 >> 3)) + 1000,
167             (((b1 & 0x7) << 10) | (b2 << 2) | (b3 >> 6)) + 1000,
168             (((b3 & 0x3F) << 7) | (b4 >> 1)) + 1000);
169     }
170     else if (strcmp(eventType, "m.key.verification.mac") == 0) {        
171         // mac
172         const char * masterKey = "vt8tJ5/SxqkvXS+XoGxr+4rJNe8fJfZT3/e/FTwlFsI";
173
174         STATIC char keyList[256];
175         STATIC char keyListMac[256];
176         STATIC char key1Id[128];
177         STATIC char key1[128];
178         STATIC char key1Mac[128];
179         STATIC char key2Id[128];
180         STATIC char key2[128];
181         STATIC char key2Mac[128];
182
183         if (strcmp(masterKey, client->deviceId) < 0) {
184             snprintf(key1Id, 1024, "ed25519:%s", masterKey);
185             strcpy(key1, masterKey);
186             snprintf(key2Id, 1024, "ed25519:%s", client->deviceId);
187             MatrixOlmAccountGetSigningKey(&client->olmAccount, key2, 1024);
188         }
189         else {
190             snprintf(key1Id, 1024, "ed25519:%s", client->deviceId);
191             MatrixOlmAccountGetSigningKey(&client->olmAccount, key1, 1024);
192             snprintf(key2Id, 1024, "ed25519:%s", masterKey);
193             strcpy(key2, masterKey);
194         }
195
196         snprintf(keyList, 1024,
197             "%s,%s", key1Id, key2Id);
198         
199         STATIC char macInfo[1024];
200         int macInfoLen;
201         {
202             macInfoLen =
203                 snprintf(macInfo, 1024,
204                     "MATRIX_KEY_VERIFICATION_MAC%s%s%s%s%s%s",
205                     USER_ID,
206                     client->deviceId,
207                     USER_ID,
208                     DEVICE_ID,
209                     transactionId,
210                     "KEY_IDS");
211             olm_sas_calculate_mac_fixed_base64(olmSas, keyList, strlen(keyList), macInfo, macInfoLen, keyListMac, 1024);
212         }
213         {
214             macInfoLen =
215                 snprintf(macInfo, 1024,
216                     "MATRIX_KEY_VERIFICATION_MAC%s%s%s%s%s%s",
217                     USER_ID,
218                     client->deviceId,
219                     USER_ID,
220                     DEVICE_ID,
221                     transactionId,
222                     key1Id);
223             olm_sas_calculate_mac_fixed_base64(olmSas, key1, strlen(key1), macInfo, macInfoLen, key1Mac, 1024);
224         }
225         {
226             macInfoLen =
227                 snprintf(macInfo, 1024,
228                     "MATRIX_KEY_VERIFICATION_MAC%s%s%s%s%s%s",
229                     USER_ID,
230                     client->deviceId,
231                     USER_ID,
232                     DEVICE_ID,
233                     transactionId,
234                     key2Id);
235             olm_sas_calculate_mac_fixed_base64(olmSas, key2, strlen(key2), macInfo, macInfoLen, key2Mac, 1024);
236         }
237
238         STATIC char verificationMacBuffer[1024];
239         snprintf(verificationMacBuffer, 1024,
240             "{"
241             "\"keys\":\"%s\","
242             "\"mac\":{"
243             "\"%s\":\"%s\","
244             "\"%s\":\"%s\""
245             "},"
246             "\"transaction_id\":\"%s\""
247             "}",
248             keyListMac,
249             key1Id,
250             key1Mac,
251             key2Id,
252             key2Mac,
253             transactionId);
254         
255         MatrixClientSendToDevice(client,
256             USER_ID,
257             DEVICE_ID,
258             verificationMacBuffer,
259             "m.key.verification.mac");
260
261         STATIC char verificationDoneBuffer[128];
262         snprintf(verificationDoneBuffer, 128,
263             "{"
264             "\"transaction_id\":\"%s\""
265             "}",
266             transactionId);
267         
268         MatrixClientSendToDevice(client,
269             USER_ID,
270             DEVICE_ID,
271             verificationDoneBuffer,
272             "m.key.verification.done");
273         
274         verified = true;
275     }
276     else if (strcmp(eventType, "m.room.encrypted") == 0) {
277         STATIC char algorithm[128];
278         mjson_get_string(event, eventLen, "$.content.algorithm", algorithm, 128);
279
280         if (strcmp(algorithm, "m.olm.v1.curve25519-aes-sha2") == 0) {
281             STATIC char thisDeviceKey[DEVICE_KEY_SIZE];
282             MatrixOlmAccountGetDeviceKey(&client->olmAccount, thisDeviceKey, DEVICE_KEY_SIZE);
283
284             STATIC char jp[128];
285             snprintf(jp, 128, "$.content.ciphertext.%s.type", thisDeviceKey);
286
287             double messageType;
288             mjson_get_number(event, eventLen, jp, &messageType);
289             int messageTypeInt = (int)messageType;
290
291             snprintf(jp, 128, "$.content.ciphertext.%s.body", thisDeviceKey);
292
293             mjson_get_string(event, eventLen, jp, encrypted, 2048);
294
295             MatrixOlmSession * olmSession;
296             
297             if (! MatrixClientGetOlmSession(client, USER_ID, DEVICE_ID, &olmSession))
298             {
299                 if (messageTypeInt == 0) {
300                     MatrixClientNewOlmSessionIn(client,
301                         USER_ID,
302                         DEVICE_ID,
303                         encrypted,
304                         &olmSession);
305                 }
306                 else {
307                     MatrixClientNewOlmSessionOut(client,
308                         USER_ID,
309                         DEVICE_ID,
310                         &olmSession);
311                 }
312             }
313
314             printf("event: %.*s\n", eventLen, event);
315             printf("encrypted: %s\n", encrypted);
316             
317             MatrixOlmSessionDecrypt(olmSession,
318                 messageTypeInt, encrypted, decrypted, 2048);
319             
320             printf("decrypted: %s\n", decrypted);
321             
322             HandleEvent(client, decrypted, strlen(decrypted));
323         }
324     }
325     else if (strcmp(eventType, "m.room_key") == 0 ||
326              strcmp(eventType, "m.forwarded_room_key") == 0) {
327         STATIC char roomId[128];
328         STATIC char sessionId[128];
329         STATIC char sessionKey[1024];
330         mjson_get_string(event, eventLen, "$.content.room_id", roomId, 128);
331         mjson_get_string(event, eventLen, "$.content.session_id", sessionId, 128);
332         mjson_get_string(event, eventLen, "$.content.session_key", sessionKey, 1024);
333         
334         printf("sessionId: %s\n", sessionId);
335         printf("sessionKey: %s\n", sessionKey);
336
337         MatrixMegolmInSession * megolmInSession;
338         MatrixClientNewMegolmInSession(client, roomId, sessionId, sessionKey, &megolmInSession);
339     }
340 }
341
342 void
343 HandleRoomEvent(
344     MatrixClient * client,
345     const char * room, int roomLen,
346     const char * event, int eventLen)
347 {
348     STATIC char eventType[128];
349     memset(eventType, 0, sizeof(eventType));
350     mjson_get_string(event, eventLen, "$.type", eventType, 128);
351
352     if (strcmp(eventType, "m.room.encrypted") == 0) {
353         STATIC char algorithm[128];
354         mjson_get_string(event, eventLen, "$.content.algorithm", algorithm, 128);
355
356         if (strcmp(algorithm, "m.megolm.v1.aes-sha2") == 0) {
357             STATIC char sessionId[128];
358             int sessionIdLen =
359                 mjson_get_string(event, eventLen, "$.content.session_id", sessionId, 128);
360
361             bool res;
362
363             MatrixMegolmInSession * megolmInSession;
364             res = MatrixClientGetMegolmInSession(client,
365                 room, roomLen,
366                 sessionId, sessionIdLen,
367                 &megolmInSession);
368
369             if (res) {
370                 mjson_get_string(event, eventLen, "$.content.ciphertext", encrypted, 2048);
371
372                 MatrixMegolmInSessionDecrypt(megolmInSession, encrypted, strlen(encrypted), decrypted, 2048);
373
374                 printf("decrypted: %s\n", decrypted);
375
376                 HandleEvent(client, decrypted, strlen(decrypted));
377             }
378             else {
379                 printf("megolm session not known\n");
380             }
381         }
382     }
383     HandleEvent(client, event, eventLen);
384 }
385
386 void
387 Sync(
388     MatrixClient * client,
389     char * syncBuffer, int syncBufferLen)
390 {
391     STATIC char nextBatch[1024] = {0};
392
393     MatrixClientSync(client, syncBuffer, syncBufferLen, nextBatch);
394     
395     int res;
396
397     const char * s = syncBuffer;
398     int slen = strlen(syncBuffer);
399     
400     printf("sync:\n\n%s\n\n", syncBuffer);
401     
402     // {
403     // int koff, klen, voff, vlen, vtype, off = 0;
404     // for (off = 0; (off = mjson_next(s, slen, off, &koff, &klen,
405     //                                 &voff, &vlen, &vtype)) != 0; ) {
406     //     const char * k = s + koff;
407     //     const char * v = s + voff;
408
409     //     printf("%.*s: %.100s\n", klen, k, v);
410     // }
411     // }
412
413     mjson_get_string(s, slen, "$.next_batch", nextBatch, 1024);
414
415     // to_device
416
417     const char * events;
418     int eventsLen;
419     res =
420         mjson_find(s, slen, "$.to_device.events", &events, &eventsLen);
421     
422     if (res != MJSON_TOK_INVALID) {
423         {
424         int koff, klen, voff, vlen, vtype, off = 0;
425         for (off = 0; (off = mjson_next(events, eventsLen, off, &koff, &klen,
426                                         &voff, &vlen, &vtype)) != 0; ) {
427             const char * v = events + voff;
428
429             HandleEvent(client, v, vlen);
430         }
431         }
432     }
433
434     // rooms
435     
436     const char * rooms;
437     int roomsLen;
438     res =
439         mjson_find(s, slen, "$.rooms.join", &rooms, &roomsLen);
440     
441     if (res != MJSON_TOK_INVALID) {
442         {
443         int koff, klen, voff, vlen, vtype, off = 0;
444         for (off = 0; (off = mjson_next(rooms, roomsLen, off, &koff, &klen,
445                                         &voff, &vlen, &vtype)) != 0; ) {
446             const char * k = rooms + koff;
447             const char * v = rooms + voff;
448
449             const char * events;
450             int eventsLen;
451             res =
452                 mjson_find(v, vlen, "$.timeline.events", &events, &eventsLen);
453             
454             if (res != MJSON_TOK_INVALID) {
455                 {
456                 int koff2, klen2, voff2, vlen2, vtype2, off2 = 0;
457                 for (off2 = 0; (off2 = mjson_next(events, eventsLen, off2, &koff2, &klen2,
458                                                 &voff2, &vlen2, &vtype2)) != 0; ) {
459                     const char * v2 = events + voff2;
460
461                     HandleRoomEvent(client,
462                         k+1, klen-2,
463                         v2, vlen2);
464                 }
465                 }
466             }
467         }
468         }
469     }
470 }
471
472
473 int
474 main(void)
475 {
476     // sizeof(MatrixOlmAccount);
477     // sizeof(MatrixMegolmInSession);
478     // sizeof(MatrixMegolmOutSession);
479     // sizeof(MatrixOlmSession);    
480     // sizeof(MatrixDevice);
481
482     // STATIC MatrixClient _client;
483     // MatrixClient * client = &_client;
484     MatrixClient * client = (MatrixClient*)malloc(sizeof(MatrixClient));
485     MatrixClientInit(client);
486
487     MatrixHttpInit(&client->hc, SERVER);
488     MatrixClientSetUserId(client, USER_ID);
489
490     MatrixClientLoginPassword(client,
491         "pscho",
492         "Wc23EbmB9G3faMq",
493         "Test1");
494     printf("deviceId: %s\n", client->deviceId);
495     MatrixClientGenerateOnetimeKeys(client, 10);
496     MatrixClientUploadOnetimeKeys(client);
497     MatrixClientUploadDeviceKey(client);
498
499     STATIC char eventBuffer[1024];
500     MatrixClientGetRoomEvent(client,
501         ROOM_ID,
502         EVENT_ID,
503         eventBuffer, 1024);
504     printf("event: %s\n", eventBuffer);
505
506     #define SYNC_BUFFER_SIZE 1024*10
507
508     // char * syncBuffer = (char*)malloc(SYNC_BUFFER_SIZE);
509     STATIC char syncBuffer[SYNC_BUFFER_SIZE];
510
511     while (! verified) {
512         Sync(client, syncBuffer, SYNC_BUFFER_SIZE);
513     }
514
515     printf("verified!\n");
516     
517     int c;
518     while ((c=getchar()) != 'q') {
519         printf("getchar() = %c [%d]\n", c, c);
520         Sync(client, syncBuffer, SYNC_BUFFER_SIZE);
521     }
522     
523     // MatrixClientRequestMegolmInSession(client,
524     //     ROOM_ID,
525     //     SESSION_ID,
526     //     SENDER_KEY,
527     //     USER_ID,
528     //     DEVICE_ID);
529
530     // MatrixMegolmInSession * megolmInSession;
531     // while (! MatrixClientGetMegolmInSession(client,
532     //     ROOM_ID, strlen(ROOM_ID),
533     //     SESSION_ID, strlen(SESSION_ID),
534     //     &megolmInSession))
535     //     Sync(client, syncBuffer, SYNC_BUFFER_SIZE);
536
537     // int encryptedLen =
538     //     mjson_get_string(eventBuffer, strlen(eventBuffer), "$.content.ciphertext", encrypted, 1024);
539     
540     // printf("encrypted: [%.*s]\n", encryptedLen, encrypted);
541
542     // MatrixMegolmInSessionDecrypt(megolmInSession,
543     //     encrypted, encryptedLen,
544     //     decrypted, 1024);
545
546     // printf("decrypted: %s\n", decrypted);
547
548     MatrixClientDeleteDevice(client);
549         
550     MatrixHttpDeinit(&client->hc);
551
552     return 0;
553 }
554
555 #include "wifi.h"
556
557 void
558 app_main(void)
559 {
560     wifi_init("Hundehuette", "Affensicherespw55");
561
562     main();
563 }