7 #define SERVER "https://matrix.org"
8 #define USER_ID "@pscho:matrix.org"
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"
16 // main stack size: 3584
18 bool verified = false;
19 char transactionId[64];
20 OlmSAS * olmSas = NULL;
24 STATIC char encrypted[2048];
25 STATIC char decrypted[2048];
29 MatrixClient * client,
30 const char * event, int eventLen
32 STATIC char eventType[128];
33 memset(eventType, 0, sizeof(eventType));
34 mjson_get_string(event, eventLen, "$.type", eventType, 128);
36 if (strcmp(eventType, "m.key.verification.request") == 0) {
37 mjson_get_string(event, eventLen, "$.content.transaction_id", transactionId, 256);
39 char verificationReadyBuffer[2048];
40 snprintf(verificationReadyBuffer, 2048,
42 "\"from_device\":\"%s\","
43 "\"methods\":[\"m.sas.v1\"],"
44 "\"transaction_id\":\"%s\""
49 MatrixClientSendToDevice(client,
52 verificationReadyBuffer,
53 "m.key.verification.ready");
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,
60 olm_create_sas_random_length(olmSas));
62 OlmUtility * olmUtil = olm_utility(malloc(olm_utility_size()));
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,
71 printf("public key: %.*s\n", olm_sas_pubkey_length(olmSas), publicKey);
73 const char * keyStartJson;
75 mjson_find(event, eventLen, "$.content", &keyStartJson, &keyStartJsonLen);
76 JsonCanonicalize(keyStartJson, keyStartJsonLen, keyStartJsonCanonical, 512);
78 printf("json:\n%.*s\ncanonical json:\n%s\n", keyStartJsonLen, keyStartJson, keyStartJsonCanonical);
81 snprintf(concat, 512+64, "%.*s%s", olm_sas_pubkey_length(olmSas), publicKey, keyStartJsonCanonical);
84 olm_sha256(olmUtil, concat, concatLen, commitment, 1024);
86 STATIC char verificationAcceptBuffer[512];
87 snprintf(verificationAcceptBuffer, 512,
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\""
97 commitmentLen, commitment,
100 MatrixClientSendToDevice(client,
103 verificationAcceptBuffer,
104 "m.key.verification.accept");
106 else if (strcmp(eventType, "m.key.verification.key") == 0) {
107 STATIC char publicKey[128];
108 olm_sas_get_pubkey(olmSas,
112 STATIC char theirPublicKey[128];
113 int theirPublicKeyLen =
114 mjson_get_string(event, eventLen, "$.content.key", theirPublicKey, 128);
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);
120 olm_sas_set_their_key(olmSas, theirPublicKey, theirPublicKeyLen);
122 STATIC char verificationKeyBuffer[256];
123 snprintf(verificationKeyBuffer, 256,
126 "\"transaction_id\":\"%s\""
128 olm_sas_pubkey_length(olmSas), publicKey,
131 MatrixClientSendToDevice(client,
134 verificationKeyBuffer,
135 "m.key.verification.key");
138 STATIC char hkdfInfo[1024];
140 snprintf(hkdfInfo, 1024,
141 "MATRIX_KEY_VERIFICATION_SAS%s%s%s%s%s",
148 unsigned char sasBytes[5];
149 olm_sas_generate_bytes(olmSas,
150 hkdfInfo, hkdfInfoLen,
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];
158 printf("%d %d %d %d %d\n", b0, b1, b2, b3, b4);
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);
170 else if (strcmp(eventType, "m.key.verification.mac") == 0) {
172 const char * masterKey = "vt8tJ5/SxqkvXS+XoGxr+4rJNe8fJfZT3/e/FTwlFsI";
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];
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);
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);
196 snprintf(keyList, 1024,
197 "%s,%s", key1Id, key2Id);
199 STATIC char macInfo[1024];
203 snprintf(macInfo, 1024,
204 "MATRIX_KEY_VERIFICATION_MAC%s%s%s%s%s%s",
211 olm_sas_calculate_mac_fixed_base64(olmSas, keyList, strlen(keyList), macInfo, macInfoLen, keyListMac, 1024);
215 snprintf(macInfo, 1024,
216 "MATRIX_KEY_VERIFICATION_MAC%s%s%s%s%s%s",
223 olm_sas_calculate_mac_fixed_base64(olmSas, key1, strlen(key1), macInfo, macInfoLen, key1Mac, 1024);
227 snprintf(macInfo, 1024,
228 "MATRIX_KEY_VERIFICATION_MAC%s%s%s%s%s%s",
235 olm_sas_calculate_mac_fixed_base64(olmSas, key2, strlen(key2), macInfo, macInfoLen, key2Mac, 1024);
238 STATIC char verificationMacBuffer[1024];
239 snprintf(verificationMacBuffer, 1024,
246 "\"transaction_id\":\"%s\""
255 MatrixClientSendToDevice(client,
258 verificationMacBuffer,
259 "m.key.verification.mac");
261 STATIC char verificationDoneBuffer[128];
262 snprintf(verificationDoneBuffer, 128,
264 "\"transaction_id\":\"%s\""
268 MatrixClientSendToDevice(client,
271 verificationDoneBuffer,
272 "m.key.verification.done");
276 else if (strcmp(eventType, "m.room.encrypted") == 0) {
277 STATIC char algorithm[128];
278 mjson_get_string(event, eventLen, "$.content.algorithm", algorithm, 128);
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);
285 snprintf(jp, 128, "$.content.ciphertext.%s.type", thisDeviceKey);
288 mjson_get_number(event, eventLen, jp, &messageType);
289 int messageTypeInt = (int)messageType;
291 snprintf(jp, 128, "$.content.ciphertext.%s.body", thisDeviceKey);
293 mjson_get_string(event, eventLen, jp, encrypted, 2048);
295 MatrixOlmSession * olmSession;
297 if (! MatrixClientGetOlmSession(client, USER_ID, DEVICE_ID, &olmSession))
299 if (messageTypeInt == 0) {
300 MatrixClientNewOlmSessionIn(client,
307 MatrixClientNewOlmSessionOut(client,
314 printf("event: %.*s\n", eventLen, event);
315 printf("encrypted: %s\n", encrypted);
317 MatrixOlmSessionDecrypt(olmSession,
318 messageTypeInt, encrypted, decrypted, 2048);
320 printf("decrypted: %s\n", decrypted);
322 HandleEvent(client, decrypted, strlen(decrypted));
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);
334 printf("sessionId: %s\n", sessionId);
335 printf("sessionKey: %s\n", sessionKey);
337 MatrixMegolmInSession * megolmInSession;
338 MatrixClientNewMegolmInSession(client, roomId, sessionId, sessionKey, &megolmInSession);
344 MatrixClient * client,
345 const char * room, int roomLen,
346 const char * event, int eventLen)
348 STATIC char eventType[128];
349 memset(eventType, 0, sizeof(eventType));
350 mjson_get_string(event, eventLen, "$.type", eventType, 128);
352 if (strcmp(eventType, "m.room.encrypted") == 0) {
353 STATIC char algorithm[128];
354 mjson_get_string(event, eventLen, "$.content.algorithm", algorithm, 128);
356 if (strcmp(algorithm, "m.megolm.v1.aes-sha2") == 0) {
357 STATIC char sessionId[128];
359 mjson_get_string(event, eventLen, "$.content.session_id", sessionId, 128);
363 MatrixMegolmInSession * megolmInSession;
364 res = MatrixClientGetMegolmInSession(client,
366 sessionId, sessionIdLen,
370 mjson_get_string(event, eventLen, "$.content.ciphertext", encrypted, 2048);
372 MatrixMegolmInSessionDecrypt(megolmInSession, encrypted, strlen(encrypted), decrypted, 2048);
374 printf("decrypted: %s\n", decrypted);
376 HandleEvent(client, decrypted, strlen(decrypted));
379 printf("megolm session not known\n");
383 HandleEvent(client, event, eventLen);
388 MatrixClient * client,
389 char * syncBuffer, int syncBufferLen)
391 STATIC char nextBatch[1024] = {0};
393 MatrixClientSync(client, syncBuffer, syncBufferLen, nextBatch);
397 const char * s = syncBuffer;
398 int slen = strlen(syncBuffer);
400 printf("sync:\n\n%s\n\n", syncBuffer);
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;
409 // printf("%.*s: %.100s\n", klen, k, v);
413 mjson_get_string(s, slen, "$.next_batch", nextBatch, 1024);
420 mjson_find(s, slen, "$.to_device.events", &events, &eventsLen);
422 if (res != MJSON_TOK_INVALID) {
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;
429 HandleEvent(client, v, vlen);
439 mjson_find(s, slen, "$.rooms.join", &rooms, &roomsLen);
441 if (res != MJSON_TOK_INVALID) {
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;
452 mjson_find(v, vlen, "$.timeline.events", &events, &eventsLen);
454 if (res != MJSON_TOK_INVALID) {
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;
461 HandleRoomEvent(client,
476 // sizeof(MatrixOlmAccount);
477 // sizeof(MatrixMegolmInSession);
478 // sizeof(MatrixMegolmOutSession);
479 // sizeof(MatrixOlmSession);
480 // sizeof(MatrixDevice);
482 // STATIC MatrixClient _client;
483 // MatrixClient * client = &_client;
484 MatrixClient * client = (MatrixClient*)malloc(sizeof(MatrixClient));
485 MatrixClientInit(client);
487 MatrixHttpInit(&client->hc, SERVER);
488 MatrixClientSetUserId(client, USER_ID);
490 MatrixClientLoginPassword(client,
494 printf("deviceId: %s\n", client->deviceId);
495 MatrixClientGenerateOnetimeKeys(client, 10);
496 MatrixClientUploadOnetimeKeys(client);
497 MatrixClientUploadDeviceKey(client);
499 STATIC char eventBuffer[1024];
500 MatrixClientGetRoomEvent(client,
504 printf("event: %s\n", eventBuffer);
506 #define SYNC_BUFFER_SIZE 1024*10
508 // char * syncBuffer = (char*)malloc(SYNC_BUFFER_SIZE);
509 STATIC char syncBuffer[SYNC_BUFFER_SIZE];
512 Sync(client, syncBuffer, SYNC_BUFFER_SIZE);
515 printf("verified!\n");
518 while ((c=getchar()) != 'q') {
519 printf("getchar() = %c [%d]\n", c, c);
520 Sync(client, syncBuffer, SYNC_BUFFER_SIZE);
523 // MatrixClientRequestMegolmInSession(client,
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);
537 // int encryptedLen =
538 // mjson_get_string(eventBuffer, strlen(eventBuffer), "$.content.ciphertext", encrypted, 1024);
540 // printf("encrypted: [%.*s]\n", encryptedLen, encrypted);
542 // MatrixMegolmInSessionDecrypt(megolmInSession,
543 // encrypted, encryptedLen,
546 // printf("decrypted: %s\n", decrypted);
548 MatrixClientDeleteDevice(client);
550 MatrixHttpDeinit(&client->hc);
560 wifi_init("Hundehuette", "Affensicherespw55");