]> gitweb.ps.run Git - matrix_esp_thesis/commitdiff
actually add Canonical and Verify examples :()
authorPatrick <patrick.schoenberger@posteo.de>
Wed, 13 Sep 2023 20:04:23 +0000 (22:04 +0200)
committerPatrick <patrick.schoenberger@posteo.de>
Wed, 13 Sep 2023 20:04:23 +0000 (22:04 +0200)
examples/Canonical.c [new file with mode: 0644]
examples/Verify.c [new file with mode: 0644]
examples/Verify.rdbg [new file with mode: 0644]

diff --git a/examples/Canonical.c b/examples/Canonical.c
new file mode 100644 (file)
index 0000000..d3a1905
--- /dev/null
@@ -0,0 +1,28 @@
+#include <matrix.h>\r
+#include <mjson.h>\r
+#include <olm/sas.h>\r
+\r
+#include <stdio.h>\r
+\r
+int\r
+main(void)\r
+{\r
+    const char json[] =\r
+    "{"\r
+    "\"method\":\"m.sas.v1\","\r
+    "\"from_device\":\"ULZZOKJBYN\","\r
+    "\"key_agreement_protocols\":[\"curve25519-hkdf-sha256\",\"curve25519\"],"\r
+    "\"hashes\":[\"sha256\"],"\r
+    "\"message_authentication_codes\":[\"hkdf-hmac-sha256.v2\",\"org.matrix.msc3783.hkdf-hmac-sha256\",\"hkdf-hmac-sha256\",\"hmac-sha256\"],"\r
+    "\"short_authentication_string\":[\"decimal\",\"emoji\"],"\r
+    "\"transaction_id\":\"CmMReoy5AK59qd7pa6EO7ocbFwX03isB\""\r
+    "}";\r
+    \r
+    char canonical[1024];\r
+\r
+    JsonCanonicalize(json, strlen(json), canonical, 1024);\r
+\r
+    printf("%s\n", canonical);\r
+\r
+    return 0;\r
+}\r
diff --git a/examples/Verify.c b/examples/Verify.c
new file mode 100644 (file)
index 0000000..ba8989a
--- /dev/null
@@ -0,0 +1,541 @@
+#include <matrix.h>\r
+#include <mjson.h>\r
+#include <olm/sas.h>\r
+\r
+#include <stdio.h>\r
+\r
+#define SERVER       "https://matrix.org"\r
+#define USER_ID      "@pscho:matrix.org"\r
+\r
+#define DEVICE_ID    "ULZZOKJBYN"\r
+#define SENDER_KEY   "cjP41XzRlY+pd8DoiBuKQJj9o15mrx6gkrpqTkAPZ2c"\r
+#define ROOM_ID      "!XKFUjAsGrSSrpDFIxB:matrix.org"\r
+#define EVENT_ID     "$vOS09eUaI0CduqAcaIU5ZVk6ljLQfLspz7UThP8vaUM"\r
+#define SESSION_ID   "90UbGLue3ADVhvW7hFjoA2c6yg0JJKs/lPdMDZXnZAk"\r
+\r
+\r
+bool verified = false;\r
+char transactionId[256];\r
+OlmSAS * olmSas = NULL;\r
+\r
+void\r
+HandleEvent(\r
+    MatrixClient * client,\r
+    const char * event, int eventLen\r
+) {\r
+    static char eventType[128];\r
+    memset(eventType, 0, sizeof(eventType));\r
+    mjson_get_string(event, eventLen, "$.type", eventType, 128);\r
+\r
+    if (strcmp(eventType, "m.key.verification.request") == 0) {\r
+        mjson_get_string(event, eventLen, "$.content.transaction_id", transactionId, 256);\r
+        \r
+        char verificationReadyBuffer[2048];\r
+        snprintf(verificationReadyBuffer, 2048,\r
+            "{"\r
+            "\"from_device\":\"%s\","\r
+            "\"methods\":[\"m.sas.v1\"],"\r
+            "\"transaction_id\":\"%s\""\r
+            "}",\r
+            client->deviceId,\r
+            transactionId);\r
+        \r
+        MatrixClientSendToDevice(client,\r
+            USER_ID,\r
+            DEVICE_ID,\r
+            verificationReadyBuffer,\r
+            "m.key.verification.ready");\r
+    }\r
+    else if (strcmp(eventType, "m.key.verification.start") == 0) {\r
+        olmSas = olm_sas(malloc(olm_sas_size()));\r
+        void * sasRandomBytes = malloc(olm_create_sas_random_length(olmSas));\r
+        olm_create_sas(olmSas,\r
+            sasRandomBytes,\r
+            olm_create_sas_random_length(olmSas));\r
+        \r
+        OlmUtility * olmUtil = olm_utility(malloc(olm_utility_size()));\r
+        \r
+        char publicKey[128];\r
+        char keyStartJsonCanonical[1024];\r
+        char concat[1024];\r
+        char commitment[256];\r
+        olm_sas_get_pubkey(olmSas,\r
+            publicKey,\r
+            128);\r
+        printf("public key: %.*s\n", olm_sas_pubkey_length(olmSas), publicKey);\r
+\r
+        const char * keyStartJson;\r
+        int keyStartJsonLen;\r
+        mjson_find(event, eventLen, "$.content", &keyStartJson, &keyStartJsonLen);\r
+        JsonCanonicalize(keyStartJson, keyStartJsonLen, keyStartJsonCanonical, 1024);\r
+\r
+        printf("json:\n%.*s\ncanonical json:\n%s\n", keyStartJsonLen, keyStartJson, keyStartJsonCanonical);\r
+\r
+        int concatLen =\r
+            snprintf(concat, 1024, "%.*s%s", olm_sas_pubkey_length(olmSas), publicKey, keyStartJsonCanonical);\r
+\r
+        int commitmentLen =\r
+            olm_sha256(olmUtil, concat, concatLen, commitment, 256);\r
+        \r
+        char verificationAcceptBuffer[2048];\r
+        snprintf(verificationAcceptBuffer, 2048,\r
+            "{"\r
+            "\"commitment\":\"%.*s\","\r
+            "\"hash\":\"sha256\","\r
+            "\"key_agreement_protocol\":\"curve25519\","\r
+            "\"message_authentication_code\":\"hkdf-hmac-sha256.v2\","\r
+            "\"method\":\"m.sas.v1\","\r
+            "\"short_authentication_string\":[\"decimal\"],"\r
+            "\"transaction_id\":\"%s\""\r
+            "}",\r
+            commitmentLen, commitment,\r
+            transactionId);\r
+        \r
+        MatrixClientSendToDevice(client,\r
+            USER_ID,\r
+            DEVICE_ID,\r
+            verificationAcceptBuffer,\r
+            "m.key.verification.accept");\r
+    }\r
+    else if (strcmp(eventType, "m.key.verification.key") == 0) {\r
+        char publicKey[128];\r
+        olm_sas_get_pubkey(olmSas,\r
+            publicKey,\r
+            128);\r
+\r
+        char theirPublicKey[128];\r
+        int theirPublicKeyLen =\r
+            mjson_get_string(event, eventLen, "$.content.key", theirPublicKey, 128);\r
+        \r
+        printf("event: %.*s\n", eventLen, event);\r
+        printf("theirPublicKey: %.*s\n", theirPublicKeyLen, theirPublicKey);\r
+        printf("publicKey: %.*s\n", olm_sas_pubkey_length(olmSas), publicKey);\r
+\r
+        olm_sas_set_their_key(olmSas, theirPublicKey, theirPublicKeyLen);\r
+        \r
+        char verificationKeyBuffer[2048];\r
+        snprintf(verificationKeyBuffer, 2048,\r
+            "{"\r
+            "\"key\":\"%.*s\","\r
+            "\"transaction_id\":\"%s\""\r
+            "}",\r
+            olm_sas_pubkey_length(olmSas), publicKey,\r
+            transactionId);\r
+        \r
+        MatrixClientSendToDevice(client,\r
+            USER_ID,\r
+            DEVICE_ID,\r
+            verificationKeyBuffer,\r
+            "m.key.verification.key");\r
+        \r
+        // sas\r
+        char hkdfInfo[1024];\r
+        int hkdfInfoLen =\r
+            snprintf(hkdfInfo, 1024,\r
+                "MATRIX_KEY_VERIFICATION_SAS%s%s%s%s%s",\r
+                USER_ID,\r
+                DEVICE_ID,\r
+                USER_ID,\r
+                client->deviceId,\r
+                transactionId);\r
+\r
+        unsigned char sasBytes[5];\r
+        olm_sas_generate_bytes(olmSas,\r
+            hkdfInfo, hkdfInfoLen,\r
+            sasBytes, 5);\r
+        int b0 = sasBytes[0];\r
+        int b1 = sasBytes[1];\r
+        int b2 = sasBytes[2];\r
+        int b3 = sasBytes[3];\r
+        int b4 = sasBytes[4];\r
+        \r
+        printf("%d %d %d %d %d\n", b0, b1, b2, b3, b4);\r
+\r
+        // https://spec.matrix.org/v1.7/client-server-api/#sas-method-decimal\r
+        printf("%d | %d | %d\n",\r
+            (b0 << 5 | b1 >> 3) + 1000,\r
+            ((b1 & 0x7) << 10 | b2 << 2 | b3 >> 6) + 1000,\r
+            ((b3 & 0x3F) << 7 | b4 >> 1) + 1000);\r
+        printf("%d | %d | %d\n",\r
+            ((b0 << 5) | (b1 >> 3)) + 1000,\r
+            (((b1 & 0x7) << 10) | (b2 << 2) | (b3 >> 6)) + 1000,\r
+            (((b3 & 0x3F) << 7) | (b4 >> 1)) + 1000);\r
+    }\r
+    else if (strcmp(eventType, "m.key.verification.mac") == 0) {        \r
+        // mac\r
+        const char * masterKey = "vt8tJ5/SxqkvXS+XoGxr+4rJNe8fJfZT3/e/FTwlFsI";\r
+\r
+        char keyList[1024];\r
+        char keyListMac[1024];\r
+        char key1Id[1024];\r
+        char key1[1024];\r
+        char key1Mac[1024];\r
+        char key2Id[1024];\r
+        char key2[1024];\r
+        char key2Mac[1024];\r
+\r
+        if (strcmp(masterKey, client->deviceId) < 0) {\r
+            snprintf(key1Id, 1024, "ed25519:%s", masterKey);\r
+            strcpy(key1, masterKey);\r
+            snprintf(key2Id, 1024, "ed25519:%s", client->deviceId);\r
+            MatrixOlmAccountGetSigningKey(&client->olmAccount, key2, 1024);\r
+        }\r
+        else {\r
+            snprintf(key1Id, 1024, "ed25519:%s", client->deviceId);\r
+            MatrixOlmAccountGetSigningKey(&client->olmAccount, key1, 1024);\r
+            snprintf(key2Id, 1024, "ed25519:%s", masterKey);\r
+            strcpy(key2, masterKey);\r
+        }\r
+\r
+        snprintf(keyList, 1024,\r
+            "%s,%s", key1Id, key2Id);\r
+        \r
+        char macInfo[1024];\r
+        int macInfoLen;\r
+        {\r
+            macInfoLen =\r
+                snprintf(macInfo, 1024,\r
+                    "MATRIX_KEY_VERIFICATION_MAC%s%s%s%s%s%s",\r
+                    USER_ID,\r
+                    client->deviceId,\r
+                    USER_ID,\r
+                    DEVICE_ID,\r
+                    transactionId,\r
+                    "KEY_IDS");\r
+            olm_sas_calculate_mac_fixed_base64(olmSas, keyList, strlen(keyList), macInfo, macInfoLen, keyListMac, 1024);\r
+        }\r
+        {\r
+            macInfoLen =\r
+                snprintf(macInfo, 1024,\r
+                    "MATRIX_KEY_VERIFICATION_MAC%s%s%s%s%s%s",\r
+                    USER_ID,\r
+                    client->deviceId,\r
+                    USER_ID,\r
+                    DEVICE_ID,\r
+                    transactionId,\r
+                    key1Id);\r
+            olm_sas_calculate_mac_fixed_base64(olmSas, key1, strlen(key1), macInfo, macInfoLen, key1Mac, 1024);\r
+        }\r
+        {\r
+            macInfoLen =\r
+                snprintf(macInfo, 1024,\r
+                    "MATRIX_KEY_VERIFICATION_MAC%s%s%s%s%s%s",\r
+                    USER_ID,\r
+                    client->deviceId,\r
+                    USER_ID,\r
+                    DEVICE_ID,\r
+                    transactionId,\r
+                    key2Id);\r
+            olm_sas_calculate_mac_fixed_base64(olmSas, key2, strlen(key2), macInfo, macInfoLen, key2Mac, 1024);\r
+        }\r
+\r
+        char verificationMacBuffer[2048];\r
+        snprintf(verificationMacBuffer, 2048,\r
+            "{"\r
+            "\"keys\":\"%s\","\r
+            "\"mac\":{"\r
+            "\"%s\":\"%s\","\r
+            "\"%s\":\"%s\""\r
+            "},"\r
+            "\"transaction_id\":\"%s\""\r
+            "}",\r
+            keyListMac,\r
+            key1Id,\r
+            key1Mac,\r
+            key2Id,\r
+            key2Mac,\r
+            transactionId);\r
+        \r
+        MatrixClientSendToDevice(client,\r
+            USER_ID,\r
+            DEVICE_ID,\r
+            verificationMacBuffer,\r
+            "m.key.verification.mac");\r
+\r
+        char verificationDoneBuffer[2048];\r
+        snprintf(verificationDoneBuffer, 2048,\r
+            "{"\r
+            "\"transaction_id\":\"%s\""\r
+            "}",\r
+            transactionId);\r
+        \r
+        MatrixClientSendToDevice(client,\r
+            USER_ID,\r
+            DEVICE_ID,\r
+            verificationDoneBuffer,\r
+            "m.key.verification.done");\r
+        \r
+        verified = true;\r
+    }\r
+    else if (strcmp(eventType, "m.room.encrypted") == 0) {\r
+        static char algorithm[128];\r
+        mjson_get_string(event, eventLen, "$.content.algorithm", algorithm, 128);\r
+\r
+        if (strcmp(algorithm, "m.olm.v1.curve25519-aes-sha2") == 0) {\r
+            static char thisDeviceKey[DEVICE_KEY_SIZE];\r
+            MatrixOlmAccountGetDeviceKey(&client->olmAccount, thisDeviceKey, DEVICE_KEY_SIZE);\r
+\r
+            static char jp[128];\r
+            snprintf(jp, 128, "$.content.ciphertext.%s.type", thisDeviceKey);\r
+\r
+            double messageType;\r
+            mjson_get_number(event, eventLen, jp, &messageType);\r
+            int messageTypeInt = (int)messageType;\r
+            \r
+            static char encrypted[2048];\r
+            static char decrypted[2048];\r
+\r
+            snprintf(jp, 128, "$.content.ciphertext.%s.body", thisDeviceKey);\r
+\r
+            mjson_get_string(event, eventLen, jp, encrypted, 2048);\r
+\r
+            MatrixOlmSession * olmSession;\r
+            if (messageTypeInt == 0) {\r
+                MatrixClientGetOlmSessionIn(client,\r
+                    USER_ID,\r
+                    DEVICE_ID,\r
+                    encrypted,\r
+                    &olmSession);\r
+            } else {\r
+                MatrixClientGetOlmSessionOut(client,\r
+                    USER_ID,\r
+                    DEVICE_ID,\r
+                    &olmSession);\r
+            }\r
+\r
+            printf("event: %.*s\n", eventLen, event);\r
+            printf("encrypted: %s\n", encrypted);\r
+            \r
+            MatrixOlmSessionDecrypt(olmSession,\r
+                messageTypeInt, encrypted, decrypted, 2048);\r
+            \r
+            printf("decrypted: %s\n", decrypted);\r
+            \r
+            HandleEvent(client, decrypted, strlen(decrypted));\r
+        }\r
+    }\r
+    else if (strcmp(eventType, "m.room_key") == 0) {\r
+        static char roomId[128];\r
+        static char sessionId[128];\r
+        static char sessionKey[1024];\r
+        mjson_get_string(event, eventLen, "$.content.room_id", roomId, 128);\r
+        mjson_get_string(event, eventLen, "$.content.session_id", sessionId, 128);\r
+        mjson_get_string(event, eventLen, "$.content.session_key", sessionKey, 1024);\r
+        \r
+        printf("sessionId: %s\n", sessionId);\r
+        printf("sessionKey: %s\n", sessionKey);\r
+\r
+        MatrixMegolmInSession * megolmInSession;\r
+        MatrixClientNewMegolmInSession(client, roomId, sessionId, sessionKey, &megolmInSession);\r
+    }\r
+    else if (strcmp(eventType, "m.forwarded_room_key") == 0) {\r
+        static char roomId[128];\r
+        static char sessionId[128];\r
+        static char sessionKey[1024];\r
+        mjson_get_string(event, eventLen, "$.content.room_id", roomId, 128);\r
+        mjson_get_string(event, eventLen, "$.content.session_id", sessionId, 128);\r
+        mjson_get_string(event, eventLen, "$.content.session_key", sessionKey, 1024);\r
+        \r
+        printf("sessionId: %s\n", sessionId);\r
+        printf("sessionKey: %s\n", sessionKey);\r
+\r
+        MatrixMegolmInSession * megolmInSession;\r
+        MatrixClientNewMegolmInSession(client, roomId, sessionId, sessionKey, &megolmInSession);\r
+    }\r
+}\r
+\r
+void\r
+HandleRoomEvent(\r
+    MatrixClient * client,\r
+    const char * room, int roomLen,\r
+    const char * event, int eventLen)\r
+{\r
+    static char eventType[128];\r
+    memset(eventType, 0, sizeof(eventType));\r
+    mjson_get_string(event, eventLen, "$.type", eventType, 128);\r
+\r
+    if (strcmp(eventType, "m.room.encrypted") == 0) {\r
+        static char algorithm[128];\r
+        mjson_get_string(event, eventLen, "$.content.algorithm", algorithm, 128);\r
+\r
+        if (strcmp(algorithm, "m.megolm.v1.aes-sha2") == 0) {\r
+            static char sessionId[128];\r
+            int sessionIdLen =\r
+                mjson_get_string(event, eventLen, "$.content.session_id", sessionId, 128);\r
+\r
+            bool res;\r
+\r
+            MatrixMegolmInSession * megolmInSession;\r
+            res = MatrixClientGetMegolmInSession(client,\r
+                room, roomLen,\r
+                sessionId, sessionIdLen,\r
+                &megolmInSession);\r
+\r
+            if (res) {\r
+                static char encrypted[2048];\r
+                static char decrypted[2048];\r
+                mjson_get_string(event, eventLen, "$.content.ciphertext", encrypted, 2048);\r
+\r
+                MatrixMegolmInSessionDecrypt(megolmInSession, encrypted, strlen(encrypted), decrypted, 2048);\r
+\r
+                printf("decrypted: %s\n", decrypted);\r
+\r
+                HandleEvent(client, decrypted, strlen(decrypted));\r
+            }\r
+            else {\r
+                printf("megolm session not known\n");\r
+            }\r
+        }\r
+    }\r
+    HandleEvent(client, event, eventLen);\r
+}\r
+\r
+void\r
+Sync(\r
+    MatrixClient * client\r
+) {\r
+    static char nextBatch[1024];\r
+\r
+    static char syncBuffer[1024*50];\r
+    MatrixClientSync(client, syncBuffer, 1024*50, nextBatch);\r
+    \r
+    int res;\r
+\r
+    const char * s = syncBuffer;\r
+    int slen = strlen(syncBuffer);\r
+    \r
+    // {\r
+    // int koff, klen, voff, vlen, vtype, off = 0;\r
+    // for (off = 0; (off = mjson_next(s, slen, off, &koff, &klen,\r
+    //                                 &voff, &vlen, &vtype)) != 0; ) {\r
+    //     const char * k = s + koff;\r
+    //     const char * v = s + voff;\r
+\r
+    //     printf("%.*s: %.100s\n", klen, k, v);\r
+    // }\r
+    // }\r
+\r
+    mjson_get_string(s, slen, "$.next_batch", nextBatch, 1024);\r
+\r
+    // to_device\r
+\r
+    const char * events;\r
+    int eventsLen;\r
+    res =\r
+        mjson_find(s, slen, "$.to_device.events", &events, &eventsLen);\r
+    \r
+    if (res != MJSON_TOK_INVALID) {\r
+        {\r
+        int koff, klen, voff, vlen, vtype, off = 0;\r
+        for (off = 0; (off = mjson_next(events, eventsLen, off, &koff, &klen,\r
+                                        &voff, &vlen, &vtype)) != 0; ) {\r
+            const char * v = events + voff;\r
+\r
+            HandleEvent(client, v, vlen);\r
+        }\r
+        }\r
+    }\r
+\r
+    // rooms\r
+    \r
+    const char * rooms;\r
+    int roomsLen;\r
+    res =\r
+        mjson_find(s, slen, "$.rooms.join", &rooms, &roomsLen);\r
+    \r
+    if (res != MJSON_TOK_INVALID) {\r
+        {\r
+        int koff, klen, voff, vlen, vtype, off = 0;\r
+        for (off = 0; (off = mjson_next(rooms, roomsLen, off, &koff, &klen,\r
+                                        &voff, &vlen, &vtype)) != 0; ) {\r
+            const char * k = rooms + koff;\r
+            const char * v = rooms + voff;\r
+\r
+            const char * events;\r
+            int eventsLen;\r
+            res =\r
+                mjson_find(v, vlen, "$.timeline.events", &events, &eventsLen);\r
+            \r
+            if (res != MJSON_TOK_INVALID) {\r
+                {\r
+                int koff2, klen2, voff2, vlen2, vtype2, off2 = 0;\r
+                for (off2 = 0; (off2 = mjson_next(events, eventsLen, off2, &koff2, &klen2,\r
+                                                &voff2, &vlen2, &vtype2)) != 0; ) {\r
+                    const char * v2 = events + voff2;\r
+\r
+                    HandleRoomEvent(client,\r
+                        k+1, klen-2,\r
+                        v2, vlen2);\r
+                }\r
+                }\r
+            }\r
+        }\r
+        }\r
+    }\r
+}\r
+\r
+\r
+int\r
+main(void)\r
+{\r
+    MatrixClient client;\r
+    MatrixClientInit(&client,\r
+        SERVER);\r
+    MatrixHttpInit(&client);\r
+    MatrixClientSetUserId(&client, USER_ID);\r
+\r
+    MatrixClientLoginPassword(&client,\r
+        "pscho",\r
+        "Wc23EbmB9G3faMq",\r
+        "Test1");\r
+    printf("deviceId: %s\n", client.deviceId);\r
+    MatrixClientGenerateOnetimeKeys(&client, 10);\r
+    MatrixClientUploadOnetimeKeys(&client);\r
+    MatrixClientUploadDeviceKey(&client);\r
+\r
+    static char eventBuffer[1024];\r
+    MatrixClientGetRoomEvent(&client,\r
+        ROOM_ID,\r
+        EVENT_ID,\r
+        eventBuffer, 1024);\r
+    printf("event: %s\n", eventBuffer);\r
+    \r
+    while (! verified)\r
+        Sync(&client);\r
+    \r
+    // while (getchar() != 'q')\r
+    //     Sync(&client);\r
+    \r
+    MatrixClientRequestMegolmInSession(&client,\r
+        ROOM_ID,\r
+        SESSION_ID,\r
+        SENDER_KEY,\r
+        USER_ID,\r
+        DEVICE_ID);\r
+\r
+    MatrixMegolmInSession * megolmInSession;\r
+    while (! MatrixClientGetMegolmInSession(&client,\r
+        ROOM_ID, strlen(ROOM_ID),\r
+        SESSION_ID, strlen(SESSION_ID),\r
+        &megolmInSession))\r
+        Sync(&client);\r
+\r
+    static char encryptedBuffer[1024];\r
+    int encryptedBufferLen =\r
+        mjson_get_string(eventBuffer, strlen(eventBuffer), "$.content.ciphertext", encryptedBuffer, 1024);\r
+    \r
+    printf("encryptedBuffer: [%.*s]\n", encryptedBufferLen, encryptedBuffer);\r
+\r
+    static char decryptedBuffer[1024];\r
+    MatrixMegolmInSessionDecrypt(megolmInSession,\r
+        encryptedBuffer, encryptedBufferLen,\r
+        decryptedBuffer, 1024);\r
+\r
+    printf("decrypted: %s\n", decryptedBuffer);\r
+\r
+    MatrixClientDeleteDevice(&client);\r
+        \r
+    MatrixHttpDeinit(&client);\r
+\r
+    return 0;\r
+}\r
diff --git a/examples/Verify.rdbg b/examples/Verify.rdbg
new file mode 100644 (file)
index 0000000..099e62c
Binary files /dev/null and b/examples/Verify.rdbg differ