Android System Design Interview Questions
What is the difference between hashing, encrypting and encoding?
Tier: CommonDifficulty: Easy
The difference is whether the transformation can be reversed, and if so, who's allowed to reverse it.
- Encoding changes the format of data so a different system can read it, and it's meant to be reversed by anyone, no secret required. Base64 turning binary image data into ASCII text for a JSON payload is encoding. Decoding it back is a public, documented operation.
- Encrypting transforms data so it can only be read back by someone holding the right key. It's reversible, but only with that key. This is what you use for data you need to get back later in its original form, a token stored on disk, a message in transit.
- Hashing is one way. It produces a fixed size digest from any input, and there's no key that turns the digest back into the original data. The same input always produces the same digest, which is what makes it useful for checking that data hasn't changed.
One thing to state carefully, because interviewers listen for it. Collisions have to exist. The digest is a fixed size and the input isn't, so there are more possible inputs than there are digests. What a good hash guarantees is not that collisions are impossible, it's that finding two inputs with the same digest is computationally infeasible. That's precisely what MD5 and SHA-1 stopped guaranteeing, so they're finished for anything security related and survive only as checksums against accidental corruption. Reach for SHA-256 or better.
A bare hash can detect a change relative to a trusted expected digest, but does not authenticate who sent the data. If the question is whether a payload really came from your server, the answer is an HMAC, a hash with a shared secret key mixed in, so only a holder of that key could have produced the tag.
The password case is the one that trips people up. An authentication backend normally stores a password verifier rather than a recoverable password. It hashes the password, but not with a general purpose hash. You hash it with a per user salt, so two people who chose the same password get different stored values and a precomputed table is useless, and you use a function deliberately built to be slow and memory hungry, Argon2id first, scrypt or bcrypt if that's what the platform gives you. A fast hash is exactly what an attacker with a stolen table wants, because a single GPU will try billions of SHA-256 guesses a second.
Encoding was never about security at all. Base64 keeps no secret and anyone decodes it in one line, so using it to hide sensitive data is a real and common mistake worth calling out. On Android the split shows up in the packages themselves. MessageDigest and Mac come from the security libraries, and Base64 sits in android.util next to the other formatting helpers, which is a fair statement of what it is.
How I'd build this on Android
I'd put security operations in a separate component that the repository receives through its constructor. The ViewModel should not select algorithms or manage keys. A DAO can store encrypted data and the details needed to decrypt it. Compose gets only the decrypted values it needs to display.
fun contentDigest(bytes: ByteArray): ByteArray =
MessageDigest.getInstance("SHA-256").digest(bytes)
fun transportText(bytes: ByteArray): String =
Base64.encodeToString(bytes, Base64.NO_WRAP)
These examples produce a digest and an encoding. Neither example encrypts storage. A file digest only helps if the expected digest comes from a trusted source. If an attacker replaces both the file and digest, they still match. A verified signature or authenticated connection can establish where the data came from. Putting the same secret HMAC key in every APK does not hide it from people who have the APK.
A login service normally stores a slow, salted password verifier, while the Android app avoids keeping the password after login. A password manager has a different requirement because it must recover the saved password. For private data that must be recovered, I'd use authenticated encryption, a unique nonce for each encryption and Keystore protection where appropriate. Base64 provides no protection.
I'd check these cases.
- Corrupt data.
- A wrong key.
- Nonce handling.
- Key loss.
- Logout cleanup.
Logs must not expose decrypted data or keys. See Android cryptography guidance.
Read more Cryptography (opens in a new tab)