C++ / a working model

160 / 163   ·   C11   ·   8 min

Cryptography

Keep this sentence

An operating system cannot protect data after it leaves the hardware the kernel actually controls. Cryptography uses a key to turn plaintext into ciphertext so that later possession of the bits still yields neither meaning nor useful alteration. This chapter presents the symmetric-encryption model, the decisive role of key secrecy, and how a hash supplies integrity checking.

In this lesson
  1. When the Kernel Cannot Reach the Data
  2. Plaintext, Ciphertext and Deterministic Maps
  3. Algorithms May Be Public; Keys Must Stay Secret
  4. Integrity: Turning Tampering into Garbage
  5. Example
  6. Exercise

Official chapter PDF

When the Kernel Cannot Reach the Data

Access-control lists apply only to objects the kernel currently manages. Once a USB stick is stolen, a packet is sniffed, or another host’s memory is dumped, those policies no longer exist. Data must therefore be transformed in advance into a form that remains worthless even when every bit is later obtained; that transformation is the job of cryptography.

Plaintext, Ciphertext and Deterministic Maps

Readable data is called plaintext P. An encryption algorithm E together with a key K yields ciphertext C. The matching decryption algorithm D, given the same key, recovers P. Both maps must be deterministic, and recovering P from C without K must be computationally infeasible. It is conventional to treat P as the message we wish to send and C as the protected copy that travels in the open.

Algorithms May Be Public; Keys Must Stay Secret

Inventing a cipher free of structural weaknesses is extremely hard, so real systems almost always adopt a few thoroughly analysed public standards. Consequently the entire security argument collapses onto the key: anyone who learns K can decrypt. Keeping that key secret in a running system is far harder than writing the encryption formula, and is the most common practical failure.

Integrity: Turning Tampering into Garbage

A strong cipher diffuses changes: altering even one bit of ciphertext produces an unpredictable, usually garbage plaintext, so an attacker cannot steer the result toward a chosen message. Including a hash of the original plaintext lets the receiver recompute and compare after decryption; any modification is then immediately visible.

Pitfalls

  • Treating the encryption algorithm itself as the secret rather than protecting the key.
  • Re-using one key for many independent messages without a nonce or counter.
  • Assuming encryption by itself authenticates the origin of the data.

Run an example

Minimum C11 · complete program · Download .c

#include <stdio.h>
#include <string.h>
#include <ctype.h>

void caesar_shift(char *s, int shift)
{
    int delta = ((shift % 26) + 26) % 26;
    for (int i = 0; s[i] != '\0'; i++) {
        unsigned char c = (unsigned char)s[i];
        if (isupper(c)) {
            s[i] = 'A' + (c - 'A' + delta) % 26;
        } else if (islower(c)) {
            s[i] = 'a' + (c - 'a' + delta) % 26;
        }
    }
}

int simple_hash(const char *s)
{
    int h = 0;
    for (int i = 0; s[i] != '\0'; i++) {
        h = (h + (unsigned char)s[i]) % 256;
    }
    return h;
}

int main(void)
{
    char buf[64] = "Transfer funds now";
    int h = simple_hash(buf);
    printf("plaintext: %s\n", buf);
    printf("hash: %d\n", h);
    caesar_shift(buf, 3);
    printf("ciphertext: %s\n", buf);
    caesar_shift(buf, -3);
    printf("decrypted: %s hash_match=%s\n", buf, simple_hash(buf) == h ? "yes" : "no");
    caesar_shift(buf, 3);
    buf[4] = 'X';
    caesar_shift(buf, -3);
    printf("tampered decrypt: %s hash_match=%s\n", buf, simple_hash(buf) == h ? "yes" : "no");
    return 0;
}

Compile locally

gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-56-cryptography.c -o example && ./example

Expected result

plaintext: Transfer funds now
hash: 249
ciphertext: Wudqvihu ixqgv qrz
decrypted: Transfer funds now hash_match=yes
tampered decrypt: TranUfer funds now hash_match=no

CHECK YOUR UNDERSTANDING

Close the answer. Explain it.

An attacker can rewrite ciphertext at will. Why is it still hard to make decryption produce a plaintext of the attacker’s choosing? How can such rewriting be detected more reliably?

Show a reference answer

A well-designed cipher spreads tiny ciphertext differences into an unrecognisable plaintext, so the attacker cannot know which bits to flip to obtain a target message. Protecting a hash of the plaintext alongside the data, then recomputing and comparing after decryption, makes any change visible.

Check the sources

Drafts and official chapters change. The version mark is only the example’s minimum.

Back to the catalog