Skip to content
iotauthPublic

About

A repository for SST API in C and C++ languages and examples

Resources

Stars

17 stars

Watchers

3 watching

Forks

Repository files navigation

Overview


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.

Prerequisites

  • OpenSSL 3.0 or later, including development headers and libraries. On macOS with Homebrew, install openssl@3 and, if CMake cannot find it, set export 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.

Repository Layout

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 API

Code Hierarchy

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.

Functions

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.

Context and session keys

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_t used 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_KEY keys.

session_key_list_t *get_session_key(SST_ctx_t *ctx, session_key_list_t *existing_s_key_list)

  • Requests entityInfo.number_key session keys from Auth for the configured purpose.
  • When existing_s_key_list is NULL, 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 at purpose_index (0 or 1, for an entry present in the config). Without an explicit index, the C API uses the last entityInfo.purpose entry.

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-NULL list. 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.

Secure sessions

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_list or 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 msg with the session key and sends it as a SECURE_COMM_MSG. msg_length must not exceed MAX_PAYLOAD_LENGTH.

int read_secure_message(unsigned char *plaintext, SST_session_ctx_t *session_ctx)

  • Reads one SECURE_COMM_MSG from the session's socket, verifies and decrypts it, and copies the plaintext into the caller's buffer, which must hold MAX_SECURE_COMM_MSG_LENGTH bytes.
  • 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);

Encryption with a session key

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() from c_crypto.h.

Saving and loading session keys

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.

Utilities

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 buf with length cryptographically 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.

Freeing

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.

Compile

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-failure

This 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.

Install the Static Library

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

Examples and Tests

  • C examples: see the examples/ directory (server/client, file block encryption, IPFS file sharing).
  • C tests: see tests/.

C++ API

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:

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-failure

This runs six standalone C++ tests. They use local sockets and test doubles; no running Auth or IPFS daemon is needed.

For Developers

  • For C and C++ indentation, we use the Google style.

    • To enable the Google style indentation in VSCode, follow the instructions below. (Source)
      1. Go to Preferences -> Settings
      2. Search for C_Cpp.clang_format_fallbackStyle
      3. Click Edit, Copy to Settings
      4. Change from "Visual Studio" to "{ BasedOnStyle: Google, IndentWidth: 4 }"
    • To format the code, follow the instructions on this page.
  • 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-check
    

    Both commands operate on all .c, .h, .cpp, .hpp, .cc, and .hh files, excluding the build/ directory and embedded/lib/.

  • CI: .github/workflows/ci.yml runs the C unit and integration tests, and .github/workflows/ci-cpp.yml runs 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 the CHECK macros in the regression tests). The example integration builds do not currently set CMAKE_BUILD_TYPE.
    • On pushes and pull requests to this repository, both jobs use the commit under test, and ci.yml also runs the entity integration tests of iotauth against it through their sst-c-api-ref input.
    • The iotauth repository calls both workflows from its sst-c-api-tests.yml and sst-c-api-cpp-tests.yml with an iotauth-ref input. In that case the unit test jobs check out this repository's main, while the integration test jobs check out iotauth at iotauth-ref with its submodules, so they use the commit of this repository pinned by iotauth's entity/c submodule.

Last updated on October 30, 2026

About

A repository for SST API in C and C++ languages and examples

Resources

Stars

17 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages