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