You do not need the mathematics to use cryptography correctly. You need to know what each primitive promises, and what it does not.
Four promises
- Encryption promises confidentiality. It says nothing about whether the message was altered.
- Hashing promises a fixed fingerprint. It is not encryption and cannot be reversed — but it can be guessed at, which is why passwords need a slow hash.
- Signing promises origin and integrity. It does not hide anything.
- Key exchange promises that two parties end up with a shared secret without sending it.
Most real failures come from using one where another was needed.
The failures you will actually meet
- A password stored with a fast hash such as SHA-256. Fast is the wrong property: use Argon2id or bcrypt, which are slow on purpose.
- Encryption without authentication, so an attacker can alter ciphertext undetected. Use an AEAD mode.
- A key committed to a repository. The algorithm is irrelevant once the key is public.
> Every primitive is a promise about one property. Confusing which is which causes more breaches than broken maths.
What to take away
When you see cryptography in a design, ask what property it is supposed to provide and check that the chosen primitive actually provides it.