+ const char * event, int eventLen\r
+) {\r
+ // get the event type\r
+ STATIC char eventType[128];\r
+ memset(eventType, 0, sizeof(eventType));\r
+ mjson_get_string(event, eventLen, "$.type", eventType, 128);\r
+\r
+ // static variables for verification\r
+ // since verification takes multiple requests\r
+ // data is cleared when verification is finished or started\r
+ static char transactionId[64];\r
+ static char verifyFromDeviceId[DEVICE_ID_SIZE];\r
+ static OlmSAS * olmSas = NULL;\r
+\r
+ // initial verification request, reply that we are ready to verify\r
+ if (strcmp(eventType, "m.key.verification.request") == 0) {\r
+ // reset static data\r
+ memset(transactionId, 0, 64);\r
+ memset(verifyFromDeviceId, 0, DEVICE_ID_SIZE);\r
+ if (olmSas != NULL)\r
+ free(olmSas);\r
+ \r
+ mjson_get_string(event, eventLen, "$.content.transaction_id", transactionId, 64);\r
+ mjson_get_string(event, eventLen, "$.content.from_device", verifyFromDeviceId, DEVICE_ID_SIZE);\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
+ client->userId,\r
+ verifyFromDeviceId,\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
+ // calculate commitment according to \r
+ // https://spec.matrix.org/v1.8/client-server-api/#mkeyverificationaccept\r
+ STATIC char publicKey[64];\r
+ STATIC char keyStartJsonCanonical[512];\r
+ STATIC char concat[512+64];\r
+ STATIC char commitment[1024];\r
+ olm_sas_get_pubkey(olmSas,\r
+ publicKey,\r
+ 64);\r
+\r
+ const char * keyStartJson;\r
+ int keyStartJsonLen;\r
+ mjson_find(event, eventLen, "$.content", &keyStartJson, &keyStartJsonLen);\r
+ JsonCanonicalize(keyStartJson, keyStartJsonLen, keyStartJsonCanonical, 512);\r
+\r
+ int concatLen =\r
+ snprintf(concat, 512+64, "%.*s%s", (int)olm_sas_pubkey_length(olmSas), publicKey, keyStartJsonCanonical);\r
+\r
+ int commitmentLen =\r
+ olm_sha256(olmUtil, concat, concatLen, commitment, 1024);\r
+ olm_clear_utility(olmUtil);\r
+ free(olmUtil);\r
+ \r
+ STATIC char verificationAcceptBuffer[512];\r
+ snprintf(verificationAcceptBuffer, 512,\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
+ client->userId,\r
+ verifyFromDeviceId,\r
+ verificationAcceptBuffer,\r
+ "m.key.verification.accept");\r
+ }\r
+ // send our sas key and calculate sas using their received key\r
+ else if (strcmp(eventType, "m.key.verification.key") == 0) {\r
+ STATIC char publicKey[128];\r
+ olm_sas_get_pubkey(olmSas,\r
+ publicKey,\r
+ 128);\r
+\r
+ STATIC char theirPublicKey[128];\r
+ int theirPublicKeyLen =\r
+ mjson_get_string(event, eventLen, "$.content.key", theirPublicKey, 128);\r
+\r
+ olm_sas_set_their_key(olmSas, theirPublicKey, theirPublicKeyLen);\r
+ \r
+ STATIC char verificationKeyBuffer[256];\r
+ snprintf(verificationKeyBuffer, 256,\r
+ "{"\r
+ "\"key\":\"%.*s\","\r
+ "\"transaction_id\":\"%s\""\r
+ "}",\r
+ (int)olm_sas_pubkey_length(olmSas), publicKey,\r
+ transactionId);\r
+ \r
+ MatrixClientSendToDevice(client,\r
+ client->userId,\r
+ verifyFromDeviceId,\r
+ verificationKeyBuffer,\r
+ "m.key.verification.key");\r
+ \r
+ // sas\r
+ STATIC char hkdfInfo[1024];\r
+ int hkdfInfoLen =\r
+ snprintf(hkdfInfo, 1024,\r
+ "MATRIX_KEY_VERIFICATION_SAS%s%s%s%s%s",\r
+ client->userId,\r
+ verifyFromDeviceId,\r
+ client->userId,\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
+ // for now just printf SAS numbers\r
+ // https://spec.matrix.org/v1.8/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
+ }\r
+ // calculate MACs for signing key, master key and the key list\r
+ else if (strcmp(eventType, "m.key.verification.mac") == 0) { \r
+ // mac\r
+ STATIC char masterKey[123];\r
+ MatrixClientRequestMasterKey(client, masterKey, 123);\r
+\r
+ STATIC char keyList[256];\r
+ STATIC char keyListMac[256];\r
+ STATIC char key1Id[128];\r
+ STATIC char key1[128];\r
+ STATIC char key1Mac[128];\r
+ STATIC char key2Id[128];\r
+ STATIC char key2[128];\r
+ STATIC char key2Mac[128];\r
+\r
+ // keys have to be sorted so write keys/key IDs into key1/key2\r
+ // depending on lexicographical order\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