diff --git a/src/mesh/CryptoEngine.h b/src/mesh/CryptoEngine.h index e33a9880b..f0a214e5a 100644 --- a/src/mesh/CryptoEngine.h +++ b/src/mesh/CryptoEngine.h @@ -109,6 +109,9 @@ class CryptoEngine * Set cryptographic (hashed) shared_key calculated from the given pubkey */ bool setCryptoSharedSecret(meshtastic_UserLite_public_key_t pubkey); + + // Allow unit test harness to peer into private/protected members + friend struct TestCryptoEngine; }; extern CryptoEngine *crypto; \ No newline at end of file diff --git a/test/test_crypto/test_main.cpp b/test/test_crypto/test_main.cpp index 36dc37b9d..930887145 100644 --- a/test/test_crypto/test_main.cpp +++ b/test/test_crypto/test_main.cpp @@ -4,6 +4,18 @@ #include "TestUtil.h" #include +struct TestCryptoEngine { + static bool getCachedSecret(uint32_t lookupKey, CachedSharedSecret &entry) + { + auto iter = crypto->sharedSecretCache.find(lookupKey); + if (iter == crypto->sharedSecretCache.end()) { + return false; + } + entry = iter->second; + return true; + } +}; + void HexToBytes(uint8_t *result, const std::string hex, size_t len = 0) { if (len) { @@ -108,6 +120,33 @@ void test_DH25519(void) TEST_ASSERT(crypto->setDHPublicKey(public_key)); crypto->hash(crypto->shared_key, 32); TEST_ASSERT_EQUAL_MEMORY(expected_shared, crypto->shared_key, 32); + + // Caching code path generates the same secret + uint8_t now = (millis() >> 22) & 0xff; + meshtastic_UserLite_public_key_t userlite_public_key; + memcpy(userlite_public_key.bytes, public_key, 32); + TEST_ASSERT(crypto->setCryptoSharedSecret(userlite_public_key)); + TEST_ASSERT_EQUAL_MEMORY(expected_shared, crypto->shared_key, 32); + + // Check it was added to the cache + CachedSharedSecret entry; + uint32_t lookupKey; + memcpy(&lookupKey, public_key, sizeof(lookupKey)); + TEST_ASSERT(TestCryptoEngine::getCachedSecret(lookupKey, entry)); + TEST_ASSERT_EQUAL_MEMORY(expected_shared, entry.shared_secret, 32); + TEST_ASSERT_TRUE(entry.last_used >= now); + + // Calling again should fetch from the cache. Shared secret is the same. + // FIXME If tests could mock the millis() time, it would be ideal to mock the time forward by a + // couple hours before hitting the cache. + TEST_ASSERT(crypto->setCryptoSharedSecret(userlite_public_key)); + TEST_ASSERT_EQUAL_MEMORY(expected_shared, crypto->shared_key, 32); + + // Check cache was updated + now = (millis() >> 22) & 0xff; + TEST_ASSERT(TestCryptoEngine::getCachedSecret(lookupKey, entry)); + TEST_ASSERT_EQUAL_MEMORY(expected_shared, entry.shared_secret, 32); + TEST_ASSERT_TRUE(entry.last_used >= now); } void test_PKC(void)