This is a repository for the C and C++ APIs of SST (Secure Swarm Toolkit) as a submodule.
- The C API (
src/) is the reference implementation of the SST entity protocol. - The C++ API (
cpp/) is a port of the C API to modern C++ (RAII, exceptions, caller-provided crypto buffers). It speaks the same wire protocol, so C and C++ entities interoperate with each other and with Auth. See C++ API below.
- OpenSSL 3.0 or later, including development headers and libraries.
On macOS with Homebrew, install
openssl@3and, if CMake cannot find it, setexport OPENSSL_ROOT_DIR="$(brew --prefix openssl@3)"before configuring. - A POSIX environment (Linux or macOS) and a C compiler.
- CMake 3.19 or later.
- For the C++ API, a C++17 compiler (clang or gcc) and spdlog; see the C++ requirements for dependency setup.
entity/c/
├── src/ # C API (c_api.h is the public header)
├── cpp/ # C++ API, its examples and tests (see cpp/README.md)
├── examples/ # C API examples, including some callers written in C++
├── tests/ # C unit and integration tests
├── embedded/ # C API for embedded targets
├── cmake/ # CMake package config for the installed library
└── .github/ # CI workflows for the C (ci.yml) and C++ (ci-cpp.yml) APIs
c_common -> c_crypto -> c_secure_comm -> c_api -> entity_client, entity_server
load_config --↑
ipfs.h builds on c_api.h and adds the file sharing helpers used by the IPFS examples.
The public header is src/c_api.h. See the website C Guide and C API Reference for configuration and usage. Unless noted otherwise, functions that return a pointer return NULL on failure, and functions that return int return 0 on success and -1 on failure.
SST_ctx_t *init_SST(const char *config_path)
- Loads the config file, the entity's private key and Auth's public key (or the permanent distribution key when
PermanentDistKeyMode=on). - Returns the
SST_ctx_tused by all other functions.
session_key_list_t *init_empty_session_key_list(void)
- Allocates an empty session key list with room for
MAX_SESSION_KEYkeys.
session_key_list_t *get_session_key(SST_ctx_t *ctx, session_key_list_t *existing_s_key_list)
- Requests
entityInfo.number_keysession keys from Auth for the configured purpose. - When
existing_s_key_listisNULL, returns a new list. Otherwise appends the received keys to the existing list and returns it. If the list cannot accommodate the requested keys after discarding expired oldest entries, returns the existing list without contacting Auth.
session_key_list_t *get_session_key_with_index(SST_ctx_t *ctx, int purpose_index, session_key_list_t *existing_s_key_list)
- Same as
get_session_key()but uses the purpose atpurpose_index(0 or 1, for an entry present in the config). Without an explicit index, the C API uses the lastentityInfo.purposeentry.
session_key_t *get_session_key_by_ID(unsigned char *target_session_key_id, SST_ctx_t *ctx, session_key_list_t *existing_s_key_list)
- Returns the session key with the given 8-byte ID. If it is not in
existing_s_key_list, requests it from Auth by ID and adds it to the list. - Used by entity servers to obtain the key a client presents in its handshake.
- Requires an initialized, non-
NULLlist. The returned pointer refers to an entry owned by that list; do not free it separately or retain it across operations that overwrite or free the list.
The C API does not internally serialize requests on a shared SST_ctx_t. Protect concurrent requests and shared key-list access with an application mutex. The C++ SST_API serializes Auth requests internally.
SST_session_ctx_t *secure_connect_to_server(session_key_t *s_key, SST_ctx_t *ctx)
- Connects to the entity server from the config and runs the session key handshake as the client.
SST_session_ctx_t *secure_connect_to_server_with_socket(session_key_t *s_key, int sock)
- Runs the client side of the handshake over a socket the caller already connected with
connect(). - The caller remains responsible for closing the supplied socket, including when the handshake fails.
SST_session_ctx_t *server_secure_comm_setup(SST_ctx_t *ctx, int clnt_sock, session_key_list_t *existing_s_key_list)
- Runs the server side of the handshake on an accepted client socket. The session key is looked up in
existing_s_key_listor fetched from Auth by ID. - The caller remains responsible for closing
clnt_sock, including when the handshake fails.
int send_secure_message(char *msg, unsigned int msg_length, SST_session_ctx_t *session_ctx)
- Encrypts
msgwith the session key and sends it as aSECURE_COMM_MSG.msg_lengthmust not exceedMAX_PAYLOAD_LENGTH.
int read_secure_message(unsigned char *plaintext, SST_session_ctx_t *session_ctx)
- Reads one
SECURE_COMM_MSGfrom the session's socket, verifies and decrypts it, and copies the plaintext into the caller's buffer, which must holdMAX_SECURE_COMM_MSG_LENGTHbytes. - Returns the plaintext length, 0 for either an empty plaintext or peer closure, or -1 on failure.
void *receive_thread_read_one_each(void *session_ctx)
- Thread body that calls
read_secure_message()in a loop and logs the received messages. Usage:
pthread_t thread;
pthread_create(&thread, NULL, &receive_thread_read_one_each, (void *)session_ctx);
int encrypt_buf_with_session_key(session_key_t *s_key, unsigned char *plaintext, unsigned int plaintext_length, unsigned char **encrypted, unsigned int *encrypted_length) int decrypt_buf_with_session_key(session_key_t *s_key, unsigned char *encrypted, unsigned int encrypted_length, unsigned char **decrypted, unsigned int *decrypted_length)
- Encrypt or decrypt a buffer using the session key's cipher settings, adding or verifying an HMAC when enabled for that key.
- These allocate the result buffer, which the caller must
free().
int encrypt_buf_with_session_key_without_malloc(...) int decrypt_buf_with_session_key_without_malloc(...)
- Same as above but write into a caller-provided buffer. Size it with
get_expected_encrypted_total_length()/get_expected_decrypted_maximum_length()fromc_crypto.h.
int save_session_key_list(session_key_list_t *session_key_list, const char *file_path) int load_session_key_list(session_key_list_t *session_key_list, const char *file_path)
- Save or load a session key list to or from a file. Before loading, use
init_empty_session_key_list()to provide the destination list.
int save_session_key_list_with_password(session_key_list_t *session_key_list, const char *file_path, const char *password, unsigned int password_len, const char *salt, unsigned int salt_len) int load_session_key_list_with_password(...)
- Same, but the file is additionally encrypted with a key derived from the password and salt.
unsigned int convert_skid_buf_to_int(unsigned char *buf, int byte_length)
- Converts a big-endian buffer to an
unsigned int. For buffers wider than that type, only the low-order bytes are retained; this is not a full 64-bit session key ID conversion.
int generate_random_nonce(int length, unsigned char *buf)
- Fills
bufwithlengthcryptographically secure random bytes.
int secure_rand(int min, int max)
- Returns a cryptographically secure random integer in
[min, max], or -1 on failure.
void SST_print_debug / SST_print_log / SST_print_error / SST_print_error_exit(const char *fmt, ...)
- printf-style logging helpers.
SST_print_debug()only prints when built with-DCMAKE_BUILD_TYPE=Debug.SST_print_error_exit()prints the error and exits the process.
void free_session_key_list_t(session_key_list_t *session_key_list) void free_session_ctx(SST_session_ctx_t *session_ctx) void free_SST_ctx_t(SST_ctx_t *ctx)
- Free the memory owned by a session key list, a session context, or the SST context (including the loaded keys).
free_session_ctx()does not close the socket.
For the rest of this document, set $SST_ROOT to the absolute path of SST's main repository, with this submodule at entity/c/.
cd "$SST_ROOT/entity/c"
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build
ctest --test-dir build --output-on-failureThis runs the three standalone C tests without Auth or IPFS. Debug builds enable SST_print_debug() and retain the assertions in the C crypto test. CI also runs the unit tests in Release mode. See tests/README.md for the separate Auth integration tests.
The current CMake target is a static library. The commands below install libsst-c-api.a under /usr/local/lib/ and c_api.h as /usr/local/include/sst-c-api/c_api.h. The install rules currently copy only the public header; lower-level headers such as c_crypto.h remain in src/. The repository examples build directly against the source tree. Run from entity/c/:
cmake -S . -B build
cmake --build build
sudo cmake --install build
- C examples: see the
examples/directory (server/client, file block encryption, IPFS file sharing). - C tests: see
tests/.
The C++ API lives in cpp/ and is documented in cpp/README.md. It is organized in four layers:
| Layer | Location | Purpose |
|---|---|---|
| Crypto | cpp/src/crypto.hpp/cpp |
Stateless primitives (sst::Crypto): RSA, AES, SHA-256, HMAC, with caller-provided output buffers |
| Network | cpp/src/net/sockets.hpp/cpp |
RAII POSIX socket wrappers |
| API | cpp/src/api.hpp, cpp/src/ipfs.hpp |
Public interfaces; implementations are split across configuration, Auth requests, handshakes, sessions, session keys and IPFS helpers |
| Logging | cpp/src/log/log_manager.hpp/cpp |
spdlog-based logger |
The C concepts map to C++ classes as follows. Setup operations (construction, key requests, handshakes) throw sst::SST_Exception on failure; message and buffer operations return status codes. C sends return 0 on success; C++ sends return the number of framed bytes written. Both return -1 on failure.
| C API | C++ API |
|---|---|
SST_ctx_t, init_SST() |
sst::SST_API (constructor loads the config and keys) |
get_session_key(), get_session_key_with_index(), get_session_key_by_ID() |
SST_API::get_session_key(), get_session_key_with_index(), get_session_key_by_ID() |
secure_connect_to_server(), server_secure_comm_setup() |
SST_API::secure_connect_to_server(), server_secure_comm_setup() |
session_key_list_t |
sst::SessionKeyList |
SST_session_ctx_t, send_secure_message(), read_secure_message() |
sst::SST_Session (owns the socket) with send_secure_message(), read_secure_message() |
ipfs.h |
sst::ipfs in cpp/src/ipfs.hpp |
Both APIs accept the C properties format and resolve relative credential paths from the process working directory. Follow the example-specific working directories below. C++ sessions close their socket automatically; C callers must close the socket before freeing the session context.
C++ documentation:
- C++ Guide and C++ API Reference.
cpp/README.md: design, layout, build and test instructions, full C-to-C++ mapping.cpp/examples/server_client_example/README.md: secure server/client example and session keys by ID.cpp/examples/ipfs_examples/README.md: IPFS file sharing with the plain and secure file system managers.cpp/README.md#build-and-run-the-tests: current C++ unit-test commands. Use the server/client example above for an end-to-end Auth handshake.
To build the C++ library and run its unit tests:
cd "$SST_ROOT/entity/c/cpp"
cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failureThis runs six standalone C++ tests. They use local sockets and test doubles; no running Auth or IPFS daemon is needed.
-
For C and C++ indentation, we use the Google style.
- To enable the Google style indentation in VSCode, follow the instructions below. (Source)
- Go to Preferences -> Settings
- Search for
C_Cpp.clang_format_fallbackStyle - Click Edit, Copy to Settings
- Change from
"Visual Studio"to"{ BasedOnStyle: Google, IndentWidth: 4 }"
- To format the code, follow the instructions on this page.
- To enable the Google style indentation in VSCode, follow the instructions below. (Source)
-
To format all C/C++ source files in the repository using the project's clang-format style, run:
make format -
To check formatting without modifying files (exits with an error if any file is not properly formatted), run:
make format-checkBoth commands operate on all
.c,.h,.cpp,.hpp,.cc, and.hhfiles, excluding thebuild/directory andembedded/lib/. -
CI:
.github/workflows/ci.ymlruns the C unit and integration tests, and.github/workflows/ci-cpp.ymlruns the C++ unit tests and C++ examples. Both cover Auth-backed server/client and IPFS communication; their block-encryption examples exercise different workflows.- Both unit-test jobs explicitly build in Release mode, which compiles
assert()out. New test checks must use an always-on check (see theCHECKmacros in the regression tests). The example integration builds do not currently setCMAKE_BUILD_TYPE. - On pushes and pull requests to this repository, both jobs use the commit under test, and
ci.ymlalso runs the entity integration tests of iotauth against it through theirsst-c-api-refinput. - The iotauth repository calls both workflows from its
sst-c-api-tests.ymlandsst-c-api-cpp-tests.ymlwith aniotauth-refinput. In that case the unit test jobs check out this repository'smain, while the integration test jobs check out iotauth atiotauth-refwith its submodules, so they use the commit of this repository pinned by iotauth'sentity/csubmodule.
- Both unit-test jobs explicitly build in Release mode, which compiles
Last updated on October 30, 2026