◇ OpenCyber Academy
Bachelor's · Chapter 8 · English

Chapter 8 — Programming II

Open, free learning for anyone who wants to protect people and technology. No account is required to read this text or its worked answers.

Chapter 8 — Programming II

Lesson map

Lesson 08 published. Map, example, EX015.

flowchart TD
  N0["Learning outcomes"]
  N1["8.1 Structure and data"]
  N2["8.2 Negative testing"]
  N3["8.3 Handling secrets in code"]
  N4["8.5 Practical activity"]
  N5["Synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5
  N5 --> EX["Worked example"]
  EX --> Q["Exercise EX015"]

Logical drawing

flowchart LR
  N0["Learning outcomes"]
  N1["8.1 Structure and data"]
  N2["8.2 Negative testing"]
  N3["8.3 Handling secrets in code"]
  N4["8.5 Practical activity"]
  N5["Synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX015"]
[Learning outcomes]
    |
    v
[8.1 Structure and data]
    |
    v
[8.2 Negative testing]
    |
    v
[8.3 Handling secrets in code]
    |
    v
[8.5 Practical activity]
    |
    v
[Synthesis]
    |
    v
[Worked example] --> [Exercise EX015]

Learning outcomes

You will (1) structure larger programs with modules, data classes and error handling; (2) parse structured inputs such as CSV and JSON; (3) write tests for both valid and invalid inputs; and (4) avoid common security mistakes in code that handles keys.

8.1 Structure and data

As programs grow, structure keeps them correct. Group related functions in modules, represent records with dataclasses so fields are named, and raise exceptions for invalid states instead of returning silently wrong values. The standard library's csv and json modules parse common formats; validating every field as you read it — type, range, allowed values — stops bad data from propagating. In migration work, inventories arrive as CSV exports from scanners and configuration databases, and most analysis errors begin with an unvalidated column.

8.2 Negative testing

A positive test checks that valid input works; a negative test checks that invalid input is rejected. Cryptographic code needs both. A decoder for ML-KEM encapsulation keys must accept exactly 800, 1,184 or 1,568 bytes for the three parameter sets in FIPS 203 and reject anything else, and FIPS 203 also specifies input checks on the key's coefficients. Libraries that skipped such checks have historically accepted malformed inputs that leaked information or crashed services. Write the negative tests before you write the decoder.

HCU's tests include keys one byte too short and one byte too long.

8.3 Handling secrets in code

Keep secrets out of logs, exception messages and version control. Prefer passing key handles (references held by an HSM or OS keystore) instead of raw key bytes. Compare secrets with constant-time functions. Never write your own production implementation of a post-quantum algorithm; use a vetted library, and treat even small wrapper code with suspicion, because side channels and parsing bugs live in the glue as often as in the core.

For HCU, this means calling the approved library through a small interface and reviewing that interface as carefully as anything else.

8.4 Worked example

An HCU analyst receives inventory.csv with columns host, protocol, group. A careless script counts rows where group == "x25519" and reports "most hosts classical". A careful version normalises case, rejects rows with empty groups as unknown rather than classical, and prints three numbers: classical, hybrid and unknown. The careful script reveals that 18 % of synthetic rows are unknown — a fact the first script hid.

Treating unknown as classical would have made the inventory look more complete and more uniformly classical than it was, hiding the hosts whose cryptography nobody knew. Unknowns become a work list of their own: someone must check those hosts directly before the inventory can be trusted. The careful script also records the input file's date, so later readers know how fresh the counts are.

8.5 Practical activity

Write a function that reads lines host,group, validates that group belongs to an allowed set, and returns counts of hybrid, classical and unknown. Include one negative test with an unknown group string.

Normalise case and spaces before comparing, and decide in advance what counts as hybrid. A group name you have never seen should fall into unknown, never into classical by default. Your negative test should show that a misspelt or invented group name is counted as unknown and that the function does not crash on an empty line. Print the three counts in a fixed order so outputs from different runs can be compared.

8.6 Common errors and limits

Missing data is a finding about the inventory, not about the systems. Swallowing exceptions hides the rows that failed, so the totals look complete when they are not; log each failure with its line number instead. Custom cryptography fails in ways that tests rarely catch, such as timing differences, and vetted libraries have had years of review that a new implementation cannot match.

Exercises

Synthesis

Structured code, validated inputs and negative tests make analysis trustworthy; in cryptographic code, rejecting bad input is as important as handling good input.

Continue studying — chapter 08 of 40

← Chapter 07 (draft) · Course chapter index · Chapter 09 (draft) →