|
Csilk 0.2.1
A lightweight, high-performance C HTTP web framework
|
Core cryptographic and encoding utilities. More...
#include <stdint.h>#include <stdio.h>#include <string.h>#include "context_internal.h"#include "csilk/core/internal.h"#include "csilk/drivers/cipher.h"
Macros | |
| #define | rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) |
| 32-bit rotate-left operation (cyclic bit shift). | |
| #define | ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits)))) |
| #define | ch(x, y, z) (((x) & (y)) ^ (~(x) & (z))) |
| #define | maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) |
| #define | sigma0(x) (ror(x, 2) ^ ror(x, 13) ^ ror(x, 22)) |
| #define | sigma1(x) (ror(x, 6) ^ ror(x, 11) ^ ror(x, 25)) |
| #define | gamma0(x) (ror(x, 7) ^ ror(x, 18) ^ ((x) >> 3)) |
| #define | gamma1(x) (ror(x, 17) ^ ror(x, 19) ^ ((x) >> 10)) |
Functions | |
| static void | sha1_transform (uint32_t state[5], const uint8_t buffer[64]) |
| Internal: process a single 64-byte block through the SHA-1 compression function. | |
| void | csilk_sha1_init (csilk_sha1_ctx *context) |
| Initialize a SHA-1 hashing context with the standard initial hash values. | |
| void | csilk_sha1_update (csilk_sha1_ctx *context, const uint8_t *data, size_t len) |
| Feed data into the SHA-1 hashing context for incremental hashing. | |
| void | csilk_sha1_final (csilk_sha1_ctx *context, uint8_t digest[20]) |
| Finalize the SHA-1 hash and produce the 20-byte digest. | |
| static void | sha256_transform (uint32_t state[8], const uint8_t data[64]) |
| Process a single 64-byte block through the SHA-256 compression function (FIPS 180-4 §6.2.2). | |
| void | csilk_sha256_init (csilk_sha256_ctx *context) |
| Initialize a SHA-256 hashing context with the standard initial hash values. | |
| void | csilk_sha256_update (csilk_sha256_ctx *context, const uint8_t *data, size_t len) |
| Feed data into the SHA-256 hashing context for incremental hashing. | |
| void | csilk_sha256_final (csilk_sha256_ctx *context, uint8_t digest[32]) |
| Finalize the SHA-256 hash and produce the 32-byte digest. | |
| void | csilk_hmac_sha256 (const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, uint8_t out[32]) |
| Compute HMAC-SHA256 as defined in RFC 2104. | |
| void | csilk_base64_encode (const uint8_t *src, size_t len, char *out) |
| Encode raw bytes as a standard Base64 string per RFC 4648. | |
| void | csilk_base64url_encode (const uint8_t *src, size_t len, char *out) |
| Encode raw bytes as a Base64URL string per RFC 4648 §5 (URL-safe). | |
| int | csilk_base64url_decode (const char *src, uint8_t *out) |
| Decode a Base64URL-encoded string back to raw bytes. | |
| void | csilk_generate_uuid (char *buf) |
| Generate a random UUID version 4 string in the standard 8-4-4-4-12 format. | |
| void | _csilk_hmac_sha256 (csilk_ctx_t *c, const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, uint8_t out[32]) |
| Context-aware HMAC-SHA256 — delegates to the crypto driver if available. | |
| void | _csilk_generate_uuid (csilk_ctx_t *c, char buf[37]) |
| Context-aware UUID generation — delegates to the crypto driver if available. | |
| static csilk_cipher_driver_t * | resolve_cipher (csilk_ctx_t *c) |
| int | _csilk_symmetric_encrypt (csilk_ctx_t *c, const uint8_t *key, size_t key_len, const uint8_t *plaintext, size_t plaintext_len, const uint8_t *iv, size_t iv_len, uint8_t *ciphertext, size_t *ciphertext_len, uint8_t *tag, size_t tag_len) |
| Internal: Symmetric encrypt using the context's cipher driver or the built-in OpenSSL AES-256-GCM implementation. | |
| int | _csilk_symmetric_decrypt (csilk_ctx_t *c, const uint8_t *key, size_t key_len, const uint8_t *ciphertext, size_t ciphertext_len, const uint8_t *iv, size_t iv_len, const uint8_t *tag, size_t tag_len, uint8_t *plaintext, size_t *plaintext_len) |
| Internal: Symmetric decrypt using the context's cipher driver or the built-in OpenSSL AES-256-GCM implementation. | |
| int | _csilk_generate_keypair (csilk_ctx_t *c, char *public_key, size_t *pub_len, char *private_key, size_t *priv_len) |
| Internal: Generate an RSA-2048 key pair using the context's cipher driver or the built-in OpenSSL implementation. | |
| int | _csilk_asymmetric_encrypt (csilk_ctx_t *c, const char *public_key, size_t pub_len, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t *ciphertext_len) |
| Internal: Asymmetric encrypt using the context's cipher driver or the built-in OpenSSL RSA-OAEP implementation. | |
| int | _csilk_asymmetric_decrypt (csilk_ctx_t *c, const char *private_key, size_t priv_len, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t *plaintext_len) |
| Internal: Asymmetric decrypt using the context's cipher driver or the built-in OpenSSL RSA-OAEP implementation. | |
| int | _csilk_sign (csilk_ctx_t *c, const char *private_key, size_t priv_len, const uint8_t *data, size_t data_len, uint8_t *signature, size_t *sig_len) |
| Internal: Sign data using the context's cipher driver or the built-in OpenSSL RSA-PSS implementation. | |
| int | _csilk_verify (csilk_ctx_t *c, const char *public_key, size_t pub_len, const uint8_t *data, size_t data_len, const uint8_t *signature, size_t sig_len) |
| Internal: Verify a signature using the context's cipher driver or the built-in OpenSSL RSA-PSS implementation. | |
Variables | |
| static const uint32_t | k256 [] |
| static const char | b64_table [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" |
| Standard Base64 alphabet per RFC 4648 §4. | |
| csilk_cipher_driver_t | csilk_default_cipher_driver |
| Default cipher driver vtable mapping all operations to the OpenSSL-backed implementations above. | |
Core cryptographic and encoding utilities.
Implements low-level building blocks used throughout the csilk framework:
All functions support the internal dispatch pattern: they can be called standalone (using built-in software implementations) or delegating through the context's crypto/cipher driver when one is set.
| #define ch | ( | x, | |
| y, | |||
| z | |||
| ) | (((x) & (y)) ^ (~(x) & (z))) |
| #define maj | ( | x, | |
| y, | |||
| z | |||
| ) | (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) |
| #define rol | ( | value, | |
| bits | |||
| ) | (((value) << (bits)) | ((value) >> (32 - (bits)))) |
32-bit rotate-left operation (cyclic bit shift).
| #define ror | ( | value, | |
| bits | |||
| ) | (((value) >> (bits)) | ((value) << (32 - (bits)))) |
| int _csilk_asymmetric_decrypt | ( | csilk_ctx_t * | c, |
| const char * | private_key, | ||
| size_t | priv_len, | ||
| const uint8_t * | ciphertext, | ||
| size_t | ciphertext_len, | ||
| uint8_t * | plaintext, | ||
| size_t * | plaintext_len | ||
| ) |
Internal: Asymmetric decrypt using the context's cipher driver or the built-in OpenSSL RSA-OAEP implementation.
| c | Request context (for driver lookup, may be NULL). | |
| private_key | PEM-encoded RSA private key. | |
| priv_len | Private key length. | |
| ciphertext | Data to decrypt (typically 256 bytes for RSA-2048). | |
| ciphertext_len | Ciphertext length. | |
| [out] | plaintext | Output buffer. |
| [in,out] | plaintext_len | In: capacity, Out: actual length. |
| int _csilk_asymmetric_encrypt | ( | csilk_ctx_t * | c, |
| const char * | public_key, | ||
| size_t | pub_len, | ||
| const uint8_t * | plaintext, | ||
| size_t | plaintext_len, | ||
| uint8_t * | ciphertext, | ||
| size_t * | ciphertext_len | ||
| ) |
Internal: Asymmetric encrypt using the context's cipher driver or the built-in OpenSSL RSA-OAEP implementation.
| c | Request context (for driver lookup, may be NULL). | |
| public_key | PEM-encoded RSA public key. | |
| pub_len | Public key length. | |
| plaintext | Data to encrypt (max ~190 bytes for RSA-2048). | |
| plaintext_len | Plaintext length. | |
| [out] | ciphertext | 256-byte output buffer. |
| [in,out] | ciphertext_len | In: capacity, Out: actual length. |
| int _csilk_generate_keypair | ( | csilk_ctx_t * | c, |
| char * | public_key, | ||
| size_t * | pub_len, | ||
| char * | private_key, | ||
| size_t * | priv_len | ||
| ) |
Internal: Generate an RSA-2048 key pair using the context's cipher driver or the built-in OpenSSL implementation.
Keys are output as PEM-encoded strings.
| c | Request context (for driver lookup, may be NULL). | |
| [out] | public_key | PEM public key buffer. |
| [in,out] | pub_len | In: capacity, Out: actual PEM length (incl. NUL). |
| [out] | private_key | PEM private key buffer. |
| [in,out] | priv_len | In: capacity, Out: actual PEM length (incl. NUL). |
| void _csilk_generate_uuid | ( | csilk_ctx_t * | c, |
| char | buf[37] | ||
| ) |
Context-aware UUID generation — delegates to the crypto driver if available.
Internal: Generate a random UUID v4 string using the crypto driver (if set) or the built-in /dev/urandom-based implementation.
This is the late-bound UUID generator. If the context has a crypto driver with a cryptographically secure generate_uuid method (e.g., reading from a hardware RNG or via OpenSSL), that is used. Otherwise falls back to the built-in csilk_generate_uuid() which reads /dev/urandom.
The delegation pattern ensures callers always get the best available randomness source without explicit driver management.
| c | Request context (may be NULL — falls back to built-in). |
| buf | [out] 37-byte buffer for the UUID string. |
| void _csilk_hmac_sha256 | ( | csilk_ctx_t * | c, |
| const uint8_t * | key, | ||
| size_t | key_len, | ||
| const uint8_t * | data, | ||
| size_t | data_len, | ||
| uint8_t | out[32] | ||
| ) |
Context-aware HMAC-SHA256 — delegates to the crypto driver if available.
Internal: Compute HMAC-SHA256 using the server's crypto driver (if set) or the built-in software implementation.
This is the "late-bound" version of csilk_hmac_sha256(). It checks whether the request context has a crypto driver installed (e.g., OpenSSL, mbedTLS, or a hardware security module). If so, the driver's accelerated HMAC is used. Otherwise, the built-in software implementation serves as the portable fallback.
This pattern allows the application to use pluggable crypto backends without changing caller code. The default built-in implementation is always available for environments without hardware crypto.
| c | Request context (may be NULL — falls back to built-in). |
| key | HMAC key. |
| key_len | Key length. |
| data | Input data. |
| data_len | Data length. |
| out | [out] 32-byte HMAC output buffer. |
| int _csilk_sign | ( | csilk_ctx_t * | c, |
| const char * | private_key, | ||
| size_t | priv_len, | ||
| const uint8_t * | data, | ||
| size_t | data_len, | ||
| uint8_t * | signature, | ||
| size_t * | sig_len | ||
| ) |
Internal: Sign data using the context's cipher driver or the built-in OpenSSL RSA-PSS implementation.
| c | Request context (for driver lookup, may be NULL). | |
| private_key | PEM-encoded RSA private key. | |
| priv_len | Private key length. | |
| data | Data to sign. | |
| data_len | Data length. | |
| [out] | signature | 256-byte signature buffer. |
| [in,out] | sig_len | In: capacity, Out: actual signature length. |
| int _csilk_symmetric_decrypt | ( | csilk_ctx_t * | c, |
| const uint8_t * | key, | ||
| size_t | key_len, | ||
| const uint8_t * | ciphertext, | ||
| size_t | ciphertext_len, | ||
| const uint8_t * | iv, | ||
| size_t | iv_len, | ||
| const uint8_t * | tag, | ||
| size_t | tag_len, | ||
| uint8_t * | plaintext, | ||
| size_t * | plaintext_len | ||
| ) |
Internal: Symmetric decrypt using the context's cipher driver or the built-in OpenSSL AES-256-GCM implementation.
| c | Request context (for driver lookup, may be NULL). | |
| key | Decryption key (must be 32 bytes for AES-256). | |
| key_len | Key length. | |
| ciphertext | Data to decrypt. | |
| ciphertext_len | Ciphertext length. | |
| iv | 12-byte initialisation vector (nonce). | |
| iv_len | IV length (must be 12 for GCM). | |
| tag | 16-byte authentication tag. | |
| tag_len | Tag length (must be 16). | |
| [out] | plaintext | Output buffer (must be at least ciphertext_len bytes). |
| [in,out] | plaintext_len | In: capacity, Out: actual plaintext length. |
| int _csilk_symmetric_encrypt | ( | csilk_ctx_t * | c, |
| const uint8_t * | key, | ||
| size_t | key_len, | ||
| const uint8_t * | plaintext, | ||
| size_t | plaintext_len, | ||
| const uint8_t * | iv, | ||
| size_t | iv_len, | ||
| uint8_t * | ciphertext, | ||
| size_t * | ciphertext_len, | ||
| uint8_t * | tag, | ||
| size_t | tag_len | ||
| ) |
Internal: Symmetric encrypt using the context's cipher driver or the built-in OpenSSL AES-256-GCM implementation.
| c | Request context (for driver lookup, may be NULL). | |
| key | Encryption key (must be 32 bytes for AES-256). | |
| key_len | Key length. | |
| plaintext | Data to encrypt. | |
| plaintext_len | Plaintext length. | |
| iv | 12-byte initialisation vector (nonce). | |
| iv_len | IV length (must be 12 for GCM). | |
| [out] | ciphertext | Output buffer (must be at least plaintext_len bytes). |
| [in,out] | ciphertext_len | In: capacity, Out: actual ciphertext length. |
| [out] | tag | 16-byte authentication tag buffer. |
| tag_len | Tag buffer size (must be 16). |
| int _csilk_verify | ( | csilk_ctx_t * | c, |
| const char * | public_key, | ||
| size_t | pub_len, | ||
| const uint8_t * | data, | ||
| size_t | data_len, | ||
| const uint8_t * | signature, | ||
| size_t | sig_len | ||
| ) |
Internal: Verify a signature using the context's cipher driver or the built-in OpenSSL RSA-PSS implementation.
| c | Request context (for driver lookup, may be NULL). |
| public_key | PEM-encoded RSA public key. |
| pub_len | Public key length. |
| data | Original signed data. |
| data_len | Data length. |
| signature | Signature to verify. |
| sig_len | Signature length. |
| void csilk_base64_encode | ( | const uint8_t * | src, |
| size_t | len, | ||
| char * | out | ||
| ) |
Encode raw bytes as a standard Base64 string per RFC 4648.
Encode raw bytes as a standard Base64 string.
Processes input in 3-byte groups, producing 4 Base64 characters each. Padding with '=' is added if the input length is not a multiple of 3. The output string is null-terminated.
| src | Input byte buffer. |
| len | Input length in bytes. |
| out | [out] Output buffer (must be large enough: 4 * ceil(len/3) + 1). |
out has sufficient capacity. The worst-case output length is ((len + 2) / 3) * 4 + 1. | int csilk_base64url_decode | ( | const char * | src, |
| uint8_t * | out | ||
| ) |
Decode a Base64URL-encoded string back to raw bytes.
Decode a Base64URL (RFC 4648 §5) string to raw bytes.
The decoding process is the inverse of Base64URL encoding:
The reverse lookup maps each Base64 character (A-Z, a-z, 0-9, +, /) back to its 6-bit value. Characters outside this set (including whitespace) cause an immediate error return (-1). The '=' padding character terminates decoding early.
| src | Base64URL-encoded input string (null-terminated). |
| out | [out] Output buffer for decoded bytes. |
out is large enough (at least strlen(src) * 3 / 4 + 1 bytes). | void csilk_base64url_encode | ( | const uint8_t * | src, |
| size_t | len, | ||
| char * | out | ||
| ) |
Encode raw bytes as a Base64URL string per RFC 4648 §5 (URL-safe).
Encode raw bytes as a Base64URL (RFC 4648 §5) string.
Base64URL is the same as standard Base64 but replaces: '+' → '-' (URL-safe, as '+' is treated as space in URL query strings) '/' → '_' (URL-safe, as '/' has path separator meaning) '=' → '' (omitted — padding is unnecessary because length is inferred)
The output is produced by first encoding with standard Base64, then character-substituting and stripping padding.
| src | Input byte buffer. |
| len | Input length in bytes. |
| out | [out] Output buffer (must be large enough for the padded Base64 result + 1). |
| void csilk_generate_uuid | ( | char * | buf | ) |
Generate a random UUID version 4 string in the standard 8-4-4-4-12 format.
Generate a random UUID v4 string (standalone, no context needed).
UUID v4 (RFC 4122 §4.4) uses random or pseudo-random bytes for all 128 bits, with specific bits reserved for the version and variant:
Field Bits Purpose time_low 32 Random time_mid 16 Random time_hi_ver 16 Version (4 bits) + random (12 bits) clock_seq_hi 8 Variant (2 bits) + random (6 bits) clock_seq_low 8 Random node 48 Random
Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx where '4' indicates RFC 4122 version 4 (random UUID). where 'y' has the top 2 bits set to '10' (RFC 4122 variant).
Reads 16 random bytes from /dev/urandom. If /dev/urandom is unavailable, falls back to rand() (which is NOT cryptographically secure). Sets the UUID version nibble (4) and variant bits (10xx) per RFC 4122.
| buf | [out] 37-byte buffer to receive the UUID string (36 hex chars + 4 hyphens + null terminator). |
| void csilk_hmac_sha256 | ( | const uint8_t * | key, |
| size_t | key_len, | ||
| const uint8_t * | data, | ||
| size_t | data_len, | ||
| uint8_t | out[32] | ||
| ) |
Compute HMAC-SHA256 as defined in RFC 2104.
Compute HMAC-SHA256 (keyed-hash message authentication code).
HMAC (Hash-based Message Authentication Code) provides both data integrity and authenticity via a shared secret. The construction is:
HMAC(K, m) = SHA256((K' XOR opad) || SHA256((K' XOR ipad) || m))
where:
The double-hashing protects against length-extension attacks on the underlying hash function. The ipad/opad XOR ensures that the inner and outer hashes use distinct keys derived from the same secret.
| key | HMAC secret key. |
| key_len | Key length in bytes. |
| data | Input message data. |
| data_len | Message length in bytes. |
| out | [out] 32-byte output buffer for the HMAC digest. |
| void csilk_sha1_final | ( | csilk_sha1_ctx * | context, |
| uint8_t | digest[20] | ||
| ) |
Finalize the SHA-1 hash and produce the 20-byte digest.
Finalise the SHA-1 hash and write the 20-byte digest.
Pads the message according to RFC 3174 (SHA-1 specification), appends the 64-bit message length, and outputs the final hash digest. After this call, the context should not be used without re-initialization.
| context | SHA-1 context with accumulated data. |
| digest | [out] 20-byte buffer to receive the hash digest. |
| void csilk_sha1_init | ( | csilk_sha1_ctx * | context | ) |
Initialize a SHA-1 hashing context with the standard initial hash values.
Initialise a SHA-1 hashing context.
Sets the five state words to the SHA-1 initial constants and resets the bit count to zero. Must be called before the first csilk_sha1_update().
| context | SHA-1 context to initialize (must not be NULL). |
| void csilk_sha1_update | ( | csilk_sha1_ctx * | context, |
| const uint8_t * | data, | ||
| size_t | len | ||
| ) |
Feed data into the SHA-1 hashing context for incremental hashing.
Feed data into the SHA-1 hashing context.
Processes the input data in 64-byte blocks, updating the context's state. Partial blocks are buffered until the next call or csilk_sha1_final().
| context | SHA-1 context (initialized via csilk_sha1_init()). |
| data | Input data buffer. |
| len | Length of input data in bytes. |
| void csilk_sha256_final | ( | csilk_sha256_ctx * | context, |
| uint8_t | digest[32] | ||
| ) |
Finalize the SHA-256 hash and produce the 32-byte digest.
Finalise the SHA-256 hash and write the 32-byte digest.
Pads the message according to FIPS 180-4, appends the 64-bit message length, and outputs the final 256-bit (32-byte) hash digest.
| context | SHA-256 context with accumulated data. |
| digest | [out] 32-byte buffer to receive the hash digest. |
| void csilk_sha256_init | ( | csilk_sha256_ctx * | context | ) |
Initialize a SHA-256 hashing context with the standard initial hash values.
Initialise a SHA-256 hashing context.
Sets the eight state words to the SHA-256 initial constants and resets the bit count to zero.
| context | SHA-256 context to initialize (must not be NULL). |
| void csilk_sha256_update | ( | csilk_sha256_ctx * | context, |
| const uint8_t * | data, | ||
| size_t | len | ||
| ) |
Feed data into the SHA-256 hashing context for incremental hashing.
Feed data into the SHA-256 hashing context.
Processes the input data in 64-byte blocks, updating the context's state. Partial blocks are buffered. Tracks the total bit count for final padding.
| context | SHA-256 context (initialized via csilk_sha256_init()). |
| data | Input data buffer. |
| len | Length of input data in bytes. |
|
static |
|
static |
Internal: process a single 64-byte block through the SHA-1 compression function.
Performs the SHA-1 round computation on a 512-bit message block, updating the 5-word hash state. Implements the standard SHA-1 algorithm with four rounds (20 steps each) using the functions f(), k constants, and message schedule expansion.
| state | [in/out] 5-element hash state array (updated in-place). |
| buffer | 64-byte (512-bit) message block to process. |
|
static |
Process a single 64-byte block through the SHA-256 compression function (FIPS 180-4 §6.2.2).
The SHA-256 compression function operates on a 256-bit (8-word) state and a 512-bit (64-byte) message block:
| state | [in/out] 8-element hash state (updated in-place). |
| data | 64-byte (512-bit) message block to process. |
|
static |
Standard Base64 alphabet per RFC 4648 §4.
The alphabet uses 64 ASCII characters: A-Z (indices 0-25), a-z (26-51), 0-9 (52-61), '+' (62), '/' (63). Each group of 3 input bytes (24 bits) is encoded as 4 Base64 characters (6 bits each). If the input length is not a multiple of 3, padding '=' characters are added.
|
extern |
Default cipher driver vtable mapping all operations to the OpenSSL-backed implementations above.
Installed by the cipher subsystem as the default driver. Callers can override individual operations by building a custom driver struct with different function pointers for specific needs (e.g., hardware-backed keys).
|
static |