DEV Community

Michael Carter
Michael Carter

Posted on

Your Code Is More Cryptographic Than You Think: Designing Applications for Algorithm Agility


It is usually encountered through a library call, a TLS configuration, an authentication framework, a certificate, or a cloud service. The implementation works, the tests pass, and the application moves toward production.

The problem appears later.

An algorithm needs to be replaced. A certificate hierarchy changes. A cryptographic library reaches end of life. A vulnerability affects a primitive. A vendor introduces a new security requirement. Or the organization begins preparing for post-quantum cryptography.

Suddenly, something that looked like a small security change becomes an application modernization project.

This happens because cryptography is often more deeply coupled to software than developers realize.

The solution is not to predict which algorithm will remain dominant for the next several decades.

It is to design applications so that cryptographic mechanisms can be replaced without rewriting the application around them.

That is the core idea behind cryptographic agility.

Cryptography Doesn't Stay Inside the Crypto Module

A traditional architecture might make cryptography look like a small component:

Application
    |
    v
Crypto Library
    |
    v
Encryption / Signing
Enter fullscreen mode Exit fullscreen mode

Modern applications are rarely that simple.

A cloud-native application could have:

                    Internet
                       |
                       v
                      CDN
                       |
                       v
                 Load Balancer
                       |
                       v
                  API Gateway
                       |
                       v
                  Service Mesh
                       |
            +----------+----------+
            |          |          |
            v          v          v
         Service A  Service B  Service C
            |          |          |
            +----------+----------+
                       |
                       v
                    Database
Enter fullscreen mode Exit fullscreen mode

Cryptography can appear at nearly every layer.

TLS protects network connections.

mTLS authenticates services.

Certificates establish machine identities.

Tokens may be digitally signed.

Databases may encrypt stored information.

KMS platforms manage encryption keys.

HSMs may protect high-value private keys.

CI/CD systems may use signing credentials.

Container registries may depend on cryptographic verification.

The application may therefore depend on dozens of cryptographic mechanisms without having a single component named cryptography.

That is the first problem developers need to understand.

The Hidden Dependency Problem

Consider a simple requirement:

"We need to replace RSA with a different cryptographic mechanism."

At first glance, the task might appear straightforward.

Search the codebase for RSA.

Replace the relevant library calls.

Run the tests.

Deploy.

But what if RSA is also being used by:

  • A TLS termination layer
  • An internal certificate authority
  • A Java dependency
  • A container image
  • A signing service
  • A third-party SDK
  • A deployment platform
  • An HSM
  • An identity provider

The application source code may contain only a small portion of the actual dependency.

This is why a source-code search is not a complete cryptographic inventory.

A useful inventory needs to connect:

Application → Protocol → Certificate → Key → Algorithm → Library → Provider → Infrastructure

Without those relationships, developers may know what cryptography exists but not what depends on it.

Hard-Coded Algorithms Create Long-Term Coupling

Hard-coded algorithms are not necessarily insecure.

The problem is that they create change resistance.

Imagine an application with this architecture:

Application
     |
     v
RSA
     |
     v
Specific Crypto Library
     |
     v
Specific Key Format
     |
     v
Certificate
Enter fullscreen mode Exit fullscreen mode

The application has effectively made several assumptions:

  • Which algorithm is used
  • Which library implements it
  • Which key type is expected
  • Which certificate format is accepted
  • Which provider handles cryptographic operations

Changing the algorithm may therefore require changing multiple layers.

A more flexible architecture looks different:

Application
     |
     v
Cryptographic Interface
     |
     v
Policy / Configuration
     |
     +----------+
     |          |
     v          v
Provider A   Provider B
     |          |
     v          v
Algorithm X  Algorithm Y
Enter fullscreen mode Exit fullscreen mode

Now the business logic does not need to understand every cryptographic implementation.

The application asks for an operation.

The cryptographic layer determines how that operation should be performed.

This separation is one of the foundations of cryptographic agility.

Don't Build an "Algorithm Abstraction" That Isn't Actually Agile

Developers sometimes create an abstraction that simply wraps one algorithm.

For example:

encrypt(data)
Enter fullscreen mode Exit fullscreen mode

may internally always call:

AES-256-GCM
Enter fullscreen mode Exit fullscreen mode

That is an API abstraction, but it does not necessarily provide cryptographic agility.

A genuinely adaptable design needs to separate the operation from the cryptographic policy.

For example:

encrypt(data, policy)
Enter fullscreen mode Exit fullscreen mode

where the policy determines:

Algorithm
Key Type
Key Source
Provider
Parameters
Rotation Policy
Enter fullscreen mode Exit fullscreen mode

The exact implementation depends on the language and framework, but the architectural principle remains the same.

The application should not have to know why a particular cryptographic implementation was selected.

Post-Quantum Cryptography Makes This More Important

Post-quantum cryptography provides a practical example of why cryptographic agility matters.

NIST has standardized ML-KEM for key establishment and ML-DSA and SLH-DSA for digital signatures. These algorithms are designed to address cryptographic threats posed by sufficiently capable quantum computers.

But migrating an application is not equivalent to replacing a class name in a dependency file.

A developer needs to know what the cryptographic operation actually does.

For example:

Key establishment and digital signatures are different problems.

ML-KEM is designed for key establishment.

ML-DSA and SLH-DSA are designed for digital signatures.

An application that currently uses RSA may use it for signatures, key transport, or other operations. An application using elliptic curve cryptography may use different mechanisms for signatures and key agreement.

The migration path therefore depends on how the existing cryptography is being used, not simply which algorithm name appears in the code.

Certificates Add Another Layer

Application developers often treat certificates as infrastructure.

From an application architecture perspective, however, certificates can be hard dependencies.

Consider:

Application
    |
    v
TLS Library
    |
    v
Leaf Certificate
    |
    v
Intermediate CA
    |
    v
Root CA
    |
    v
Trust Store
Enter fullscreen mode Exit fullscreen mode

Changing the certificate can affect every layer below it.

A new certificate may require a new key type.

A new certificate chain may require updated trust.

A new signature algorithm may require newer TLS or X.509 implementations.

A legacy client may not understand the new chain.

This is why certificate management and application architecture cannot be completely separated during a large cryptographic migration.

The modern web already depends heavily on certificate-based encrypted communication. Recent HTTPS adoption statistics show how deeply TLS has become embedded into Internet infrastructure.

For developers, the takeaway is simple:

Certificates are dependencies, not just deployment artifacts.

Libraries Are Part of Your Cryptographic Supply Chain

A developer may never directly implement RSA, ECDSA or AES.

Instead, the application might depend on:

Application
   ↓
Framework
   ↓
HTTP Client
   ↓
TLS Library
   ↓
Operating System
   ↓
Cryptographic Provider
Enter fullscreen mode Exit fullscreen mode

The cryptographic implementation is several abstraction layers away.

This is why dependency management becomes particularly important during cryptographic migration.

An application may need to evaluate:

  • Which crypto library is being used?
  • Which version?
  • Which algorithms does it support?
  • Which providers does it rely on?
  • Is the implementation maintained?
  • Does the platform support newer cryptography?
  • Can the library support multiple algorithms simultaneously?
  • What happens when the dependency is upgraded?

A software bill of materials can help identify software dependencies.

A Cryptography Bill of Materials (CBOM) extends that thinking toward cryptographic components and relationships. IBM Research has discussed CBOM as a way to identify and manage cryptographic assets as organizations prepare for quantum-safe migration.

For large applications, that additional visibility can become extremely valuable.

Crypto Agility Should Be a Developer Requirement

Cryptographic agility should not live exclusively inside the security team's documentation.

It should influence application design.

Developers can ask several questions during architecture reviews:

Can the algorithm be changed without changing business logic?

If changing the cryptographic primitive requires rewriting application workflows, the abstraction boundary may be too low.

Can keys be replaced without redeploying the entire application?

Key lifecycle should ideally be separated from application lifecycle where practical.

Can the cryptographic provider change?

Applications tightly coupled to one provider can become difficult to migrate.

Can certificates be rotated automatically?

Manual certificate replacement becomes increasingly difficult as environments scale.

Can cryptographic policy be changed centrally?

Centralized policy can reduce inconsistent configurations across services.

These questions are more valuable than simply asking whether an application "uses strong encryption."

Avoid Cryptographic Configuration Scattered Across the Codebase

One of the easiest ways to accumulate cryptographic debt is to distribute cryptographic configuration throughout the application.

For example:

Service A → RSA
Service B → ECDSA
Service C → RSA
Service D → hard-coded AES configuration
Service E → library default
Enter fullscreen mode Exit fullscreen mode

Now imagine introducing a new organization-wide cryptographic policy.

Every service becomes a separate migration project.

A better architecture centralizes policy where appropriate:

                    CRYPTO POLICY
                         |
          +--------------+--------------+
          |              |              |
          v              v              v
       Service A      Service B      Service C
          |              |              |
          +--------------+--------------+
                         |
                         v
                CRYPTO PROVIDER
Enter fullscreen mode Exit fullscreen mode

This doesn't mean every cryptographic operation should be centrally controlled.

Some applications require specialized behavior.

The important principle is to avoid unnecessary duplication of cryptographic decisions.

Key Management Should Be Separated From Application Logic

Another common architectural mistake is allowing applications to manage sensitive keys directly.

Instead of:

Application
    |
    v
Private Key
    |
    v
Cryptographic Operation
Enter fullscreen mode Exit fullscreen mode

a stronger architecture often looks like:

Application
    |
    v
KMS / HSM Interface
    |
    v
Protected Key
Enter fullscreen mode Exit fullscreen mode

The application requests a cryptographic operation without necessarily handling the underlying private key.

This architecture can make key rotation, access control, auditing and future migration easier.

It also reduces the number of systems that directly handle sensitive key material.

What Developers Should Inventory

A practical developer-focused cryptographic inventory can start with seven categories:

Category Examples
Algorithms RSA, ECDSA, AES, SHA-2
Protocols TLS, mTLS, SSH, IPsec
Keys Private keys, symmetric keys, signing keys
Certificates TLS, client authentication, code signing
Libraries OpenSSL, BoringSSL, language crypto APIs
Providers KMS, HSM, cloud cryptographic services
Applications APIs, services, workloads, devices

The goal is not to create documentation that nobody maintains.

The goal is to make cryptographic dependencies discoverable and actionable.

Automation should eventually feed this inventory.

Build for Replacement, Not Prediction

One mistake organizations can make is trying to predict exactly which cryptographic algorithm they will use decades from now.

That is difficult.

Cryptography changes.

Standards evolve.

Implementation vulnerabilities appear.

Hardware capabilities change.

New algorithms emerge.

Instead of trying to predict the final destination, application architecture should make the journey easier.

That means designing systems around replaceable cryptographic components.

Think:

Crypto Interface

rather than:

RSA Interface

Think:

Key Management Service

rather than:

Private Key File

Think:

Certificate Policy

rather than:

Certificate Embedded in Configuration

Think:

Algorithm Configuration

rather than:

Algorithm Hard-Coded in Business Logic

These small architectural decisions can have a significant impact years later.

A Practical Crypto-Agility Checklist

Before introducing a new cryptographic dependency, developers should consider:

  • Is the algorithm configurable?
  • Is the implementation isolated behind an interface?
  • Can keys be rotated independently?
  • Can certificates be replaced without application changes?
  • Can the cryptographic provider be changed?
  • Is the dependency actively maintained?
  • Can the application support multiple cryptographic configurations?
  • Is the cryptographic configuration observable?
  • Can the dependency be discovered automatically?
  • Is there a migration path if the algorithm becomes deprecated?

These questions turn cryptographic agility from a theoretical concept into an engineering practice.

The Biggest Mistake Is Waiting for the Migration

Cryptographic agility is easiest to introduce before it is urgently required.

Trying to redesign cryptographic dependencies during a security incident or mandatory migration is much more expensive.

The organization then has to discover dependencies, design an abstraction, test new implementations, replace certificates, coordinate infrastructure and maintain production availability at the same time.

Doing the architectural work earlier changes the problem.

Instead of:

"How do we replace everything?"

the question becomes:

"Which cryptographic provider and policy should we deploy next?"

That is a much more manageable engineering problem.

Cryptographic Agility Is Part of Modern Software Architecture

The next generation of applications will not be defined only by how strong their encryption is.

They will also be defined by how adaptable their cryptographic architecture is.

Post-quantum migration is making this increasingly obvious.

RSA and ECC will not simply disappear overnight. Applications will operate through a period where classical and post-quantum mechanisms coexist, infrastructure will evolve at different speeds, and compatibility will remain an important engineering constraint.

The applications that handle this transition most effectively will be the ones that have already separated business logic from cryptographic implementation.

Cryptography should therefore be treated like any other infrastructure dependency that can evolve.

Make it observable.

Make it configurable.

Make it replaceable.

Automate its lifecycle.

And most importantly, don't assume today's cryptographic implementation will still be the right implementation tomorrow.

The best time to design for cryptographic agility is before the next cryptographic migration becomes mandatory.

Top comments (0)