Cryptography for Software Developers
In this post I'll provide software developers with what I think is necessary information regarding cryptography and security.
Hey folks, I am back, officially this time. Thank you for bearing with me during the absence. But I am back and better than ever.
Today we’ll be taking a look at core cryptography knowledge that I consider essential for software developers.
Before starting, once again, I’d like to thank all of you for tuning in. If you’re new here, please consider subscribing, it allows me to really feel like you want more of this.
What is Cryptography?
Cryptography, plain and simple, is the study and practice of hiding information so that only the intended recipient can read the message. Cryptography revolves around four pillars:
Confidentiality: Ensuring only the intended recipient can read the data.
Integrity: Ensuring data has not been tampered with.
Authentication: Verifying the identity of parties involved.
Non-Repudiation: Preventing someone from denying they performed an action (e.g., signed a document).
Cryptography is everywhere in the digital world, from encrypting WhatsApp messages to ensuring your credit card numbers remain confidential and secure.
Terms
Plaintext (PT): the unencrypted text. Just regular text, like what you’re reading.
Ciphertext (CT): the encrypted counterpart to PT. For example: 1238B45E5AF8E88324699CC6BD9B6DB2 which is the AES-256 representation for “Hello, World”
Hash/Digest: A fixed-size fingerprint of data (e.g., SHA-256 hashes "Hello World" to d2a84f4b8b650937ec8f73cd8be2c74add5a911ba64df27458ed8229da804a26).
The Basics
Let’s start with the basics. In this section we’ll discuss symmetric vs asymmetric cryptography.
Symmetric Cryptography
Symmetric cryptography is cryptography that uses the same key for encryption and decryption, hence the classification symmetric.
For symmetric cryptography two, or more, communicating parties know the shared secret (the key). An example of a symmetric key algorithm is AES (Advanced Encryption Standard). Symmetric Cryptography offer speed of encryption, efficiency over large amounts of data, and confidentiality.
Symmetric cryptographic algorithms can be further split into two categories:
Block Ciphers
Stream Ciphers:
Block Ciphers
As the name suggests, block ciphers encrypt blocks of bits at a time. For example, AES has a block size of 128 bits. That means that the AES algorithm breaks an input into chunks of 128 bits when encrypting. Block ciphers are very prominent in internet applications such as TLS/SSL (HTTPS), VPN, and BitLocker are some examples.
Other popular block ciphers include Triple DES (3DES) and BlowFish both with a block size of 64 bits.
Note: Block size is entirely separate from key size. Block size is a fixed-size chunk of data that a cipher processes in every encryption / decryption operation.
Stream Ciphers
Stream ciphers operate on a stream of bits, thus, these ciphers encrypt bits/byte one at a time, individually. Stream ciphers are used heavily in real-time scenarios such as, real-time communication such as VoIP (Voice-over-IP) and mobile communications. Since these ciphers are lightweight they’re perfect for resource-constrained environments.
An example of a stream cipher, a very important example, is the One-Time Pad (OTP). The importance here lies in the fact that a OTP is mathematically unbreakable, when used correctly. This is because the ciphertext provides absolutely no information about the plaintext if the key is unknown.
Asymmetric Cryptography
Asymmetric cryptography is also known by its much more popular pseudonym …public-key cryptography, this is what I’ll use moving forward. Public-Key Cryptography, when compared to Symmetric Cryptography, offer better security and robustness (offers confidentiality, authenticity, and non-repudiation). However, these algorithms are much more resource intensive making it slower than symmetric cryptography. Public-Key Cryptography also greatly simplifies the key exchange process, removing the need to share a single secret key.
In Public-Key Cryptography, a pair of keys are used. One of the keys, the public key, is not a secret, it can be shared with anyone. The other key, the private key, is the user’s secret that does not get shared with anyone. There is a mathematical relationship between the two keys, however, given a key one cannot derive the other part of the pair (it’s mathematically infeasible). Very common example of a public-key algorithm is RSA (Rivest-Shamir-Adleman).

One of the most important aspects of Public Key Cryptography is the fact that it greatly simplifies key distribution. No longer does one need to share secrets via a secure channel. The presence of two keys (one public and one private) builds the basis for digital signatures.
As mentioned earlier, public-key cryptography is slower than it’s counterpart (symmetric cryptography) but another con is that it requires much larger key sizes to achieve comparable security. For example, when comparing RSA and AES, RSA needs a key size of 15360 bits to achieve the same level of security as 256 for AES.

Hashes and Digests
Sometimes rather than completely encrypting data we just need to verify its integrity, a quick and simple way of doing so is using hashes. Hashes and digest are used pretty interchangeably, they both refer to the result of applying a cryptographic hash function to a piece of data (file, text, etc). The point of the hash/digest is to create a “fingerprint” of sorts for the input data that allows us to track the integrity of the message, to make sure it has not been tampered with.
So we mentioned a cryptographic hash function above, but what is that? Basically a cryptographic hash function, referred to simply as a hash function, is a one-way function that produces a fixed size output. Hash functions have two really important properties to them: they’re one way and they’re collision resistant.
One Way: it should be computationally infeasible (basically impossible) to get the original data from the hash value.
Collision-Resistant: it should be computationally infeasible (basically impossible) to find two pieces of data that map to the same hash value.
I mentioned above that hashes are great at verifying data integrity, lets give a few examples of that to better understand the role of hashes/message digests:
Software Distribution: you may have noticed when downloading a new piece of software often times you’re provided with something called the “SHA” of that distribution.
Data Backups: verifying that backups haven’t been tampered with.
Storing Passwords: passwords aren’t stored in plaintext, for obvious reasons, instead they are hashed and the hashed value is stored. This ensures that even if the password database is hacked/compromised the passwords themselves are not.
Commit Identification: if you use Git (a version-control system) you’ll notice random alphanumeric characters representing the commits. Git uses a hash to identify the commit.
There are many hash functions available, some more popular than others. Examples include: MD5, SHA-1, SHA-256, BLAKE-2, etc.
Hashes and digest also make the foundation for crypto currencies. They’re crucial in ensuring integrity, security and trust. In an earlier post, we talked about Merkle Trees and their applications, remember Merkle Trees rely on the concept of hashes to be able to verify transactions. This extends beyond just proof of transactions, with hashes/digests, crypto currencies add functionality like Proof of Stake, data integrity, and digital signatures.
Note: Please don’t use MD5 and SHA-1 they are weak hashes.
Message Authentication Codes and Signatures
I mentioned above that if we wanted to simply check the integrity of a message we could use a hash function. But what if we wanted to make sure that the message was authentic, the sending party is who they say they are? This is where message authentication codes (MACs) come into play. Think of a MAC as the digital fingerprint of the message, it’s unique to that message (and the shared secret key). Formally, a message authentication code (MAC) is a cryptographic technique used to verify both the integrity and authenticity of the message. Remember, authenticity relates to the sending and receiving parties, so a MAC not only makes sure that the message has not been tampered with but also provides verification of the two parties involved.
So how do MACs work? Well before anything, step 0 if you will, the sender and receiver need to share a secret key beforehand. This key is crucial for verification. Once that’s taken care of we can generate the MAC.

Once the secret key is shared, when sending a message the sending party generates a MAC of the message and includes it in the transmission. Once the receiving party receives the message, they would also generate a MAC of the message and compare it to the accompanying MAC. If the MACs match everything proceeds as normal, otherwise the message gets rejected.
Digital signatures are basically the same thing. Instead of a shared secret key the senders private key is used for signing, as we know the senders private key can be verified by the senders public key. Basically, digital signatures are for asymmetric cryptography whereas MACs are for symmetric cryptography.
Tips, Reminders & Resources
Please DO NOT roll your own crypto algorithm beyond for fun. If you’re using crypto algorithms for production applications please use current best practices. Check out NIST Standards, as well as, Cryptographic Right Answers.
Please DO NOT use outdated or weak algorithms.
Utilize OWASP Top 10s and OWASP Cheat Sheets.
That’s all I have today. Thank you for reading through the entire post. Hopefully I was able to teach you something new about the ever-evolving and extremely important field of cryptography.
If you liked the post please like, share, and subscribe. Please share your thoughts on the post.
My next post will start the Distributed Systems series. I’ll see you there.
Ali