aboutsummaryrefslogtreecommitdiff
path: root/nearby/presence/ldt_np_c_sample/tests/ldt_ffi_tests.cc
diff options
context:
space:
mode:
Diffstat (limited to 'nearby/presence/ldt_np_c_sample/tests/ldt_ffi_tests.cc')
-rw-r--r--nearby/presence/ldt_np_c_sample/tests/ldt_ffi_tests.cc300
1 files changed, 300 insertions, 0 deletions
diff --git a/nearby/presence/ldt_np_c_sample/tests/ldt_ffi_tests.cc b/nearby/presence/ldt_np_c_sample/tests/ldt_ffi_tests.cc
new file mode 100644
index 0000000..e66af65
--- /dev/null
+++ b/nearby/presence/ldt_np_c_sample/tests/ldt_ffi_tests.cc
@@ -0,0 +1,300 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <gtest/gtest.h>
+#include <json/json.h>
+
+extern "C" {
+#include "np_ldt.h"
+}
+
+#include <algorithm>
+#include <fstream>
+
+// TODO: get multi threaded tests working on windows
+#ifndef _WIN32
+#include <pthread.h>
+#endif
+
+#ifdef LDT_TEST_VECTORS
+static const char *PATH_TO_DATA_FILE = LDT_TEST_VECTORS;
+#else
+static const char *PATH_TO_DATA_FILE = "np_adv_test_vectors.json";
+#endif
+static const uint8_t KEY_SEED_BYTES[] = {
+ 204, 219, 36, 137, 233, 252, 172, 66, 179, 147, 72, 184, 148, 30, 209, 154,
+ 29, 54, 14, 117, 224, 152, 200, 193, 94, 107, 28, 194, 182, 32, 205, 57};
+static const uint8_t KNOWN_HMAC_BYTES[] = {
+ 223, 185, 10, 31, 155, 31, 226, 141, 24, 187, 204,
+ 165, 34, 64, 181, 204, 44, 203, 95, 141, 82, 137,
+ 163, 203, 100, 235, 53, 65, 202, 97, 75, 180};
+static const uint8_t TEST_DATA_BYTES[] = {205, 104, 63, 225, 161, 209, 248,
+ 70, 84, 61, 10, 19, 212, 174,
+ 164, 0, 64, 200, 214, 123};
+
+static NpLdtSalt salt = {{12, 15}};
+
+static NpLdtEncryptHandle create_enc_handle_from_test_key() {
+ NpLdtKeySeed key_seed;
+ memcpy(key_seed.bytes, KEY_SEED_BYTES, 32);
+
+ return NpLdtEncryptCreate(key_seed);
+}
+
+static NpLdtDecryptHandle create_dec_handle_from_test_key() {
+ NpLdtKeySeed key_seed;
+ memcpy(key_seed.bytes, KEY_SEED_BYTES, 32);
+
+ NpMetadataKeyHmac known_hmac;
+ memcpy(known_hmac.bytes, KNOWN_HMAC_BYTES, 32);
+
+ return NpLdtDecryptCreate(key_seed, known_hmac);
+}
+
+static void hex_string_to_bytes(const char *hexString, uint8_t *out,
+ size_t len) {
+ for (size_t count = 0; count < len; count++) {
+ sscanf(hexString, "%2hhx", &out[count]); // NOLINT(cert-err34-c)
+ hexString += 2;
+ }
+}
+
+static void bytes_to_hex_string(uint8_t *data, char *out, size_t len) {
+ std::stringstream ss;
+ ss << std::hex;
+ for (size_t i = 0; i < len; ++i)
+ ss << std::setw(2) << std::setfill('0') << (int)data[i];
+
+ std::string result = ss.str();
+ transform(result.begin(), result.end(), result.begin(), ::toupper);
+ strcpy(out, result.c_str());
+}
+
+// Run through JSON data with test cases generated by Rust tests.
+// Using generated data for now because the C layer does not have the ability
+// to generate the ldt_key and hmac_key from a key_seed, this is an
+// implementation detail of the rust ldt library
+TEST(LdtFfiTests, TestJsonData) {
+ Json::Value root;
+ Json::Reader reader;
+ std::ifstream test(PATH_TO_DATA_FILE);
+ bool parsingSuccessful = reader.parse(test, root, false);
+ if (!parsingSuccessful) {
+ std::cout << reader.getFormattedErrorMessages() << "\n";
+ }
+ ASSERT_TRUE(root.size() == 1000);
+
+ for (const auto &v : root) {
+ auto key_seed = v["key_seed"].asCString();
+ auto metadata_key_hmac = v["metadata_key_hmac"].asCString();
+ auto adv_salt = v["adv_salt"].asCString();
+ auto plaintext = v["plaintext"].asCString();
+ auto ciphertext = v["ciphertext"].asCString();
+
+ NpLdtKeySeed np_key_seed;
+ auto len = strlen(key_seed) / 2;
+ hex_string_to_bytes(key_seed, np_key_seed.bytes, len);
+ ASSERT_EQ(len, 32);
+
+ NpMetadataKeyHmac known_hmac;
+ len = strlen(metadata_key_hmac) / 2;
+ hex_string_to_bytes(metadata_key_hmac, known_hmac.bytes, len);
+ ASSERT_EQ(len, 32);
+
+ NpLdtEncryptHandle enc_handle = NpLdtEncryptCreate(np_key_seed);
+ ASSERT_TRUE(enc_handle.handle != 0);
+
+ NpLdtSalt salt_data;
+ len = strlen(adv_salt) / 2;
+ hex_string_to_bytes(adv_salt, salt_data.bytes, len);
+ ASSERT_TRUE(len == 2);
+
+ len = strlen(plaintext) / 2;
+ auto buffer = (uint8_t *)malloc(len);
+ hex_string_to_bytes(plaintext, buffer, len);
+ NP_LDT_RESULT result = NpLdtEncrypt(enc_handle, buffer, len, salt_data);
+ ASSERT_EQ(result, NP_LDT_SUCCESS);
+
+ char *output = (char *)malloc(strlen(plaintext) + 1);
+ bytes_to_hex_string(buffer, output, len);
+ ASSERT_EQ(strcmp(output, ciphertext), 0);
+
+ NpLdtDecryptHandle dec_handle = NpLdtDecryptCreate(np_key_seed, known_hmac);
+ ASSERT_TRUE(dec_handle.handle != 0);
+
+ result = NpLdtDecryptAndVerify(dec_handle, buffer, len, salt_data);
+ ASSERT_EQ(result, NP_LDT_SUCCESS);
+
+ result = NpLdtEncryptClose(enc_handle);
+ ASSERT_EQ(result, NP_LDT_SUCCESS);
+
+ result = NpLdtDecryptClose(dec_handle);
+ ASSERT_EQ(result, NP_LDT_SUCCESS);
+
+ bytes_to_hex_string(buffer, output, len);
+ ASSERT_EQ(strcmp(output, plaintext), 0);
+ free(buffer);
+ free(output);
+ }
+ test.close();
+}
+
+TEST(LdtFfiTests, TestValidLength) {
+ auto plaintext = (uint8_t *)malloc(20 * sizeof(uint8_t));
+ memcpy(plaintext, TEST_DATA_BYTES, 20);
+
+ NpLdtEncryptHandle enc_handle = create_enc_handle_from_test_key();
+ ASSERT_TRUE(enc_handle.handle != 0);
+
+ NP_LDT_RESULT result = NpLdtEncrypt(enc_handle, plaintext, 20, salt);
+ ASSERT_EQ(result, NP_LDT_SUCCESS);
+
+ NpLdtDecryptHandle dec_handle = create_dec_handle_from_test_key();
+
+ result = NpLdtDecryptAndVerify(dec_handle, plaintext, 20, salt);
+ ASSERT_EQ(result, NP_LDT_SUCCESS);
+ free(plaintext);
+}
+
+TEST(LdtFfiTests, TestEncryptInvalidLength) {
+ auto plaintext = (uint8_t *)malloc(32 * sizeof(uint8_t));
+ memcpy(plaintext, TEST_DATA_BYTES, 20);
+
+ NpLdtEncryptHandle enc_handle = create_enc_handle_from_test_key();
+ ASSERT_TRUE(enc_handle.handle != 0);
+
+ NP_LDT_RESULT result = NpLdtEncrypt(enc_handle, plaintext, 32, salt);
+ ASSERT_EQ(result, NP_LDT_ERROR_INVALID_LENGTH);
+
+ result = NpLdtEncrypt(enc_handle, plaintext, 15, salt);
+ ASSERT_EQ(result, NP_LDT_ERROR_INVALID_LENGTH);
+ free(plaintext);
+}
+
+TEST(LdtFfiTests, TestDecryptInvalidLength) {
+ auto plaintext = (uint8_t *)malloc(32 * sizeof(uint8_t));
+ memcpy(plaintext, TEST_DATA_BYTES, 20);
+
+ NpLdtDecryptHandle dec_handle = create_dec_handle_from_test_key();
+ ASSERT_TRUE(dec_handle.handle != 0);
+
+ NP_LDT_RESULT result = NpLdtDecryptAndVerify(dec_handle, plaintext, 32, salt);
+ ASSERT_EQ(result, NP_LDT_ERROR_INVALID_LENGTH);
+
+ result = NpLdtDecryptAndVerify(dec_handle, plaintext, 15, salt);
+ ASSERT_EQ(result, NP_LDT_ERROR_INVALID_LENGTH);
+ free(plaintext);
+}
+
+// We want to make sure no decryption is performed when the hmac is invalid
+TEST(LdtFfiTests, TestDecryptMacMismatch) {
+ char test_text[] = "this text should not change!";
+ auto plaintext = (uint8_t *)malloc(30 * sizeof(char));
+ memcpy(plaintext, test_text, 29);
+
+ NpLdtDecryptHandle dec_handle = create_dec_handle_from_test_key();
+ ASSERT_TRUE(dec_handle.handle != 0);
+
+ NP_LDT_RESULT result = NpLdtDecryptAndVerify(dec_handle, plaintext, 24, salt);
+ ASSERT_EQ(result, NP_LDT_ERROR_MAC_MISMATCH);
+
+ ASSERT_EQ(strcmp((char *)plaintext, test_text), 0);
+ free(plaintext);
+}
+
+TEST(LdtFfiTests, TestInvalidHandle) {
+ auto plaintext = (uint8_t *)malloc(20 * sizeof(uint8_t));
+ memcpy(plaintext, TEST_DATA_BYTES, 20);
+
+ NP_LDT_RESULT result =
+ NpLdtEncrypt(NpLdtEncryptHandle{1234}, plaintext, 20, salt);
+ ASSERT_EQ(result, NP_LDT_INVALID_HANDLE);
+
+ result = NpLdtDecryptAndVerify(NpLdtDecryptHandle{1234}, plaintext, 20, salt);
+ ASSERT_EQ(result, NP_LDT_INVALID_HANDLE);
+ free(plaintext);
+
+ result = NpLdtEncryptClose(NpLdtEncryptHandle{1234});
+ ASSERT_EQ(result, NP_LDT_INVALID_HANDLE);
+
+ result = NpLdtDecryptClose(NpLdtDecryptHandle{1234});
+ ASSERT_EQ(result, NP_LDT_INVALID_HANDLE);
+}
+
+#ifndef _WIN32
+pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+
+void *worker_thread(void *arg) {
+ (void)arg;
+ pthread_mutex_lock(&my_mutex);
+
+ pthread_cond_wait(&cond, &my_mutex);
+ pthread_mutex_unlock(&my_mutex);
+
+ auto plaintext = (uint8_t *)malloc(20 * sizeof(uint8_t));
+ memcpy(plaintext, TEST_DATA_BYTES, 20);
+
+ NpLdtEncryptHandle enc_handle = create_enc_handle_from_test_key();
+ if (enc_handle.handle == 0) {
+ printf("Error creating handle in thread!");
+ free(plaintext);
+ exit(2);
+ }
+
+ NP_LDT_RESULT result = NpLdtEncrypt(enc_handle, plaintext, 20, salt);
+ if (result != NP_LDT_SUCCESS) {
+ printf("Error in encrypt in thread!");
+ free(plaintext);
+ exit(2);
+ }
+
+ NpLdtDecryptHandle dec_handle = create_dec_handle_from_test_key();
+ if (dec_handle.handle == 0) {
+ printf("Error creating handle in thread!");
+ free(plaintext);
+ exit(2);
+ }
+ result = NpLdtDecryptAndVerify(dec_handle, plaintext, 20, salt);
+ if (result != NP_LDT_SUCCESS) {
+ printf("Error in decrypt in thread!");
+ free(plaintext);
+ exit(2);
+ }
+
+ free(plaintext);
+ pthread_exit(nullptr);
+}
+
+TEST(LdtFfiTests, MultiThreadedTests) {
+ int i, num_threads = 100;
+ pthread_t tid[num_threads];
+ memset(tid, 0, num_threads * sizeof(pthread_t));
+
+ // Create the threads
+ for (i = 0; i < num_threads; i++)
+ ASSERT_EQ(pthread_create(&tid[i], nullptr, worker_thread, (void *)&tid[i]),
+ 0);
+
+ // give time for all threads to lock
+ sleep(1);
+
+ // unleash the threads!
+ pthread_cond_broadcast(&cond);
+
+ // Wait for them all to finish and check the status
+ for (i = 0; i < num_threads; i++)
+ ASSERT_EQ(pthread_join(tid[i], nullptr), 0);
+}
+#endif