Cryptography Advanced About 2 hours

Cryptography for Developers

Make safer engineering decisions about encoding, password storage, encryption, nonces, and signature verification.

Short lessons 5 lessons Hands-on practice Local progress

Start here

Course introduction

Most application cryptography failures are selection, storage, or verification mistakes rather than broken mathematics. This course focuses on those engineering decisions with short evidence reviews rather than mathematical puzzles.

The examples are intentionally language-neutral. In production, use a maintained library and a documented high-level construction instead of implementing a primitive yourself.

By the end of this course, you can

  • Select a cryptographic primitive based on the property the feature needs.
  • Recognize unsafe nonce reuse, key rotation, and unverified-token patterns.
  • Put verification, validation, and authorization in the right order.
  • Choose failure behavior that does not expose a useful oracle.

Learn, then practice

Course lessons

Work through these 5 lessons in order. Each lesson introduces one concept, then gives you a practical activity or lab to apply it.

1

Name the property you need

Not started

Encoding, hashing, encryption, and signing solve different problems even when their output looks similarly unreadable.

Encoding changes representation and is reversible without a secret. Hashing creates a fixed-size digest. Encryption protects confidentiality with a key. A signature lets someone verify origin and integrity.

Start by naming the property. If the requirement is password verification, reversible encryption is the wrong primitive. Use a password-hashing function designed to be slow and salted.

Unreadable is not encrypted Text
c2VjcmV0LXRva2Vu  →  secret-token

Base64 is useful for transport. Anyone can decode it, so it provides no confidentiality.

Course challenge

Review the password record

This record must support password verification without allowing recovery of the original password. Enter the missing primitive.

Storage requirement Design note
Need: verify a submitted password
Must not: recover the original password
Per-record random salt: yes
Primitive: ?
2

Uniqueness is part of the design

Not started

Modern encryption modes depend on nonces or initialization values that must follow precise reuse rules.

Developers tend to protect the key and treat the nonce as decoration. In several common modes, reusing a nonce with the same key can reveal relationships between messages or break authentication.

Let a maintained cryptographic library generate the nonce. Store it beside the ciphertext, and design rotation so keys and encrypted records remain traceable.

Course challenge

Find the unsafe event

Compare the mock encryption log. Enter the event ID that reused a nonce with the same key.

Encryption log Log
evt-101  key=k7  nonce=8af2
evt-102  key=k7  nonce=c410
evt-103  key=k7  nonce=8af2
3

Verify before use

Not started

Encrypted or signed data is safe only when verification happens before the application acts on its contents.

Authenticated encryption produces ciphertext and an authentication tag. If tag verification fails, treat the whole message as untrusted and return one consistent error.

The same order matters for tokens and signed payloads. Pin the accepted algorithm and key source, verify the signature, validate expiry and audience, then use claims for authorization.

Safe processing order Pseudocode
payload = verify_and_decrypt(message, expected_key)
if payload is invalid: reject
if payload.audience != this_service: reject
process(payload)

Parsing unverified claims for a security decision puts trust before proof.

Before moving on, find the exact line in your own application where verification finishes and business logic begins.

Course challenge

Rebuild the trust boundary

Put the token-processing steps in the only order that avoids using untrusted claims.

Select the steps in the order they should happen.

4

Rotate with key identities

Not started

Rotation works when every ciphertext or signature can be connected to the key version that created it.

Give each key version a stable identifier and store that identifier beside the protected data. During rotation, write with the new key while retaining the old key only for the reads that still require it.

Removing the old key before data is migrated creates an outage. Keeping it active for new writes means rotation never really finishes.

Course challenge

Select the right key version

The record was created before rotation and carries its key identifier. Enter the key the service must use to decrypt it.

Encrypted record JSON
{
  "created": "2026-06-04T10:16:00Z",
  "key_id": "key-v2",
  "ciphertext": "b7a91f..."
}
5

Do not build an oracle

Not started

Detailed cryptographic errors can reveal which part of a protected message was valid.

Return one consistent failure to the caller when signature, padding, tag, or format validation fails. Keep the detailed reason in restricted internal logs.

Also keep the rejection path reasonably consistent. An attacker should not be able to distinguish a valid signature from a valid account by comparing messages or timing.

Course challenge

Choose the safe failure

A token fails verification. Which response gives the caller the least useful oracle?

Continue learning

Choose your next path

You have reached the end of this path. Pick another topic from the course catalog when you are ready.

Browse courses