Skip to content

Security

Encryption Basics

Encryption transforms readable data (plaintext) into unreadable data (ciphertext) using a key, so that only someone with the right key can reverse the process and read it. There are two broad families: symmetric encryption, which uses the same key to encrypt and decrypt, and asymmetric encryption, which uses a mathematically related pair of keys, one public and one private. Hashing is a related but different tool: it turns data into a fixed-size fingerprint that can't be reversed back into the original, which is why it's used for things like verifying passwords rather than protecting data you need to read again later.

Why it matters

It protects data both at rest and in transit
Encrypting a database's contents protects it if the storage is accessed directly; encrypting a network connection, as HTTPS does, protects data as it travels between a browser and a server.
Confusing encryption with hashing is a common, serious mistake
Encrypted data is meant to be decrypted again by someone with the key; a hashed password is never meant to be reversed at all, and using the wrong one for the wrong purpose is a real, recurring vulnerability.
Key management matters more than the algorithm choice
A strong, standard algorithm with a poorly protected key is no safer than a weak algorithm, since the key, not the algorithm, is almost always the actual point of attack in practice.
It underlies authentication and secure communication
TLS, the encryption behind HTTPS, password storage, and signed software updates all rest on the same handful of encryption and hashing primitives applied to different problems.

Symmetric vs asymmetric encryption

Symmetric encryption uses one shared key for both encrypting and decrypting; it's fast, but the key has to reach everyone who needs it without being intercepted along the way, which is a real logistical problem on its own. Asymmetric encryption uses a public key that anyone can encrypt with and a private key, kept secret, that alone can decrypt what was encrypted with its matching public key - it solves the key distribution problem but is far slower. In practice, protocols like TLS use asymmetric encryption briefly, just to agree on a shared secret, and then switch to fast symmetric encryption for the actual data.

Hashing is not encryption

A hash is deliberately one-way: it turns input into a fixed-size value with no operation that turns it back. That makes it useful for checking whether data has changed - comparing hashes instead of full contents - and, importantly, for storing passwords: the server keeps a hash of the password rather than the password itself, and checks a login by hashing the attempt and comparing it to the stored hash. A fast, general-purpose hash designed for integrity checking is the wrong tool for this; password storage needs a deliberately slow, purpose-built hashing function with a unique salt per user, so that guessing passwords by trying billions of hashes offline is impractical.

Python
# WRONG: reversible, and useless if the database leaks
stored_password = encrypt(password, app_key)

# RIGHT: one-way, slow by design, unique salt per user
# (use a vetted library, such as one implementing Argon2 or bcrypt)
stored_hash = password_hashing_library.hash(password)

# checking a login re-hashes the attempt and compares - it never decrypts anything
is_valid = password_hashing_library.verify(stored_hash, attempted_password)

What 'end-to-end encrypted' actually promises

End-to-end encryption means only the two endpoints of a conversation can read the content - not even the service relaying it in between. It doesn't promise that either endpoint is itself secure: a compromised device or a captured screenshot exposes the data regardless of how it was encrypted in transit, and it typically doesn't hide metadata such as who communicated with whom and when.

Mistakes people make here

Storing passwords encrypted instead of hashed
encryption is reversible by design if you have the key, which means anyone with that key, including an attacker who compromises the application, can recover every user's actual password; a proper password hash is designed to never be reversible at all.
Using a fast, general-purpose hash function for passwords
a hash designed for speed, useful for verifying file integrity, lets an attacker who steals the password database try billions of guesses per second offline; password hashing needs a deliberately slow, purpose-built algorithm to make that impractical.
Reusing the same key for everything
if one key is ever exposed, every piece of data it was used to protect is exposed with it; separating keys by purpose limits how much a single leaked key can compromise.
Writing a custom encryption scheme instead of using an established library
correct-looking cryptographic code can still be broken in ways that aren't obvious without deep, specialized review; established libraries and algorithms have had far more scrutiny than a new implementation will get.
Assuming HTTPS means all data is protected end to end
HTTPS encrypts data between the browser and the server it's talking to, but the server itself sees the plaintext; if the requirement is that even the service operator can't read the data, that needs deliberate end-to-end encryption design, not just HTTPS.

Strengths and trade-offs

Where it is strong

  • Well-established algorithms, such as AES for symmetric encryption and RSA or elliptic-curve methods for asymmetric encryption, have withstood decades of public scrutiny, which is a large part of why they're trusted.
  • Combining both families - asymmetric to exchange a key, symmetric for the actual data - gets the security benefit of public-key cryptography without its full performance cost, which is exactly how TLS works.
  • Purpose-built password hashing functions make large-scale offline password guessing impractical even if a password database is stolen, as long as they're configured with adequate cost parameters.

The trade-offs

  • Asymmetric encryption is computationally much slower than symmetric encryption, which is why it's used for small amounts of data, like a key exchange, rather than bulk data.
  • Encryption protects data from being read, but not from being deleted, corrupted, or from the endpoints themselves being compromised directly.
  • Losing a key, with no recovery mechanism, means losing access to the data it protects - encryption's strength, that the key is genuinely necessary, is also its risk.
  • Getting configuration details right, such as key length, mode of operation and salt handling, matters as much as picking the right algorithm family, and is where a lot of real-world mistakes happen.

Who needs this

Every developer benefits from the conceptual distinction between encryption and hashing, and from knowing never to build either from scratch. Choosing specific algorithms, key sizes and configuration is more specialized work, usually guided by a library's or framework's established defaults rather than decided from first principles.

Questions about encryption basics

What's the real difference between encryption and hashing?
Encryption is reversible: with the right key, ciphertext turns back into the original plaintext. Hashing is one-way by design: a hash can't be turned back into the original input at all. That's why passwords are hashed - there should never be a way to recover the original - while, say, a stored file might be encrypted, since you need to read it again later.
Why do secure connections use both symmetric and asymmetric encryption?
Asymmetric encryption solves the problem of securely agreeing on a secret without having met before, but it's too slow for large amounts of data. So protocols like TLS use asymmetric encryption briefly, at the start of a connection, just to agree on a shared symmetric key, then switch to fast symmetric encryption for the actual data, getting the benefits of both.
Is it safe to write my own encryption function?
No, essentially never. Cryptography has an unusually large gap between code that looks correct and code that is actually secure, and mistakes are typically invisible until someone specifically attacks them. Established, widely reviewed libraries and algorithms exist for this reason and should be used instead.
What does 'salting' a password mean?
A salt is random data unique to each password, mixed in before hashing, so that two users with the same password don't produce the same stored hash, and an attacker can't precompute a single table of hashes to crack every account at once. Modern password hashing functions handle salting automatically as part of hashing and verifying.

The primary source

Related concepts

← All concept guides