Learn C Language - Cryptography & Data Protection
Episode 14 of 24

Learn C Language - Cryptography & Data Protection

This episode opens up cryptography for C applications: the basics of symmetric and asymmetric encryption, the OpenSSL and libsodium libraries, hashing, HMAC, and secure random number generation, as well as secure key handling and the management of sensitive data in memory.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Data that crosses a network without protection can be read by anyone. Episode 14 discusses cryptography in C applications: how to protect data with encryption, ensure integrity with hashing and HMAC, and generate cryptographically secure random numbers.

An important rule to understand from the start: never write your own cryptography. Always use libraries tested by the world's security community, such as OpenSSL and libsodium. Self-written cryptography almost certainly contains fatal flaws.

This episode focuses on using libraries correctly: the right algorithms, safe configuration, and habits for keeping keys and sensitive data safe in memory.

Cryptography Basics in C

Symmetric and Asymmetric Encryption

Symmetric encryption uses one key to encrypt and decrypt, is fast, and suits large data. A modern example: AES-256-GCM. Asymmetric encryption uses a public-private key pair and is used for key exchange and signatures. In real practice, both are combined: a random symmetric key is wrapped by asymmetric cryptography.

The Framework in C

C programs talk to cryptography libraries through an API that provides context objects, initialization functions, and processing functions. Most usage errors aren't in the algorithm's math but in key management, padding, and memory cleanup. The quality of a cryptography implementation is determined by these details.

Checking Integrity Before Trusting

Cryptography provides two different guarantees that are often confused: confidentiality ensures only key holders can read, while integrity ensures data hasn't been modified. Encryption without authentication like AES-CBC only guarantees confidentiality; an attacker can still tamper with the ciphertext. That's why the AES-GCM mode combines encryption and authentication in one operation. Understand which guarantee you need before choosing an algorithm.

The OpenSSL and libsodium Libraries

OpenSSL: The Industry Standard

OpenSSL is the most widely used cryptography library in the C ecosystem, forming the foundation of TLS for most of the world's servers. Many operating systems already ship it:

Check OpenSSL
openssl version
pkg-config --modversion libcrypto libssl

The command openssl version shows the installed library version. To link a C program, use pkg-config, which outputs the right flags:

Compile with OpenSSL
gcc -Wall $(pkg-config --cflags openssl) app.c -o app $(pkg-config --libs openssl)

The pattern $(pkg-config --cflags openssl) inserts the header paths, and the libs part links libcrypto and libssl. Always use a supported OpenSSL version — outdated versions are vulnerable to CVEs.

libsodium: A Friendly Modern API

libsodium is a modern wrapper over recommended algorithms, with an API that's far harder to misuse. Its development focuses on usability: default operations already use safe settings, and key lengths are always explicit. For new projects that prioritize simplicity, libsodium is a very strong choice.

Hashing, HMAC, and Random Number Generation

Hashing and HMAC

A one-way hash such as SHA-256 produces a fixed-length fingerprint of data. Hashes suit integrity checks and password storage, but for passwords use specialized functions like Argon2 that are deliberately slow. HMAC uses a hash with a secret key, producing a signature that proves a message's authenticity and integrity:

Hash a file with the OpenSSL tool
echo -n "pesan rahasia" | openssl dgst -sha256
openssl rand -hex 32

The command openssl dgst -sha256 computes the SHA-256 hash of the input. openssl rand -hex 32 generates 32 secure random bytes that can be used as a key. This is the key difference: ordinary random generators for statistics, cryptographic random generators for keys — don't mix them up.

Secure Random Numbers

The standard rand generator is not secure for cryptography. Use getrandom on Linux or the randombytes function in libsodium. Keys must be generated from the kernel's entropy source, not from system time or a guessable seed.

Secure Key Handling and Sensitive Data

Keeping Keys in Memory

Keys in memory can leak through core dumps, swap, or process snapshots. Some recommended practices: wipe keys with memset after use, prevent the compiler from optimizing away the cleanup with volatile, and hold memory out of swap with mlock:

Wipe keys from memory
#include <string.h>
#include <sys/mman.h>
 
void bersihkan(unsigned char *kunci, size_t n) {
    mlock(kunci, n);
    volatile unsigned char *p = kunci;
    while (n--) {
        *p++ = 0;
    }
    munlock(kunci, n);
}

mlock(kunci, n) prevents the key's memory pages from being swapped out, and the wipe through a volatile pointer ensures zeros are really written without compiler optimization. Read keys from an env or a vault, not from arguments visible in the process list.

Managing Sensitive Data

Sensitive data like passwords and tokens must be wiped as soon as it's no longer needed, never printed to logs, and never sent as plaintext without TLS. Also restrict who can read key files with strict file permissions. Data security is a chain; one weak link weakens everything.

Warning

Rolling your own cryptography almost certainly produces an insecure system. Use tested libraries, follow their security updates, and run tools like sodium_init and audit dependencies regularly.

Closing

Key takeaways:

  • Symmetric encryption for data, asymmetric for key exchange.
  • Don't write your own cryptography; use OpenSSL or libsodium.
  • Link libraries through pkg-config so the compile flags are correct.
  • HMAC proves a message's authenticity and integrity.
  • Keys must be generated from a cryptographically secure random source.
  • Wipe keys from memory and never log them.

In the next episode 15 we will discuss performance optimization — profiling with perf, gprof, and Valgrind, optimization with loop unrolling, inline, and compiler flags, memory locality and cache friendliness, up to the tradeoff between readability and performance.

Learn C Language - Cryptography & Data Protection | Learn C Language