Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Applied Cryptography for Developers  Module 1 – Foundations: goals, bytes and security levels

What cryptography can and cannot do

Match each primitive to the property it gives (confidentiality, integrity, authenticity, non-repudiation), threat-model a feature, and see what no cipher fixes.

  • Beginner
  • 25 minutes
  • Examples run with Node.js 24.21.0, Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free lesson, Pro answers: 25 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Name the property each primitive provides, among confidentiality, integrity, authenticity and non-repudiation
  • Write a short threat model that states what an attacker can see, change, replay or guess
  • Choose a maintained library and its highest-level API before reaching for raw primitives
  • Recognise problems cryptography cannot fix, such as broken authorisation or a compromised device
What you’ll learn

What you will learn

  • Name the property each primitive provides, among confidentiality, integrity, authenticity and non-repudiation
  • Write a short threat model that states what an attacker can see, change, replay or guess
  • Choose a maintained library and its highest-level API before reaching for raw primitives
  • Recognise problems cryptography cannot fix, such as broken authorisation or a compromised device
On this page

The OWASP Top 10:2025 ranks cryptographic failures fourth among the risks to web applications, with 32 weakness types and 1,665,348 occurrences in its data. The first weaknesses it names are a broken or risky algorithm, too little entropy and predictable random numbers: choices made in application code, where a tool was picked that does not give the guarantee the feature needed.

Cryptography gives four precise guarantees, each from its own kind of tool, and nothing beyond them. Here you match each guarantee to the cryptographic primitive: A basic building block with one precise job, such as a hash function, a MAC, a cipher or a signature scheme. Protocols such as TLS combine several primitives. that provides it, see in a program why Base64 and a plain hash protect nothing from an attacker, turn a feature into a four-line threat model, choose a library, and meet the problems that no cipher fixes, so that you know when the answer is an access check rather than more encryption.

Four guarantees, and the tool that gives each

Your shop’s server receives this from its payment provider: {"order": 4471, "amount": 500}. Before it marks the order paid, it needs four answers, and each one is a different guarantee with a different tool behind it:

Guarantee The question it answers Tools that give it Tools that do not
confidentiality: The guarantee that information is not disclosed to anyone the owner has not authorised. Encryption gives it; encoding, compression and hashing do not. Who else can read it? Encryption: TLS on the connection, or an authenticated cipher such as AES-GCM on the data Base64, hex, compression, a hash
data integrity: The guarantee that data has not been changed without authorisation since it was created, sent or stored. A MAC, an authenticated cipher's tag or a signature detects deliberate changes; a checksum catches only accidents. Has it changed since it was sent? A MAC, the tag of an authenticated cipher, or a signature A checksum or a plain hash, which catch accidents only
source authentication: Assurance about who created or sent a piece of data, also called authenticity. A MAC shows that a holder of the shared key made it; a signature shows which private key made it. Did it really come from the provider? A MAC (a holder of the shared key made it) or a signature (the owner of the private key made it) A sender name inside the message
non-repudiation: Evidence that lets a third party decide whether a given party signed a message. It needs a digital signature from a key that only that party holds, and in the end it is a legal question. Could an auditor or a court decide who sent it? A digital signature, with a record of whose key it is A MAC: both sides hold the same key

NIST’s key-management recommendation, SP 800-57 Part 1, defines the same services: confidentiality keeps information from unauthorised parties, data integrity means no unauthorised change since the data was created, sent or stored, and source authentication gives assurance about who created or sent it. It adds two warnings worth keeping. One mechanism may provide several services but never all of them, and whether a signature really commits its signer is in the end a legal decision, not a mathematical one.

A message authentication code (MAC): A function of a secret key and a message whose output, the tag, only holders of the key can compute. A receiver with the key recomputes the tag to check that the message is unchanged and came from a key holder; HMAC and KMAC are MACs. More in “HMAC and constant-time verification”, such as HMAC from RFC 2104, mixes a secret key into a hash, and that key is the whole difference. Step through one order update sent three ways and watch which design stops a person on the network path:

Interactive · message by message One order update, sent three ways Step through the same webhook message protected by Base64, by a SHA-256 digest and by an HMAC tag, and watch what a person on the network path can change.
One order update, sent three ways, step 9 of 9. Messages so far: Payment provider to Someone on the path: eyJvcmRlciI6IDQ0NzEs…; Someone on the path to Your server: amount 5000, re-encoded; Payment provider to Someone on the path: body + SHA-256(body); Someone on the path to Your server: new body + its new digest; Payment provider to Someone on the path: body + HMAC(key, body); Someone on the path to Your server: new body + guessed tag.Payment providerholds the HMAC keySomeone on the pathreads and edits trafficYour serverholds the HMAC keyeyJvcmRlciI6IDQ0NzEs…amount 5000, re-encodedbody + SHA-256(body)new body + its new digestbody + HMAC(key, body)new body + guessed tag

The drawing shows the whole scene; its 9 steps are listed below.

Every step as text
  1. The order update. The provider sends {"order": 4471, "amount": 500} to your webhook. It crosses networks you do not control, so assume a person on the path can read it, change it, drop it or send it again.
  2. Base64 only. The body leaves as Base64. Base64 has no key, so anyone who sees the text turns it back into the order with one standard function.
  3. Read and changed. The person on the path decodes it, writes 5000, encodes it again and passes it on. Your server decodes a well-formed order and has no way to tell that it changed.
  4. Body and its digest. Now the body travels with its SHA-256 digest. If one bit flips on the way, turning 500 into 501, the digest no longer matches and the server notices.
  5. Digest recomputed. A SHA-256 digest needs no key. The person on the path changes the amount and computes the digest of the new body, so the server's check passes on a forged order.
  6. Body and an HMAC tag. This time the body carries an HMAC-SHA-256 tag, computed with a key that only the provider and your server hold.
  7. No key, no tag. Without the key, nobody on the path can compute the right tag for an amount of 5000. Your server recomputes the tag, compares, finds no match and rejects the forged order.
  8. Still readable. None of the three designs hid the amount. Base64, a digest and a tag all leave the body readable. To keep it secret, encrypt it as well, with TLS on the connection or an authenticated cipher on the data.
  9. Proof for a third party. The tag proves to your server that a key holder sent the body, but both sides hold the key, so it cannot prove to an auditor which one did. A digital signature can, because only the provider holds its private key.

The program below runs those three designs with real functions. It flips one bit on the way, which turns 500 into 501, then swaps in a forged order with whatever someone without the key can compute. Press Run, then try your own forged amount, or a guessed key that is closer to the real one:

Base64, a digest and an HMAC tag against the same forgery Python · properties/properties.py
"""One webhook message protected three ways, and what someone on the network path can do."""
import base64
import hashlib
import hmac

# A fixed demo key, so the output repeats. Real keys come from a secrets store.
KEY = b"key-for-demo-only-not-a-real-key"
MESSAGE = b'{"order": 4471, "amount": 500}'
CHANGED = b'{"order": 4471, "amount": 5000}'


def tag(key, message):
    return hmac.new(key, message, hashlib.sha256).digest()


# What the receiving server checks in each design. In all three the message
# itself travels as it is, so anyone on the path can read it.
def accepts_base64(wire):
    return True  # whatever decodes is taken as the message


def accepts_digest(message, digest):
    return hashlib.sha256(message).digest() == digest


def accepts_tag(message, received_tag):
    return hmac.compare_digest(tag(KEY, message), received_tag)


flipped = MESSAGE[:-2] + bytes([MESSAGE[-2] ^ 1]) + MESSAGE[-1:]  # 500 -> 501
wire = base64.b64encode(MESSAGE)
print("Message:      ", MESSAGE.decode())
print("Base64 form:  ", wire.decode())
print("Decoded again:", base64.b64decode(wire).decode())
print("SHA-256:      ", hashlib.sha256(MESSAGE).hexdigest()[:24], "...")
print("HMAC-SHA-256: ", tag(KEY, MESSAGE).hex()[:24], "...")
print()

# Someone on the path flips one bit, or sends CHANGED with whatever they can compute.
rows = [
    ("Base64", None, accepts_base64(base64.b64encode(CHANGED))),
    ("SHA-256 digest",
     not accepts_digest(flipped, hashlib.sha256(MESSAGE).digest()),
     accepts_digest(CHANGED, hashlib.sha256(CHANGED).digest())),
    ("HMAC-SHA-256 tag",
     not accepts_tag(flipped, tag(KEY, MESSAGE)),
     accepts_tag(CHANGED, tag(b"a guess, not the key", CHANGED))),
]
print(f"{'Protection':<18}{'Readable':<10}{'Bit flip caught':<17}Forged change accepted")
for name, caught, forged in rows:
    flip = "no check" if caught is None else ("yes" if caught else "no")
    print(f"{name:<18}{'yes':<10}{flip:<17}{'yes' if forged else 'no'}")

Output

Message:       {"order": 4471, "amount": 500}
Base64 form:   eyJvcmRlciI6IDQ0NzEsICJhbW91bnQiOiA1MDB9
Decoded again: {"order": 4471, "amount": 500}
SHA-256:       276917d7713fc8190603a982 ...
HMAC-SHA-256:  d1e5e0defa35bb038d523328 ...

Protection        Readable  Bit flip caught  Forged change accepted
Base64            yes       no check         yes
SHA-256 digest    yes       yes              yes
HMAC-SHA-256 tag  yes       yes              no

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 properties.py

Only the HMAC tag rejected the forged order, and all three left the amount readable. Here are the same checks in JavaScript with Web Crypto, as Node.js 24.21.0 ran them; the table is identical:

The same three designs with Web Crypto JavaScript · properties-js/properties.mjs
// One webhook message protected three ways, and what someone on the network path can do.
// The same checks as properties.py, with Web Crypto (globalThis.crypto.subtle).
const { subtle } = globalThis.crypto;
const bytes = (text) => new TextEncoder().encode(text);
const hex = (buffer) => Array.from(new Uint8Array(buffer), (b) => b.toString(16).padStart(2, '0')).join('');

// A fixed demo key, so the output repeats. Real keys come from a secrets store.
const KEY = bytes('key-for-demo-only-not-a-real-key');
const MESSAGE = bytes('{"order": 4471, "amount": 500}');
const CHANGED = bytes('{"order": 4471, "amount": 5000}');

const hmacKey = (raw) => subtle.importKey('raw', raw, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign', 'verify']);
const sha256 = (data) => subtle.digest('SHA-256', data);
const tag = async (raw, message) => subtle.sign('HMAC', await hmacKey(raw), message);

// What the receiving server checks in each design. In all three the message
// itself travels as it is, so anyone on the path can read it.
const acceptsBase64 = (wire) => true; // whatever decodes is taken as the message
const acceptsDigest = async (message, digest) => hex(await sha256(message)) === hex(digest);
const acceptsTag = async (message, receivedTag) => subtle.verify('HMAC', await hmacKey(KEY), receivedTag, message);

const flipped = MESSAGE.slice();
flipped[flipped.length - 2] ^= 1; // 500 -> 501
const wire = btoa(String.fromCharCode(...MESSAGE));
console.log('Message:      ', new TextDecoder().decode(MESSAGE));
console.log('Base64 form:  ', wire);
console.log('Decoded again:', atob(wire));
console.log('SHA-256:      ', hex(await sha256(MESSAGE)).slice(0, 24), '...');
console.log('HMAC-SHA-256: ', hex(await tag(KEY, MESSAGE)).slice(0, 24), '...');
console.log();

// Someone on the path flips one bit, or sends CHANGED with whatever they can compute.
const rows = [
  ['Base64', null, acceptsBase64(btoa(String.fromCharCode(...CHANGED)))],
  ['SHA-256 digest', !(await acceptsDigest(flipped, await sha256(MESSAGE))), await acceptsDigest(CHANGED, await sha256(CHANGED))],
  ['HMAC-SHA-256 tag', !(await acceptsTag(flipped, await tag(KEY, MESSAGE))), await acceptsTag(CHANGED, await tag(bytes('a guess, not the key'), CHANGED))],
];
console.log(`${'Protection'.padEnd(18)}${'Readable'.padEnd(10)}${'Bit flip caught'.padEnd(17)}Forged change accepted`);
for (const [name, caught, forged] of rows) {
  const flip = caught === null ? 'no check' : caught ? 'yes' : 'no';
  console.log(`${name.padEnd(18)}${'yes'.padEnd(10)}${flip.padEnd(17)}${forged ? 'yes' : 'no'}`);
}

Output

Message:       {"order": 4471, "amount": 500}
Base64 form:   eyJvcmRlciI6IDQ0NzEsICJhbW91bnQiOiA1MDB9
Decoded again: {"order": 4471, "amount": 500}
SHA-256:       276917d7713fc8190603a982 ...
HMAC-SHA-256:  d1e5e0defa35bb038d523328 ...

Protection        Readable  Bit flip caught  Forged change accepted
Base64            yes       no check         yes
SHA-256 digest    yes       yes              yes
HMAC-SHA-256 tag  yes       yes              no

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node properties.mjs

Key idea

Name the guarantee before the tool: encryption hides, a MAC or an authenticated cipher’s tag proves that a key holder sent the data unchanged, a signature proves which private key signed it, and encodings and plain hashes prove nothing to an attacker.

Checkpoint

Check: Four guarantees and their tools

  1. Question 1 of 2 Your server must be sure that an order update really came from the payment provider and was not changed on the way. Which guarantees does it need?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Integrity and authenticity

    The question names two separate guarantees: the data has not changed since it was sent (integrity), and it came from the provider (authenticity). A shared-key MAC gives both to a server that holds the key.

  2. Question 2 of 2 The provider and your shop share an HMAC key, and every webhook carries a valid tag. In a dispute, can the shop prove to a court that the provider sent a given message?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: No: the shop holds the same key, so it could have made the tag itself

    Non-repudiation needs a key that only one party holds. With HMAC both sides hold the key, so a valid tag shows only that one of them made it. A digital signature from the provider's private key is what a third party can check.

Encoding hides nothing, and neither does a secret design

A mobile team wants the app’s discount codes out of plain sight, so it stores them Base64-encoded and reversed. The app ships to a million phones, and every copy carries the code that undoes the trick. Nobody needs a key, because there is none: the first person to unpack the app has every code.

In 1883 Auguste Kerckhoffs listed six requirements for a cipher system, and the second has outlived the telegraph: the details of the system may become known without harm to the people using it, so its security must rest on the key alone. This is Kerckhoffs's principle: The rule that a cryptosystem must stay secure even when everything about it except the key is public, so that its security rests on the key alone.. Today it reads: assume that an attacker has your source code, your binaries and the algorithm’s specification, and design so that the only thing they lack is the key. There are good reasons for it. Designs leak through shipped apps, public repositories and former staff. A leaked key can be replaced in minutes, while a leaked design cannot. And a published algorithm has been attacked by many people before you trust it.

Every transformation that needs no key fails that test:

Transformation Needs a key to undo? What it is for
Base64, hex No: one standard function Carrying bytes through channels built for text
Compression No Making data smaller
Obfuscation: reversing, renaming, a XOR with a constant in the code No: the “key” ships with the code Slowing down a casual reader
Encryption with AES-GCM Yes, and nothing but the key Confidentiality

The first row of the program’s table above shows this for Base64: decoded again, the order reads exactly as it was sent.

A password in Base64 is a password in plain text

Wrong: DB_PASSWORD=c2VjcmV0LWRiLXBhc3M= in a configuration file, “so that nobody can read it”. Anyone who can read the file decodes it at once. Right: keep secrets in the platform’s secret store, such as a key management service or the operating system’s keychain, and treat anything inside a shipped app as public.

Checkpoint

Check: Keyless transformations hide nothing

  1. One question A configuration file stores the database password Base64-encoded, "so that nobody can read it". Who can read the password?

    Choose one answer.

    Show the answer: One question

    Answer: Anyone who can read the file

    An encoding changes how bytes are written, not who can read them. Keep the password in a secret store, or at least protect the file with access rules, and never count Base64 as protection.

A threat model in four lines

A shop emails a link to reset a password: https://shop.example/reset?token=…. Before choosing any tool, write down what you are defending against. Four lines are enough for most features:

  1. What we protect: the account the link opens.
  2. Who might attack, and from where: someone who sees the link in a log or a forwarded email, someone who tries tokens at random, someone who gets a copy of the database.
  3. What they can see, change, replay or guess: they can read the address in a log, use a link they saw again, guess tokens, and read the stored copy of every token.
  4. What must still hold: a token cannot be guessed, works once, expires soon, belongs to one account, and is stored only as a hash, so a database copy reveals no working link.

Each ability in line 3 points at what the design needs. Reading calls for confidentiality, and changing for integrity with authenticity. Guessing calls for enough randomness: OWASP’s verification standard, ASVS 5.0, asks for at least 128 bits from a cryptographically secure generator for any value that must not be guessed (requirement 11.5.1). replay: Sending a captured, valid message again. A MAC or a signature still verifies on the copy, so a design needs its own freshness check, such as a timestamp, a nonce or a record of what was accepted. is the one that tags and signatures do not stop on their own, because a resent message verifies exactly like the original, so it needs its own rule, such as a timestamp, a single-use token or a record of what was already accepted. Say what is out of scope too: a person who controls the user’s mailbox can reset the password whatever the token, and that is a job for a second factor, not for the link.

Answer the threat model’s questions for your own data in the table below. It rules out the tools that cannot give what you need, and says why:

Interactive · answer and compare Which primitive fits your data? Answer four questions from your threat model. The table marks the tools that fit and says why the others cannot give what you need.
Must the content stay hidden from the network and from whoever reads the storage?
Could someone change it on the way or where it is stored?
Who has to check where it came from?
Is it a password that a person chose?

Answer the questions above: the table then marks what fits your case and says why the rest does not.

Six families of tools against the four guarantees, and replay, which none of them stops alone
Tool Keeps it secret Detects a deliberate change Proves who made it Convinces a third party Stops a replay
Base64 or hex encoding Needs: nothing (no key) Poor one standard call decodes it, no key needed Poor change the data and encode it again Poor anyone can produce it Poor proves nothing to anyone Poor a copy is as good as the original
Plain hash (SHA-256) Needs: nothing (no key) Poor the data travels beside it; a guessable value can be found by trying Mixed catches accidents, but anyone recomputes it for a changed message Poor anyone can compute it Poor no key means no claim about anyone Poor an old message keeps its old digest
MAC (HMAC-SHA-256) Needs: a key both sides share Poor the message stays readable Good a change without the key fails the check Good a holder of the shared key made it Poor either key holder could have made the tag Poor a resent message verifies: add a timestamp or a nonce
AEAD cipher (AES-GCM) Needs: a key both sides share Good only key holders can decrypt Good the tag fails if one bit changes Mixed a key holder made it, as with a MAC Poor both sides hold the key Poor a resent ciphertext decrypts as before
Signature (Ed25519) Needs: a private key one side holds Poor signs but does not hide: encrypt as well Good a changed message fails verification Good only the private key can sign Good anyone with the public key can check it Poor a resent signed message still verifies
Password hash (Argon2id) Needs: a salt and a cost setting Mixed no way back, and slow to guess if salted and costly Poor made for comparing passwords, not messages Poor no key, so it proves no sender Poor proves nothing about who acted Poor not its job
How the answers decide
  • “Must the content stay hidden from the network and from whoever reads the storage?” Yes, keep it secret: rules out Base64 or hex encoding, Plain hash (SHA-256), MAC (HMAC-SHA-256) and Signature (Ed25519). These leave the content readable: Base64 decodes, and a digest, a tag or a signature travels beside the data in the clear.
  • “Could someone change it on the way or where it is stored?” Yes: rules out Base64 or hex encoding and Plain hash (SHA-256). No key is involved, so a changed message arrives with a valid encoding or a freshly computed digest.
  • “Who has to check where it came from?” Anyone, or a third party such as an auditor: rules out MAC (HMAC-SHA-256) and AEAD cipher (AES-GCM). Checking needs the shared key, and either key holder could have made the tag, so a third party learns nothing from it.
  • “Who has to check where it came from?” A party that shares a key with the sender: adds a caveat to Signature (Ed25519). A signature works, but when both sides already share a key, a MAC or an AEAD tag gives the same proof for less.
  • “Could someone change it on the way or where it is stored?” Yes: adds a caveat to MAC (HMAC-SHA-256), AEAD cipher (AES-GCM) and Signature (Ed25519). A resent message still verifies. Add a timestamp or a message id, and reject old or repeated ones.
  • “Is it a password that a person chose?” Yes, we store it to check logins: rules out Base64 or hex encoding, Plain hash (SHA-256), MAC (HMAC-SHA-256), AEAD cipher (AES-GCM) and Signature (Ed25519). Stored passwords need a slow, salted password hash, so that a stolen table resists guessing. A later module covers it.
  • “Is it a password that a person chose?” No: rules out Password hash (Argon2id). A password hash is built for secrets that people choose and type. Messages and records need the other tools.

In short: data that must stay secret needs encryption, and an authenticated cipher also proves it unchanged; a message checked by a party that shares your key needs a MAC; one that anyone or a third party must check needs a signature; passwords need a password hash; and replay needs its own check whatever you pick.

Checkpoint

Check: Threat models and replay

  1. Question 1 of 2 Your webhook handler checks HMAC tags correctly. Someone who copied last week's valid "refund order 4471" message sends it again, unchanged. What happens, and what stops it?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The tag verifies and the refund runs again; a timestamp or event id inside the signed body, checked against what was already processed, stops it

    Replay is the ability in the threat model that tags, signatures and encryption do not stop on their own. The fix is a rule: put a timestamp and an event id under the tag, reject messages older than a few minutes, and remember the ids you have processed.

  2. Question 2 of 2 A reset link's token is 6 random decimal digits. How many values must someone try, at most, to be sure of finding a given token?

    Type a number.

    A hint

    Each digit has 10 values, and the digits are chosen independently.

    Show the answer: Question 2 of 2

    Answer: 1000000 values

    Six digits give 10⁶ = 1,000,000 values, about 2²⁰, so the token carries about 20 bits of randomness, far below the 128 bits that ASVS 5.0 asks for values that must not be guessed. A token of 16 random bytes from a secure generator, written as 22 Base64url characters, carries the full 128.

Reach for the highest-level tool in a maintained library

The README of crypto-js, a JavaScript library that many projects still install, says that its active development has been discontinued and that it is no longer maintained, and it points users to the native crypto module of Node.js and browsers instead. Every package you add carries its maintainers’ future with it: a library nobody maintains gets no fixes for the next weakness found in it.

Two rules keep most code out of trouble. Use the platform’s own cryptography where it exists: Web Crypto in browsers and Node.js, node:crypto, Python’s hashlib, hmac and secrets with the cryptography package for the rest, Java’s cryptography architecture, Go’s crypto packages. ASVS 5.0 asks for industry-validated implementations of every operation (requirement 11.2.1). And use the highest-level operation that fits:

Instead of Use Why
A cipher and a MAC that you combine yourself An authenticated cipher: AES-GCM or ChaCha20-Poly1305 One call gives secrecy and a tag; ASVS 11.3.3 prefers it
SHA-256 of a password A password hash: Argon2id, scrypt, bcrypt or PBKDF2 Slow and salted, built for secrets that people guess
Raw RSA encryption HPKE, or a library’s sealed box Padding and key handling are already right
A home-made secure channel TLS 1.3 from the platform Years of analysis and test suites
Math.random() or random crypto.getRandomValues() or secrets Unpredictable values from the operating system

The W3C specification even names its low-level interface SubtleCrypto, to signal that its algorithms have subtle usage requirements. Before you add a package, ask the platform what it already offers. This program does that by trying, which is how portable code should detect an algorithm:

Feature-detecting Web Crypto algorithms JavaScript · algorithms/which_algorithms.mjs
// Which algorithms does this runtime's Web Crypto offer? Feature-detect by trying,
// instead of assuming: engines differ, and old algorithms are left out on purpose.
const { subtle } = globalThis.crypto;
const publicExponent = new Uint8Array([1, 0, 1]); // 65537, big-endian

const keys = [
  ['AES-GCM, 256-bit key', { name: 'AES-GCM', length: 256 }, ['encrypt', 'decrypt']],
  ['HMAC with SHA-256', { name: 'HMAC', hash: 'SHA-256' }, ['sign', 'verify']],
  ['Ed25519 signatures', { name: 'Ed25519' }, ['sign', 'verify']],
  ['ECDSA on P-256', { name: 'ECDSA', namedCurve: 'P-256' }, ['sign', 'verify']],
  ['X25519 key agreement', { name: 'X25519' }, ['deriveBits']],
  ['RSA-OAEP, 3072-bit', { name: 'RSA-OAEP', modulusLength: 3072, publicExponent, hash: 'SHA-256' }, ['encrypt', 'decrypt']],
  ['DES-CBC', { name: 'DES-CBC', length: 64 }, ['encrypt', 'decrypt']],
  ['AES-ECB', { name: 'AES-ECB', length: 128 }, ['encrypt', 'decrypt']],
];
const digests = ['SHA-256', 'SHA-512', 'SHA-1', 'MD5'];

const result = async (work) => {
  try {
    await work();
    return 'yes';
  } catch (err) {
    return `no (${err.name})`;
  }
};

console.log('Key generation');
for (const [label, algorithm, usages] of keys) {
  console.log(`  ${label.padEnd(24)}${await result(() => subtle.generateKey(algorithm, false, usages))}`);
}
console.log('Digests');
for (const name of digests) {
  console.log(`  ${name.padEnd(24)}${await result(() => subtle.digest(name, new Uint8Array(1)))}`);
}

Output

Key generation
  AES-GCM, 256-bit key    yes
  HMAC with SHA-256       yes
  Ed25519 signatures      yes
  ECDSA on P-256          yes
  X25519 key agreement    yes
  RSA-OAEP, 3072-bit      yes
  DES-CBC                 no (NotSupportedError)
  AES-ECB                 no (NotSupportedError)
Digests
  SHA-256                 yes
  SHA-512                 yes
  SHA-1                   yes
  MD5                     no (NotSupportedError)

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node which_algorithms.mjs

Node.js 24.21.0 offers every modern tool in the list and refuses DES, AES in ECB mode and MD5, none of which the Web Cryptography specification defines at all. Code that asks for one of them is a sign of an old design.

Algorithms still in active development in Node.js 24

Node.js 24 also has ChaCha20-Poly1305, SHA-3, ML-KEM and ML-DSA in Web Crypto, but its documentation marks them as still in active development, and using one prints a warning. The program above leaves them out for that reason; the symmetric-encryption and post-quantum modules use them.

“FIPS validated” is a different question again. It means that NIST’s Cryptographic Module Validation Program accepted a lab’s test of the module against FIPS 140, so the module has a validation certificate number; modules validated under the older FIPS 140-2 now sit on the program’s historical list, kept for systems already in use. A validated module can still be used the wrong way, so compliance and security are related questions, not the same one.

Checkpoint

Check: Maintained, high-level tools

  1. One question You must encrypt one column of a database table in a Node.js service. Which choice follows "the highest-level tool in a maintained library"?

    Choose one answer.

    Show the answer: One question

    Answer: AES-GCM from the platform's Web Crypto or node:crypto, with a fresh nonce for every value

    Two rules decide it: use the platform's maintained cryptography, and use its highest-level operation that fits. For data that must stay secret and unchanged, that is an authenticated cipher such as AES-GCM.

What no cipher can fix

Asha is signed in to an invoicing app over TLS 1.3, with a session token whose HMAC tag the server checks on every request. Her invoice is number 1042. She changes the address to 1043 and gets Ben’s invoice. Step through the request:

Interactive · message by message Every check passes, and the wrong person reads the invoice Step through one request from Asha for an invoice that is not hers, first to the weak handler and then to the fixed one.
Every check passes, and the wrong person reads the invoice, step 8 of 8. Messages so far: Asha's browser to Invoice API: GET /invoices/1043 + token; Invoice API to Database: invoice where id = 1043; Database to Invoice API: id 1043, owner ben; Invoice API to Asha's browser: 200 OK: Ben's invoice; Invoice API to Database: id = 1043 and owner = asha; Invoice API to Asha's browser: 404 Not Found.Asha's browsersigned in as ashaInvoice APItoken valid: ashaDatabaseinvoices 1042 and 1043GET /invoices/1043 + tokeninvoice where id = 1043id 1043, owner ben200 OK: Ben's invoiceid = 1043 and owner = asha404 Not Found

The drawing shows the whole scene; its 8 steps are listed below.

Every step as text
  1. A valid session. Asha signed in and holds a session token with an HMAC tag that the API checks on every request. TLS protects the connection. Every cryptographic part of what follows works as designed.
  2. Another number. Her own invoice is 1042. She changes the number in the address to 1043. Nothing in TLS or in the token stops her from asking.
  3. Token verified. The API recomputes the token's tag and it matches, so the token really is Asha's. That answers who is asking, not what she may see.
  4. Looked up by number. The weak handler looks the invoice up by its number alone.
  5. Ben's row. Invoice 1043 exists, and it belongs to Ben.
  6. The wrong reader. The API returns Ben's invoice to Asha over a perfectly encrypted connection. This is broken access control, first in the OWASP Top 10:2025, and no cipher could have stopped it.
  7. The fix. The fixed handler asks for the invoice by its number and by its owner, and takes the owner from the verified token, never from the request.
  8. Nothing to learn. No row matches, so Asha gets the same 404 as for an invoice that does not exist, which also tells her nothing about Ben's. The fix is a rule in the code, not more encryption.

Every cryptographic check passed: the connection was encrypted and the token was genuine. What failed is a rule, and OWASP ranks it first in the Top 10:2025 as broken access control: access control enforces a policy so that users cannot act outside their permissions, and this handler never asked whether invoice 1043 was Asha’s. NIST draws the same line in SP 800-57: authorisation, the permission to perform an activity, is a security service that cryptography often supports rather than provides. The program below runs both handlers against the same three requests, and the last column is the test that fails on the weak handler and passes on the fix. Run it, then add a third invoice for Ben and ask for it with Asha’s token:

A weak and a fixed invoice handler, tested Python · access/invoice_access.py
"""Every cryptographic check passes, and one handler still shows the wrong person an invoice."""
import hashlib
import hmac

# A fixed demo key, so the output repeats. Real keys come from a secrets store.
SESSION_KEY = b"session-key-for-this-demo-only!!"
INVOICES = {1042: {"owner": "asha", "total": 1200}, 1043: {"owner": "ben", "total": 87000}}


def issue_session(user):
    """A toy session token: the user's name and an HMAC tag (real ones also expire)."""
    tag = hmac.new(SESSION_KEY, user.encode(), hashlib.sha256).hexdigest()
    return f"{user}.{tag}"


def verify_session(token):
    """The user a session token names, or None when its tag does not match."""
    user, _, tag = token.partition(".")
    expected = hmac.new(SESSION_KEY, user.encode(), hashlib.sha256).hexdigest()
    return user if hmac.compare_digest(expected.encode(), tag.encode()) else None


def get_invoice_weak(token, invoice_id):
    user = verify_session(token)
    if user is None:
        return 401
    return 200 if invoice_id in INVOICES else 404


def get_invoice_fixed(token, invoice_id):
    user = verify_session(token)
    if user is None:
        return 401
    invoice = INVOICES.get(invoice_id)
    if invoice is None or invoice["owner"] != user:
        return 404  # the same answer as "no such invoice": nothing to probe
    return 200


asha = issue_session("asha")
forged = "ben." + "0" * 64
print("Asha's session token:", asha[:20] + "...")
print()
print(f"{'Handler':<8}{'Asha: 1042':<12}{'Asha: 1043':<12}{'Forged token':<14}Result")
for name, handler in [("weak", get_invoice_weak), ("fixed", get_invoice_fixed)]:
    own, other, fake = handler(asha, 1042), handler(asha, 1043), handler(forged, 1043)
    result = "PASS" if (own, other, fake) == (200, 404, 401) else "FAIL: Asha reads Ben's invoice"
    print(f"{name:<8}{own:<12}{other:<12}{fake:<14}{result}")

Output

Asha's session token: asha.b61ad51fe0929e6...

Handler Asha: 1042  Asha: 1043  Forged token  Result
weak    200         200         401           FAIL: Asha reads Ben's invoice
fixed   200         404         401           PASS

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 invoice_access.py

The forged token got 401 from both handlers, so the cryptography worked in both; only the ownership check separates them.

Encrypting the invoice numbers instead of checking the owner

Wrong: turning /invoices/1043 into /invoices/9f2c…, an encrypted or random identifier, and calling it fixed. The link still works for anyone who sees it in a shared email, a log or a browser history. Right: keep any identifier you like, and check on every request that the invoice belongs to the user named by the verified session.

Problems of this kind need something other than cryptography:

  • Missing authorisation checks, as above: every request needs a rule about who may do what.
  • Leaked or hard-coded keys: encryption is only as secret as its key, and a key in a repository is public.
  • A compromised device: malware on a phone or a laptop reads data before it is encrypted and after it is decrypted.
  • A person tricked into the wrong action: a phishing page that the user signs in to gets a perfectly valid session.
  • Copies outside the protected path: logs, caches and backups that hold the plaintext. OWASP’s guidance on cryptographic failures warns about caches that keep sensitive responses.

Key idea

Cryptography protects data on the way and at rest, and proves who made it; deciding who may do what is a rule your code has to check on every request.

Checkpoint

Check: What cryptography cannot fix

  1. Question 1 of 2 Users can read other people's invoices by changing the number in /invoices/1043. A teammate proposes encrypting the numbers in the address with AES. What do you say?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: It does not fix the bug: check on every request that the invoice belongs to the user of the verified session

    Broken access control is a missing rule, and no cipher adds a rule. Keep any identifiers you like, and make the handler look the invoice up by its number and by the owner named in the verified session.

  2. Question 2 of 2 Which of these problems can cryptography fix? Choose every one that applies.

    Choose every answer that is right.

    Show the answer: Question 2 of 2

    Answer:

    • Order updates that someone on the network changes on the way
    • Card numbers that a stolen backup would reveal

    Cryptography protects data in transit and at rest and proves who made it. Missing access checks, compromised devices and leaked keys need other controls: rules in code, device security, revocation.

Practise: make the webhook check a real one

Write the server side of the third design: a function that accepts a webhook only when its HMAC-SHA-256 tag is right. The sample tests start with test case 2 of RFC 4231, the official HMAC-SHA-256 vector, then try a changed body, a tag made with another key, a plain digest of a forged body, a missing signature and signatures that are not hex. The starter code is the second design, a digest check, and the forged-digest test shows why it is not enough:

Exercise · Easy · Python

Replace a digest check with an HMAC check

A payment provider sends your server webhooks. Each one carries the body as bytes and a header with a 64-character hex signature: the HMAC-SHA-256 tag of the body under a key that only the provider and your server hold.

Write verify(body, signature, key) in webhook.py. It returns True only when signature is the right tag of body under key, and False for everything else: a changed body, a tag made with another key, a plain SHA-256 digest of the body, a missing signature (None, for a request without the header) and a signature that is not 64 hex characters (it never raises). Upper-case hex is fine. Compare the tags with hmac.compare_digest, not ==.

The starter code checks a plain SHA-256 digest of the body, which anyone can compute for a body of their choice. The sample tests start with test case 2 of RFC 4231, the official HMAC-SHA-256 vector: key b"Jefe", body b"what do ya want for nothing?".

Starter code · webhook.py

import hashlib


def verify(body, signature, key):
    """True when signature is the hex HMAC-SHA-256 tag of body under key, else False."""
    # This checks a plain SHA-256 digest, which anyone can compute for any body.
    # Replace it with an HMAC-SHA-256 check under key, compared in constant time.
    return hashlib.sha256(body).hexdigest() == signature
The sample tests · test_webhook.py
import hashlib
import hmac

from webhook import verify

KEY = b"webhook-key-for-the-sample-tests"
BODY = b'{"order": 4471, "amount": 500}'


def tag_of(body, key=KEY):
    return hmac.new(key, body, hashlib.sha256).hexdigest()


def test_rfc_4231_test_case_2():
    """the official HMAC-SHA-256 vector is accepted"""
    tag = "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"
    assert verify(b"what do ya want for nothing?", tag, b"Jefe") is True


def test_right_tag_accepted_in_either_case():
    """the right tag is accepted, in lower-case and upper-case hex"""
    assert verify(BODY, tag_of(BODY), KEY) is True
    assert verify(BODY, tag_of(BODY).upper(), KEY) is True


def test_changed_body_rejected():
    """a body changed after it was tagged is rejected"""
    changed = b'{"order": 4471, "amount": 5000}'
    assert verify(changed, tag_of(BODY), KEY) is False


def test_plain_digest_rejected():
    """a SHA-256 digest of the body, which anyone can compute, is rejected"""
    changed = b'{"order": 4471, "amount": 5000}'
    assert verify(changed, hashlib.sha256(changed).hexdigest(), KEY) is False


def test_other_key_rejected():
    """a tag made with another key is rejected"""
    assert verify(BODY, tag_of(BODY, b"some-other-key"), KEY) is False


def test_missing_signature_rejected():
    """a request without the signature header (None) gives False, without an exception"""
    assert verify(BODY, None, KEY) is False


def test_malformed_signatures_rejected():
    """signatures that are not 64 hex characters give False, without an exception"""
    for bad in ["", "abc", "zz" * 32, tag_of(BODY)[:-1], tag_of(BODY) + "00", "é" * 64]:
        assert verify(BODY, bad, KEY) is False, f"{bad!r} should be rejected"
A hint

Compute the tag you expect with hmac.new(key, body, hashlib.sha256).digest(). Turn the received hex into bytes with bytes.fromhex(signature), which raises ValueError for anything that is not hex, and return False in that case. Check first that the signature is a string of 64 characters: a tag of SHA-256 is 32 bytes, 64 hex characters.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

HMAC Generator Compute an HMAC-SHA-256 tag of your own body and key, and compare it with what your verify function expects.

Finish with a mixed set on all five ideas: it opens with the one you are weakest on, climbs a level each time you answer well, and asks again at the end whatever you missed:

Practice that adapts to you

Practise this lesson

12 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 12 Which of these detect a deliberate change by someone who does not hold your key? Choose every one that applies.

    Choose every answer that is right.

    Show the answer: Question 1 of 12

    Answer:

    • A digital signature
    • An HMAC-SHA-256 tag
    • The tag of an authenticated cipher such as AES-GCM

    Deliberate changes are caught only by tools that need a secret: a MAC, an authenticated cipher's tag, or a signature. Keyless checks such as digests and checksums catch accidents only.

  2. Question 2 of 12 Nightly database backups are copied to a storage bucket that another team runs. They must stay secret from that team, and you must notice if a file was altered. What do you use?

    Choose one answer.

    Show the answer: Question 2 of 12

    Answer: An authenticated cipher such as AES-GCM, with a key that the other team cannot reach

    Two guarantees are needed: confidentiality and integrity. Only encryption gives the first, and an authenticated cipher gives both, as long as its key is kept away from the people who run the storage.

  3. Question 3 of 12 You publish an installer on several mirrors that you do not run. Users must be able to check that a file is yours and unchanged, without sharing any secret with you. Which design works?

    Choose one answer.

    Show the answer: Question 3 of 12

    Answer: Sign the installer with your private key, and publish the public key through a channel your users already trust

    The checkers are the public, so the key that checks must be public too. That is a signature, which also gives authenticity and integrity against every mirror.

  4. Question 4 of 12 What does Kerckhoffs's principle ask of a cryptosystem?

    Choose one answer.

    Show the answer: Question 4 of 12

    Answer: It must stay secure even if everything about it except the key becomes public

    The principle comes from the second of the six requirements Kerckhoffs listed in 1883: the details of a cipher system may become known without harm to its users. Security rests on the key alone.

  5. Question 5 of 12 A mobile app protects tokens it stores on the phone with a XOR against a 16-byte constant written in its code. How much protection does that give against someone who has the app?

    Choose one answer.

    Show the answer: Question 5 of 12

    Answer: None: the constant ships with every copy of the app, so it is a key that everyone has

    Anything inside a shipped app is public. On a phone, keep such tokens in the platform's keystore, which holds keys outside the app's code and data.

  6. Question 6 of 12 Put the four lines of the lesson's threat model in order.

    Give each item its position, from 1 (first).

    Show the answer: Question 6 of 12

    Answer:

    1. What we protect
    2. Who might attack, and from where
    3. What they can see, change, replay or guess
    4. What must still hold

    Start from the asset, then the attacker and their position, then their abilities, which point at the guarantees the design needs, and end with what must stay true. A last note says what is out of scope.

  7. Question 7 of 12 Service A calls service B inside your data centre with a bearer token over plain HTTP, "because the network is private". Which line of the threat model shows the problem, and what fixes it?

    Choose one answer.

    Show the answer: Question 7 of 12

    Answer: Who attacks and from where: a compromised host or a person inside the network can read the token; use TLS, ideally mutual TLS, on internal calls

    Line 2 asks where the attacker sits. Once you admit that someone may read traffic inside the network, the token needs confidentiality in transit, which TLS gives, and mutual TLS also authenticates the calling service.

  8. Question 8 of 12 Which tool does the lesson say to use for storing users' passwords?

    Choose one answer.

    Show the answer: Question 8 of 12

    Answer: A password hash such as Argon2id, scrypt, bcrypt or PBKDF2

    Passwords need the highest-level tool built for them, a password hash. The key-derivation and password module covers its settings.

  9. Question 9 of 12 Your Node.js service needs AES-GCM. Package X has more downloads, but its README says development has been discontinued. Package Y is small and active. What do you use?

    Choose one answer.

    Show the answer: Question 9 of 12

    Answer: Neither package, while the platform's own Web Crypto or node:crypto offers AES-GCM

    Platform APIs come first: they ship with the runtime and are maintained with it, the kind of widely used, tested implementation that ASVS asks for. Add a package only for what the platform lacks.

  10. Question 10 of 12 Your code runs in browsers and in several Node.js versions, and it wants Ed25519 when it is there. How should it decide?

    Choose one answer.

    Show the answer: Question 10 of 12

    Answer: Try the operation, for example generateKey, and fall back if it throws NotSupportedError

    Feature detection by trying is portable and honest: the engine answers for itself. The program in the lesson does it for eight key types and four digests.

  11. Question 11 of 12 A phone runs spyware and also a chat app with end-to-end encryption. Which messages can the spyware read?

    Choose one answer.

    Show the answer: Question 11 of 12

    Answer: Every message the app shows or the user types

    A compromised device is outside what cryptography can fix: the device itself holds the keys and the plaintext. Device security, updates and app hardening are the controls here.

  12. Question 12 of 12 A user signs in to a lookalike site that relays everything to your real site, and the attacker gets a valid session. Your TLS, tokens and password hashing all worked. What went wrong?

    Choose one answer.

    Show the answer: Question 12 of 12

    Answer: The user was deceived about which site they were using; the cryptography did exactly what it was given to do

    Phishing defeats the person, not the cipher. The defence is a sign-in that cannot be relayed, which the passkeys lesson of this track covers, plus warnings and limits on what a new session may do.

Interview questions

Warm-up (fresher to mid level): what is the difference between encoding, hashing and encryption, and which of them needs a key?

Encoding, such as Base64 or hex, rewrites bytes in another alphabet so that they survive a text channel; it needs no key, anyone can reverse it, and it protects nothing. A hash such as SHA-256 maps any input to a fixed-size digest that cannot be turned back into the input; it needs no key either, so it detects accidental changes, but anyone can compute the digest of a forged message. Encryption needs a key: without it the ciphertext reveals nothing, and an authenticated cipher such as AES-GCM also detects any change. Add a key to a hash and you get a MAC such as HMAC, which proves that a key holder sent the message unchanged without hiding it. So the quick test is the key: no key, no protection against an attacker.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Fresher to mid

    A payment provider will send order updates to your webhook. A teammate proposes that the provider add a SHA-256 digest of each body in a header, so that your server can check integrity. What is wrong with the proposal, and what do you build instead?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to senior

    Testers found that any signed-in user can read any invoice by changing the number in /invoices/1043. A teammate proposes encrypting the invoice numbers in every URL with AES-GCM. Evaluate the proposal and give the fix.

    Model answer, Pro. First step and follow-ups

Flashcards · 8 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. Which four guarantees does cryptography give, and which tool gives each one?

    Confidentiality: encryption. Integrity: a MAC, the tag of an authenticated cipher or a signature. Authenticity: a MAC (a key holder made it) or a signature (the owner of the private key made it). Non-repudiation: a digital signature, with a record of whose key it is.

  2. Why can a MAC not give non-repudiation?

    Both sides hold the same key, so either of them could have made a valid tag, and an auditor cannot tell which did. A signature comes from a private key that only the signer holds, so it can point at one party, although whether it binds the signer is in the end a legal decision, not a mathematical one.

  3. What does Kerckhoffs's principle say, and why does it still hold?

    A cryptosystem must stay secure when everything about it except the key is known, so its security rests on the key alone. Designs leak through shipped apps, repositories and former staff; a leaked key can be replaced in minutes but a leaked design cannot; and a public algorithm has been attacked by many people before you trust it.

  4. A team stores a database password Base64-encoded in a config file so that nobody can read it. What is wrong?

    Base64, hex, compression and obfuscation need no key to undo, so anyone who can read the file decodes it at once. Keep secrets in a secret store such as a key management service or the operating system's keychain, and treat anything inside a shipped app as public.

  5. What are the four lines of a quick threat model?

    What we protect; who might attack and from where; what they can see, change, replay or guess; and what must still hold. Each ability points at a need: reading calls for confidentiality, changing for integrity and authenticity, guessing for enough randomness (ASVS 5.0 asks for at least 128 bits from a secure generator), replaying for a freshness check.

  6. Why does a valid MAC or signature not stop a replayed message?

    A resent copy verifies exactly like the original. The design needs its own freshness rule: a timestamp, a single-use token, or a record of what was already accepted.

  7. A request passes TLS and carries a genuine session token, yet Asha reads Ben's invoice by changing the number in the address. What failed?

    Access control, not cryptography: the handler never asked whether the invoice belonged to the user in the verified session. Check ownership on every request. Encrypting or randomising the invoice number only hides the link, which still works for anyone who sees it.

  8. Name the higher-level choice for each: a cipher plus a MAC you combine yourself; SHA-256 of a password; raw RSA encryption; a home-made secure channel.

    An authenticated cipher (AES-GCM or ChaCha20-Poly1305); a password hash (Argon2id, scrypt, bcrypt or PBKDF2); HPKE or a library's sealed box; TLS 1.3 from the platform. Use the platform's maintained cryptography and its highest-level operation that fits.

Key takeaways

  • Cryptography gives four guarantees: confidentiality, integrity, authenticity and non-repudiation, each from its own tool, and a MAC is not a signature, because both sides hold its key.
  • Base64, hex, compression and obfuscation need no key, so by Kerckhoffs’s principle they hide nothing from someone who knows the design.
  • A four-line threat model (what you protect, who attacks from where, what they can see, change, replay or guess, and what must hold) decides the tool, and replay always needs its own check.
  • Prefer the platform’s maintained cryptography and its highest-level operation: an authenticated cipher, a password hash, TLS, HPKE, a secure random generator.
  • Authorisation, leaked keys, compromised devices and phishing are not cryptographic problems, and encrypting more does not fix them.

Terms in this lesson

confidentiality
The guarantee that information is not disclosed to anyone the owner has not authorised. Encryption gives it; encoding, compression and hashing do not.
cryptographic primitive
A basic building block with one precise job, such as a hash function, a MAC, a cipher or a signature scheme. Protocols such as TLS combine several primitives.
data integrity
The guarantee that data has not been changed without authorisation since it was created, sent or stored. A MAC, an authenticated cipher's tag or a signature detects deliberate changes; a checksum catches only accidents.
Kerckhoffs's principle
The rule that a cryptosystem must stay secure even when everything about it except the key is public, so that its security rests on the key alone.
non-repudiation
Evidence that lets a third party decide whether a given party signed a message. It needs a digital signature from a key that only that party holds, and in the end it is a legal question.
replay
Sending a captured, valid message again. A MAC or a signature still verifies on the copy, so a design needs its own freshness check, such as a timestamp, a nonce or a record of what was accepted.
source authentication
Assurance about who created or sent a piece of data, also called authenticity. A MAC shows that a holder of the shared key made it; a signature shows which private key made it.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.