mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-30 17:44:07 +00:00
Location Sharing Library
Overview
Core C++ library for live GPS location sharing with zero-knowledge end-to-end encryption in Organic Maps.
Features
- AES-256-GCM Encryption: Industry-standard authenticated encryption
- Zero-knowledge architecture: Server never sees encryption keys
- Cross-platform: Linux/Android (OpenSSL), iOS/macOS (CommonCrypto), Windows (BCrypt)
- Automatic session management: UUID generation, key derivation, URL encoding
- Update scheduling: Configurable intervals with automatic throttling
- Battery protection: Auto-stop below threshold
- Dual modes: Standalone GPS or navigation with ETA/distance
Components
1. Types (location_sharing_types.hpp/cpp)
SessionCredentials:
SessionCredentials creds = SessionCredentials::Generate();
std::string shareUrl = creds.GenerateShareUrl("https://server.com");
LocationPayload:
LocationPayload payload(gpsInfo);
payload.mode = SharingMode::Navigation;
payload.eta = timestamp + timeToArrival;
std::string json = payload.ToJson();
EncryptedPayload:
EncryptedPayload encrypted;
encrypted.iv = "..."; // 12 bytes base64
encrypted.ciphertext = "...";
encrypted.authTag = "..."; // 16 bytes base64
std::string json = encrypted.ToJson();
2. Encryption (crypto_util.hpp/cpp)
Encrypt:
std::string key = "base64-encoded-32-byte-key";
std::string plaintext = "{...}";
auto encrypted = crypto::EncryptAes256Gcm(key, plaintext);
if (encrypted.has_value()) {
std::string json = encrypted->ToJson();
// Send to server
}
Decrypt:
auto decrypted = crypto::DecryptAes256Gcm(key, encryptedPayload);
if (decrypted.has_value()) {
// Process plaintext
}
Platform implementations:
- OpenSSL (Android/Linux):
EVP_aes_256_gcm()withEVP_CIPHER_CTX - CommonCrypto (iOS/macOS): TODO - currently placeholder, needs Security framework
- BCrypt (Windows): TODO - currently placeholder
3. Session Management (location_sharing_session.hpp/cpp)
Basic usage:
LocationSharingSession session;
// Set callbacks
session.SetPayloadReadyCallback([](EncryptedPayload const & payload) {
// Send to server
PostToServer(payload.ToJson());
});
// Start session
SessionConfig config;
config.updateIntervalSeconds = 20;
SessionCredentials creds = session.Start(config);
std::string shareUrl = creds.GenerateShareUrl("https://server.com");
// Update location
session.UpdateLocation(gpsInfo);
// Update navigation (optional)
session.UpdateNavigationInfo(eta, distance, "Destination Name");
// Update battery
session.UpdateBatteryLevel(85);
// Stop session
session.Stop();
State machine:
Inactive→Starting→Active→Stopping→InactiveErrorstate on failures
Callbacks:
session.SetStateChangeCallback([](SessionState state) {
LOG(LINFO, ("State:", static_cast<int>(state)));
});
session.SetErrorCallback([](std::string const & error) {
LOG(LERROR, ("Error:", error));
});
Building
CMake
add_subdirectory(libs/location_sharing)
target_link_libraries(your_target
PRIVATE
location_sharing
)
Dependencies
Linux/Android:
sudo apt-get install libssl-dev
iOS/macOS:
- Security framework (automatic)
Windows:
- BCrypt (automatic)
Android NDK
OpenSSL is typically bundled or available via:
android {
externalNativeBuild {
cmake {
arguments "-DOPENSSL_ROOT_DIR=/path/to/openssl"
}
}
}
Security
Encryption Details
- Algorithm: AES-256-GCM (Galois/Counter Mode)
- Key size: 256 bits (32 bytes)
- IV size: 96 bits (12 bytes) - recommended for GCM
- Auth tag size: 128 bits (16 bytes)
- Key generation:
SecRandomCopyBytes(iOS) orstd::random_devicefallback
URL Format
https://server.com/live/{base64url(sessionId:encryptionKey)}
Example:
https://live.organicmaps.app/live/YWJjZDEyMzQtNTY3OC05MGFiLWNkZWYtMTIzNDU2Nzg5MGFiOmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MTIzNDU2Nzg
Decoded:
abcd1234-5678-90ab-cdef-1234567890ab:abcdefghijklmnopqrstuvwxyz12345678
^
separator
Zero-Knowledge Architecture
- Client generates session ID (UUID) + 256-bit key
- Client encrypts location with key
- Server stores encrypted blob (no key access)
- Share URL contains both session ID and key
- Viewer decrypts in-browser using key from URL
Server NEVER sees:
- Encryption key
- Plaintext location data
- User identity (session ID is random UUID)
Threat Model
Protected against:
- Server compromise (data is encrypted)
- Man-in-the-middle (TLS + authenticated encryption)
- Replay attacks (timestamp in payload)
- Tampering (GCM authentication tag)
NOT protected against:
- URL interception (anyone with URL can decrypt)
- Client compromise (key is in memory)
- Quantum computers (AES-256 is quantum-resistant)
Testing
Unit Tests
// Test encryption round-trip
TEST(CryptoUtil, EncryptDecrypt) {
std::string key = GenerateRandomKey();
std::string plaintext = "test data";
auto encrypted = crypto::EncryptAes256Gcm(key, plaintext);
ASSERT_TRUE(encrypted.has_value());
auto decrypted = crypto::DecryptAes256Gcm(key, *encrypted);
ASSERT_TRUE(decrypted.has_value());
EXPECT_EQ(plaintext, *decrypted);
}
// Test auth tag validation
TEST(CryptoUtil, AuthTagValidation) {
auto encrypted = crypto::EncryptAes256Gcm(key, plaintext);
encrypted->authTag[0] ^= 0xFF; // Corrupt tag
auto decrypted = crypto::DecryptAes256Gcm(key, *encrypted);
EXPECT_FALSE(decrypted.has_value()); // Should fail
}
Integration Tests
See docs/LOCATION_SHARING_INTEGRATION.md for full testing guide.
Performance
Benchmarks (approximate)
- Encryption: ~1-5 ms for 200-byte payload (hardware-dependent)
- Memory: ~100 bytes per session
- Network: ~300-400 bytes per update (encrypted + JSON overhead)
Optimization Tips
- Reuse sessions: Don't create new session per update
- Batch updates: If sending multiple locations, consider batching
- Adjust intervals: Increase
updateIntervalSecondsfor better battery life
Troubleshooting
OpenSSL linking errors (Android/Linux)
undefined reference to `EVP_EncryptInit_ex`
Solution:
find_package(OpenSSL REQUIRED)
target_link_libraries(location_sharing PRIVATE OpenSSL::SSL OpenSSL::Crypto)
CommonCrypto not found (iOS)
Solution:
find_library(SECURITY_FRAMEWORK Security)
target_link_libraries(location_sharing PRIVATE ${SECURITY_FRAMEWORK})
Encryption fails at runtime
Check:
- Key is exactly 32 bytes (base64-decoded)
- IV is 12 bytes
- Auth tag is 16 bytes
- Platform crypto library is available
Debug logging:
#define LOG_CRYPTO_ERRORS
API Reference
See header files for full API documentation:
location_sharing_types.hpp: Data structurescrypto_util.hpp: Encryption functionslocation_sharing_session.hpp: Session management
Contributing
When adding features:
- Maintain zero-knowledge architecture
- Add unit tests for crypto changes
- Update documentation
- Test on all platforms (Android, iOS, Linux)
License
Same as Organic Maps (Apache 2.0)