Skip to content

Services, Wiki-Artikel, Blog-Beiträge und Glossar-Einträge durchsuchen

↑↓NavigierenEnterÖffnenESCSchließen

Cryptography: encryption, algorithms, PKI and post-quantum

Cryptography is the technical foundation of IT security. This article explains symmetric and asymmetric encryption (AES, RSA, ECC), hash functions and password hashing (bcrypt, Argon2), digital signatures, PKI hierarchies, TLS 1.3 with specific Nginx configurations, post-quantum cryptography (ML-KEM, ML-DSA), BSI TR-02102 recommendations, and common implementation errors in practice.

Table of Contents (13 sections)

Without cryptography, there is no IT security. HTTPS, password hashing, digital signatures, end-to-end encryption—all of these rely on cryptographic algorithms. "Encryption is secure" is one of the most common misconceptions in computer science: The mathematics behind AES, RSA, or ECC is often indeed secure. The problem lies in the implementation: incorrect modes, weak keys, insecure random numbers, incorrect padding methods.

The Three Fundamental Cryptographic Problems

Cryptography solves three fundamental security problems:

  1. Confidentiality: Only authorized parties can read data (encryption)
  2. Integrity: Data cannot be altered without detection (hash functions, MAC)
  3. Authenticity: The sender’s identity can be verified (digital signatures, certificates)
The three pillars of cryptography:

Symmetric cryptography:
  → Same key for encryption and decryption
  → Fast, but key exchange is the problem
  → Application: Data encryption (AES, ChaCha20)

Asymmetric cryptography (public-key):
  → Key pair: Public key (public) + Private key (secret)
  → Slower, but solves the key exchange problem
  → Application: TLS handshake, digital signatures, email encryption

Hash functions:
  → One-way function: from arbitrary data → fixed length
  → Collision-resistant: no two inputs should have the same hash
  → Applications: Password storage, integrity checks, signatures

Symmetric Encryption

In symmetric encryption, the sender and receiver use the same key for encryption and decryption.

Advantage: Very fast, efficient for large amounts of data. Disadvantage: Key exchange problem—how do you securely transmit the secret key?

AES (Advanced Encryption Standard)

AES is the global standard for symmetric encryption.

Key lengths:
  AES-128: 128 bits—sufficient for most applications (until ~2030)
  AES-192: 192 bits – rarely used
  AES-256: 256 bits – recommended for highly sensitive data, post-quantum secure

Block modes – crucial for security:

ECB (Electronic Codebook) – NEVER USE:
  → Same plaintext → same ciphertext (deterministic)
  → Patterns visible in the plaintext are visible in the ciphertext!
  → Famous example: an encrypted Tux image remains recognizable

CBC (Cipher Block Chaining) – obsolete, prone to errors:
  → IV (Initialization Vector) must be random and unique
  → Vulnerable to padding oracle attacks (POODLE, Lucky Thirteen)
  → Not recommended for new implementations

CTR (Counter Mode) - good, but without authentication:
  → Converts block cipher to stream cipher
  → Nonce MUST be unique (nonce reuse = catastrophic!)
  → No integrity check → Man-in-the-middle possible

GCM (Galois/Counter Mode) - RECOMMENDED:
  → Authenticated encryption: AEAD (Encryption + Integrity)
  → Nonce MUST be unique (96 bits recommended)
  → Standard for TLS 1.3, Signal, WireGuard
  → Nonce reuse attack: If nonce is used twice → complete decryption!

ChaCha20-Poly1305:
  → Alternative to AES-GCM
  → Better on systems without AES hardware acceleration (IoT)
  → Used in TLS 1.3 and Signal Protocol

SIV (Synthetic IV) - for deterministic encryption:
  → When the same data always requires the same result (searchable)
  → Nonce-reuse-resistant

Obsolete/insecure algorithms - do not use anymore:

  • DES / 3DES - Key length too short (56 bits), practically broken
  • RC4 - Known severe weaknesses, prohibited in TLS
# AES-256-GCM in Python (correct usage)
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

def encrypt(key: bytes, plaintext: bytes) -> tuple[bytes, bytes]:
    """Encrypts using AES-256-GCM. Returns (nonce, ciphertext)."""
    aesgcm = AESGCM(key)
    nonce = os.urandom(12)  # 12-byte nonce for GCM (NEVER reuse!)
    ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data=None)
    return nonce, ciphertext

def decrypt(key: bytes, nonce: bytes, ciphertext: bytes) -> bytes:
    """Decrypts and automatically verifies integrity (AuthTag)."""
    aesgcm = AESGCM(key)
    return aesgcm.decrypt(nonce, ciphertext, associated_data=None)

# Generate key (32 bytes = 256 bits)
key = os.urandom(32)
nonce, ct = encrypt(key, b"Secret message")
plaintext = decrypt(key, nonce, ct)
// Node.js (crypto built-in) - AES-256-GCM
const crypto = require('crypto');
const algorithm = 'aes-256-gcm';

function encrypt(plaintext, key) {
  const nonce = crypto.randomBytes(12);
  const cipher = crypto.createCipheriv(algorithm, key, nonce);
  const encrypted = Buffer.concat([
    cipher.update(plaintext, 'utf8'),
    cipher.final()
  ]);
  const tag = cipher.getAuthTag();  // Authentication tag!
  return { nonce, encrypted, tag };
}

function decrypt(nonce, encrypted, tag, key) {
  const decipher = crypto.createDecipheriv(algorithm, key, nonce);
  decipher.setAuthTag(tag);         // Tag MUST be verified!
  return Buffer.concat([
    decipher.update(encrypted),
    decipher.final()
  ]).toString('utf8');
}

Asymmetric Encryption (Public-Key Cryptography)

In asymmetric encryption, there is a key pair:

  • Public Key: Public—anyone can know it and use it to encrypt
  • Private Key: Secret—only the owner has it; only they can decrypt

The genius of it: Both keys are mathematically linked, but the private key cannot be derived from the public key in a reasonable amount of time.

RSA

RSA is based on the difficulty of factoring large numbers.

Key lengths (BSI TR-02102 Recommendation 2024):
  RSA-1024: BROKEN (do not use anymore!)
  RSA-2048: Minimum – acceptable until ~2030
  RSA-3072: Recommended until 2030+
  RSA-4096: Secure in the long term; ECDSA is preferable for TLS!

Applications:
  → Digital signatures (e.g., code signing, PDF signatures, PKI certificates)
  → Key encapsulation (TLS – being replaced by ECDH)

RSA Padding - critical:
  PKCS#1 v1.5: OBSOLETE, vulnerable to Bleichenbacher attack
  OAEP (Optimal Asymmetric Encryption Padding): RECOMMENDED for encryption
  PSS (Probabilistic Signature Scheme): RECOMMENDED for signatures

  # Python - Encrypting with OAEP:
  from cryptography.hazmat.primitives.asymmetric import padding
  from cryptography.hazmat.primitives import hashes

  ciphertext = public_key.encrypt(
    plaintext,
    padding.OAEP(
      mgf=padding.MGF1(algorithm=hashes.SHA256()),
      algorithm=hashes.SHA256(),
      label=None
    )
  )

ECC (Elliptic Curve Cryptography)

ECC offers the same security as RSA with significantly smaller keys.

Comparison:
  RSA-3072 ≈ ECDSA-P256 (256-bit curve)
  RSA-7680 ≈ ECDSA-P384 (384-bit curve)
  Much faster (10–100x), lower computational overhead → good for mobile/IoT

Curves and their properties:
  P-256 (secp256r1):
    → Standard curve for TLS, FIDO2, code signing, Apple, Google
    → Recommended by BSI: "sufficiently secure"
  P-384 (secp384r1):
    → Higher security, recommended for government systems
  Curve25519 (Ed25519 / X25519):
    → By Daniel Bernstein, no NIST specification
    → Considered particularly trustworthy
    → Standard in: Signal, WireGuard, SSH keys
    → Recommended for new systems!

Applications:
  ECDSA: Digital signatures (TLS, Bitcoin)
  ECDH: Key Agreement (Diffie-Hellman on elliptic curves)
  EdDSA: Modern signatures (Ed25519, Ed448)

Generate an SSH key with Ed25519:
  ssh-keygen -t ed25519 -C "user@firma.de"
  # Significantly better than the RSA-2048 default!
# ECDH Key Exchange (Python)
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey

alice_private = X25519PrivateKey.generate()
alice_public = alice_private.public_key()
bob_private = X25519PrivateKey.generate()
bob_public = bob_private.public_key()

# Key Exchange: both derive the same shared secret
alice_shared = alice_private.exchange(bob_public)
bob_shared = bob_private.exchange(alice_public)
assert alice_shared == bob_shared  # True! Without transferring private keys

# Ed25519 for signatures:
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
private_key = Ed25519PrivateKey.generate()
public_key = private_key.public_key()
signature = private_key.sign(message)
public_key.verify(signature, message)  # Raises an exception if invalid

Diffie-Hellman / ECDH

A key exchange protocol, not an encryption algorithm. Enables secure key exchange over an insecure channel.

Perfect Forward Secrecy (PFS): Ephemeral Diffie-Hellman – each session has its own keys. Compromising the long-term key does not compromise past sessions.

Hash Functions

A cryptographic hash function transforms inputs of any size into a fixed-length fingerprint:

Input:                         → Hash (SHA-256, 256 bits)
"Hello"                          → 185f8db32921bd46d35...
"Hello!"                         → d9414818c6cde70b1e2... (completely different!)
"The complete Faust epic..."    → 3a2c981d7e4f8b9c...

Properties:

  • Determinism: Same input → always the same hash
  • One-way function: The input cannot be reconstructed from the hash
  • Collision resistance: Practically impossible to find two different inputs with the same hash
  • Avalanche effect: The slightest change in the input → completely different hash
AlgorithmOutput lengthStatus
MD5128 bitsBroken - Collisions known, never use for security!
SHA-1160 bitsBroken - Google SHAttered 2017 ("Shattered" attack: two PDFs with the same SHA-1)
SHA-256256 bitsSecure, standard, recommended
SHA-384384 bitsSecure, higher security requirements
SHA-512512 bitsSecure, higher security requirements
SHA-3 / KeccakvariableSecure, different construction (sponge function) – backup in case SHA-2 is compromised
Blake2 / Blake3variableVery fast, secure; good for checksums

Applications: File integrity, download checksums, HMAC, digital signatures (hash is signed, not the document), Git commit IDs.

Password Hashing

Cryptographic hashes like SHA-256 are too fast for passwords. An RTX 4090 can compute 100+ billion SHA-256 hashes per second. Instead: Password-specific algorithms with a built-in "work factor":

NEVER: Store passwords as MD5 or SHA-256!
  → Without a salt: Rainbow tables crack them in seconds
  → With a salt, but a fast hash: GPU cracking

Correct password hash algorithms:
  bcrypt:   Cost Factor (2^cost iterations), 72 bytes max, old but solid
            Cost Factor 12 (min.) for new applications
  scrypt:   Memory-hard, resource-intensive, NIST SP 800-132 compliant
  Argon2id: RECOMMENDED - OWASP 2024, PHC winner
            Three variants: Argon2d (GPU-resistant), Argon2i (timing-safe), Argon2id (both)
  PBKDF2:   FIPS-140 compliant, good for compliance requirements
            Iterations: at least 600,000 for SHA-256 (OWASP 2023)

OWASP recommendation for Argon2id:
  Memory:  64 MB minimum (m=65536)
  Time:    3 iterations minimum (t=3)
  Threads: Number of CPU cores (p=4)
# Argon2id (Python - argon2-cffi)
from argon2 import PasswordHasher

ph = PasswordHasher(
    time_cost=3,       # Iterations
    memory_cost=65536, # 64 MB
    parallelism=4,     # 4 threads
    hash_len=32,       # 256-bit output
    salt_len=16        # 128-bit salt
)

hash = ph.hash("MyPassword123!")

try:
    ph.verify(hash, "MyPassword123!")  # True
    if ph.check_needs_rehash(hash):
        hash = ph.hash("MyPassword123!")  # Re-hash with new parameters
except VerifyMismatchError:
    print("Incorrect password!")

Message Authentication Code (MAC)

A MAC combines a message with a secret key to create a proof of integrity:

MAC = HMAC(key, message)

The recipient recalculates the MAC and compares it—if it matches, the message is unaltered and comes from someone with the key. Applications: API signatures (HMAC-SHA256 in OAuth, JWT), TLS record layer.

Digital Signatures

Digital signatures use asymmetric cryptography for authenticity and non-repudiation:

Signing:    Hash(document) + private-key encryption = signature
Verifying: Hash(document) == public-key decryption(Signature) ?

Uses: Code signing, email signatures (S/MIME, PGP), TLS certificates, DKIM.

# GPG signature for software release
gpg --armor --detach-sign myapp-1.2.3-linux.tar.gz
# → myapp-1.2.3-linux.tar.gz.asc (Signature)

# Verification by user
gpg --verify myapp-1.2.3-linux.tar.gz.asc myapp-1.2.3-linux.tar.gz

# Windows Code Signing (signtool)
signtool sign /fd SHA256 /tr http://timestamp.digicert.com \
  /td SHA256 /f mycert.pfx /p password myapp.exe

Public Key Infrastructure (PKI)

The Problem: Who owns a public key? How do I know that the public key of "Deutsche Bank" really belongs to Deutsche Bank?

PKI Solution: A trusted Certificate Authority (CA) issues digital certificates that link public keys to identities and sign them with the CA key.

Root CA (self-signed, offline! Locked in HSM)

Intermediate CA (signed by Root CA)

End-Entity Certificates (signed by Intermediate CA)
  ├── Web Server Certificate (TLS)
  ├── Code Signing Certificate
  ├── Email Certificate (S/MIME)
  └── Client certificate (mTLS)

Why is the Root CA offline?
  → If the Root CA is compromised → all issued certificates are invalid
  → Root CA only for: issuing new Intermediate CAs

TLS process (simplified):

  1. Browser accesses https://bank.de
  2. Server sends certificate
  3. Browser checks: Is the certificate valid? Signed by a trusted CA? Issued for bank.de?
  4. Browser and server negotiate session key (ECDHE)
  5. All further communication encrypted with AES-256-GCM

Certificate types:

  • DV (Domain Validation): Only domain ownership is verified—for small websites
  • OV (Organization Validation): Organization is verified—for businesses
  • Wildcard: *.example.com—applies to all subdomains
  • SAN (Subject Alternative Names): Multiple domains in a single certificate

Certificate Transparency (CT): All TLS certificates must be logged in public CT logs. Monitoring via crt.sh.

TLS - Transport Layer Security

TLS versions:

SSL 2.0 / 3.0: Completely obsolete - never use
TLS 1.0:       Obsolete - POODLE, BEAST attacks
TLS 1.1:       Obsolete - deprecated since 2020
TLS 1.2:       Acceptable with secure cipher suites
TLS 1.3:       RECOMMENDED - faster, more secure, no legacy baggage

TLS 1.3 Improvements:
  ✓ Always forward secrecy (ECDHE/DHE mandatory)
  ✓ No more RSA key transport
  ✓ Weak cipher suites removed (RC4, 3DES, MD5, SHA1)
  ✓ Handshake in 1-RTT (instead of 2-RTT) - faster
  ✓ 0-RTT resumption (but note the risk of replay attacks!)

TLS 1.3 Cipher Suites (only 5 allowed):
  TLS_AES_256_GCM_SHA384         ← Recommended
  TLS_CHACHA20_POLY1305_SHA256   ← Recommended
  TLS_AES_128_GCM_SHA256         ← Minimum
  TLS_AES_128_CCM_8_SHA256       (IoT)
  TLS_AES_128_CCM_SHA256         (IoT)

Secure TLS 1.2 Cipher Suites:
  ECDHE-ECDSA-AES256-GCM-SHA384  ← Perfect
  ECDHE-RSA-AES256-GCM-SHA384    ← Good
  ECDHE-ECDSA-AES128-GCM-SHA256  ← Good

  INSECURE (do not use anymore):
  ECDHE-RSA-AES256-CBC-SHA       ← CBC vulnerable to padding oracle
  DH-RSA-AES256-GCM-SHA384       ← No "E" = no forward secrecy!
  RC4-SHA                        ← RC4 completely broken

Nginx configuration (TLS 1.3 + secure headers):
  ssl_protocols TLSv1.3 TLSv1.2;
  ssl_prefer_server_ciphers off;  # Client determines cipher in TLS 1.3
  ssl_ciphers 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES256-GCM-SHA384';
  ssl_ecdh_curve X25519:secp384r1;
  ssl_session_tickets off;        # Disable session tickets (PFS!)

  add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
  add_header X-Content-Type-Options nosniff;

Test TLS:
  testssl.sh --full https://firma.de
  ssllabs.com/ssltest  (Online, grades A through F)

BSI Recommendation (TR-02102-2):

  • Prefer TLS 1.3, TLS 1.2 acceptable
  • Disable TLS 1.0 and 1.1
  • Secure cipher suites: TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256

Post-Quantum Cryptography

The Quantum Computer Problem:

Shor's algorithm can break RSA and ECC in polynomial time.
A sufficiently powerful quantum computer would:
  → Break RSA-2048 in hours/days (instead of billions of years)
  → Crack ECDSA-P256 similarly quickly

"Harvest Now, Decrypt Later":
  → Attackers collect encrypted communications today
  → Decrypt them as soon as quantum computers become available
  → Timeframe: cryptographically relevant quantum computers ca. 2030–2035
  → For data sensitive in the long term: Evaluate PQC NOW!

NIST PQC Standards (finalized in 2024):
  ML-KEM (CRYSTALS-Kyber):  Key Encapsulation Mechanism - replaces RSA/ECDH in TLS
  ML-DSA (CRYSTALS-Dilithium): Digital signatures - replaces RSA/ECDSA
  SLH-DSA (SPHINCS+):        Hash-based signatures, conservative backup

BSI Recommendation (TR-02102-1):
  → Starting in 2025: Hybrid cryptography (classical + PQC)
  → By 2030 at the latest: Complete migration to PQC
  → Classified data: IMMEDIATELY use hybrid cryptography
  → Crypto-agility as a design principle: Interchangeable algorithms

TLS 1.3 + PQC (already supported by Chrome):
  X25519MLKEM768 - Hybrid curve (X25519 + ML-KEM-768)
  → Already active in Chrome 131+ and Firefox 132+

OpenSSH and Kyber: hybrid ECDH + Kyber starting with OpenSSH 9.0!

BSI Recommendations for Algorithms and Key Lengths

The BSI regularly publishes Technical Guideline TR-02102 with specific recommendations:

MethodRecommendationMinimum Key Length
Symmetric (AES)RecommendedAES-128 (normal), AES-256 (enhanced)
HashSHA-256 and above256 bits
RSAAcceptable2000 bits (until 2026), 3000 bits thereafter
ECDH/ECDSARecommended256 bits (P-256 or Brainpool)
Post-QuantumRecommended for new systemsML-KEM-768+

Common Implementation Errors

Most Common Cryptography Errors (OWASP A02:2021):

Error 1: Developing Custom Cryptography
  WRONG: Implementing a custom AES mode
  RIGHT: Using established libraries (OpenSSL, libsodium, cryptography)

Error 2: Outdated Algorithms
  MD5, SHA-1, DES, 3DES, RC4 → all broken or too weak
  TLS 1.0, TLS 1.1 → disable!

Mistake 3: Poor key management
  → Hardcoded keys in the source code
  → Same key for encryption and signing
  → Keys never rotated
  Solution: HSM, Vault, AWS KMS, Azure Key Vault

Mistake 4: Incorrect password hashing
  → MD5/SHA-1 with or without salt
  → PBKDF2 with too few iterations
  Solution: Argon2id with OWASP parameters

Error 5: Nonce/IV reuse
  → Nonce used twice in AES-GCM → complete decryption possible!
  Solution: os.urandom() for every encryption operation

Error 6: Ignoring side-channel attacks
  → Timing attacks during string comparison
  WRONG:  if stored_token == provided_token
  CORRECT: hmac.compare_digest(stored_token, provided_token)

Error 7: Random number errors
  Python: random.random() → NOT cryptographically secure!
  Java:   Math.random()   → NOT cryptographically secure!
  JS:     Math.random()   → NOT cryptographically secure!
  Correct:
  Python:   secrets.token_bytes(32)
  Java:     SecureRandom.getInstanceStrong()
  Node.js:  crypto.randomBytes(32)
  Go:       crypto/rand.Read()

Conclusion

Cryptography is the foundation of every IT security architecture. Without properly implemented encryption, even perfectly configured firewalls and access systems are ineffective if the transmitted or stored data is in plain text. The most important practical implications: TLS 1.3 everywhere, AES-256-GCM for data storage, SHA-256 for integrity, Argon2id for passwords—and early planning for the migration to post-quantum cryptography.

Sources & References

  1. [1] NIST Post-Quantum Cryptography Standardization - NIST
  2. [2] BSI: Kryptographische Verfahren - Empfehlungen und Schlüssellängen TR-02102 - BSI
  3. [3] RFC 8446 - TLS 1.3 - IETF
  4. [4] OWASP Cryptographic Storage Cheat Sheet - OWASP

Questions about this topic?

Our experts advise you free of charge and without obligation.

Free Consultation

About the Author

Jan Hörnemann
Jan Hörnemann

Chief Operating Officer · Prokurist

E-Mail

M.Sc. Internet-Sicherheit (if(is), Westfälische Hochschule). COO und Prokurist mit Expertise in Informationssicherheitsberatung und Security Awareness. Nachwuchsprofessor für Cyber Security an der FOM Hochschule, CISO-Referent bei der isits AG und Promovend am Graduierteninstitut NRW.

11 Publikationen
ISO 27001 Lead Auditor (PECB/TÜV) T.I.S.P. (TeleTrusT) ITIL 4 (PeopleCert) BSI IT-Grundschutz-Praktiker (DGI) Ext. ISB (TÜV) BSI CyberRisikoCheck CEH (EC-Council)
This article was last edited on 08.03.2026. Responsible: Jan Hörnemann, Chief Operating Officer · Prokurist at AWARE7 GmbH. License: CC BY 4.0 - free use with attribution: "AWARE7 GmbH, https://a7.de"

Cookielose Analyse via Matomo (selbst gehostet, kein Tracking-Cookie). Datenschutzerklärung