In many projects I worked on, especially payment systems and backend services, cryptography was always there. Sometimes very visible, sometimes hidden deep inside libraries or infrastructure. One thing I noticed over the years is that people often talk about keys as if they are all the same. A key is a key, right? Just keep it secret and everything is fine.
That thinking usually leads to problems later.
This article is my attempt to explain key usage in a simple and practical way. I am not trying to sound academic. I am writing this the same way I would explain it to a teammate during a design review or while fixing a security finding. Clear, practical, and sometimes a bit imperfect.
I will focus on four common key usages. Signing keys, encryption keys, MAC keys, and KDF related keys. All explanations are aligned with guidance from NIST SP 800-57, but written in my own words and based on real situations I have seen.
All code examples in this article are not taken from my actual production projects. They are created only to simplify and demonstrate the concepts discussed.
Why key usage matters more than people think
One of the first lessons I learned the hard way is that using the wrong key for the wrong purpose is not a small mistake. It breaks security assumptions.
In one project, we had a single master key used for encrypting data, generating MAC values, and even signing messages between services. On paper, everything worked. The system passed functional testing. But during a security review, this became a big red flag.
NIST SP 800 57 is very clear on this point. A cryptographic key must have a defined purpose, and that purpose should not be mixed with others. When you mix purposes, you increase the impact of a key compromise. You also make formal security analysis almost impossible.
So before we talk about algorithms or key sizes, we must first talk about intent. What is this key supposed to do?
Encryption keys and when to use them
An encryption key is used when you want to keep data confidential. This is probably the most familiar type of key. You encrypt data so that only someone with the correct key can read it.
In simple terms, encryption answers this question. Who is allowed to see this data.
In many backend systems, encryption keys are used to protect data at rest and data in transit. Examples include encrypting card data in a database, encrypting files stored in object storage, or encrypting sensitive fields before sending them to another system.
A very common mistake I have seen is using encryption where integrity or authenticity is actually the real requirement. Encryption alone does not tell you who created the data or whether it was modified. It only hides the content.
According to NIST SP 800 57, encryption keys should be used only for confidentiality. They should not be reused for signing or message authentication. Even if the algorithm technically allows it, the guideline is very clear about separation of usage.
Here is a simple example in C# to illustrate encryption.
using System.Security.Cryptography;
using System.Text;
public static byte[] EncryptData(byte[] key, byte[] plainText)
{
using var aes = Aes.Create();
aes.Key = key;
aes.GenerateIV();
using var encryptor = aes.CreateEncryptor();
var cipherText = encryptor.TransformFinalBlock(plainText, 0, plainText.Length);
return aes.IV.Concat(cipherText).ToArray();
}This key is used only to encrypt and decrypt. Nothing else. That limitation is a good thing.
Signing keys and why they are different
Signing keys are used for authenticity and non repudiation. When you sign something, you are saying this data came from me and was not changed.
In practice, signing keys are often asymmetric keys. One private key for signing and one public key for verification. This is very common in APIs, certificates, and document signing.
In one integration project, we had to verify that requests truly came from a trusted partner. Encryption was not required because the transport was already protected by TLS. What we really needed was proof of origin. That is where signing came in.
NIST SP 800 57 treats signing keys as a very sensitive category. The private signing key must be protected more strictly than many other keys because its compromise allows impersonation.
A key point here is that signing keys should never be used for encryption. Even though both involve cryptography, the security goals are completely different.
Here is a simplified signing example.
using System.Security.Cryptography;
using System.Text;
public static byte[] SignData(RSA privateKey, string message)
{
var data = Encoding.UTF8.GetBytes(message);
return privateKey.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}This key signs data. It does not encrypt. It does not generate MAC values. Its role is very clear.
MAC keys and message integrity
MAC stands for Message Authentication Code. A MAC key is usually a symmetric key shared between two parties. It is used to ensure integrity and authenticity of a message.
In payment systems, MAC keys are everywhere. Host to host messages, ISO messages, settlement files, and even internal service calls often rely on MAC values.
The important thing to understand is that MAC keys are not encryption keys. The message is usually sent in clear form or already protected by another layer. The MAC ensures that the message was not modified and that it came from someone who knows the shared secret.
One issue I encountered before was a system using an encryption key to generate MAC values. It worked technically, but it violated key separation rules and failed compliance review.
NIST SP 800 57 strongly recommends that MAC keys be used only for message authentication. They should not encrypt data and should not derive other keys unless explicitly allowed by design.
A simple example using HMAC is shown below.
using System.Security.Cryptography;
using System.Text;
public static byte[] ComputeMac(byte[] key, string message)
{
using var hmac = new HMACSHA256(key);
return hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
}This key authenticates messages. That is all it does. And that is exactly how it should be.
Key derivation and KDF related keys
Key derivation is often misunderstood. A Key Derivation Function takes one key or secret and derives one or more new keys from it.
The most important rule here is that derived keys should have specific purposes. You do not derive one key and then use it for everything.
In many designs, you start with a master key stored in an HSM or secure vault. From that master key, you derive separate keys for encryption, MAC, or other purposes. This limits the blast radius if a derived key is compromised.
NIST SP 800 57 talks about key hierarchy and derivation in detail. The idea is simple. Higher level keys protect lower level keys. Lower level keys do actual work.
In one project, we derived per transaction keys from a base key. That allowed us to limit exposure and simplify key rotation without re encrypting everything.
Here is a simplified derivation example.
using System.Security.Cryptography;
public static byte[] DeriveKey(byte[] baseKey, byte[] salt)
{
using var kdf = new Rfc2898DeriveBytes(baseKey, salt, 10000, HashAlgorithmName.SHA256);
return kdf.GetBytes(32);
}The derived key should then be labeled and restricted. For example encryption only or MAC only. That label matters in audits and in real security incidents.
Why key separation is not optional
Sometimes developers ask why all this separation is needed. Why not just use one strong key and be done with it.
The answer is risk containment.
If an encryption key is compromised, confidentiality is lost. If a signing key is compromised, trust is lost. If a MAC key is compromised, integrity is lost. Mixing these roles means one incident breaks everything.
NIST SP 800 57 repeatedly emphasizes defining key usage, enforcing it technically, and documenting it clearly. This is not just theory. Auditors look for this. Attackers exploit the lack of it.
From my experience, systems that clearly define key roles are easier to maintain, easier to rotate, and much easier to explain during reviews.
Common mistakes I keep seeing
One mistake is using the same key for encryption and MAC because it is convenient. Another is deriving keys without documenting their purpose. A third is using signing keys for internal encryption just because they already exist.
These issues usually come from rushing or from copying old code without understanding why it was written that way.
Taking time to map keys to purposes saves much more time later.
Closing thoughts
Key usage is not an abstract academic topic. It affects real systems, real data, and real incidents.
If there is one thing I hope you take from this article, it is this. A cryptographic key is defined as much by what it must not do as by what it can do.
Following the guidance of NIST SP 800 57 helped me many times, not just for compliance, but for building systems that are easier to reason about and safer by design.
And finally, a reminder. All example code in this article was created only to simplify the explanation. It does not come from my actual production projects.
If you are designing or reviewing a system today, take a moment to ask one simple question for every key you see. What exactly is this key allowed to do.


