Use of Hard-coded Cryptographic Key

Description

Use of Hard-coded Cryptographic Key occurs when software contains a fixed cryptographic key embedded in source code, configuration, or firmware. Unlike hard-coded passwords (CWE-798), this specifically refers to symmetric encryption keys, asymmetric private keys, API signing keys, or any cryptographic material used for encryption, signing, or authentication. These keys cannot be changed without modifying the software and are typically shared across all installations.

Risk

Hard-coded cryptographic keys are extremely dangerous because they completely undermine the security provided by cryptography. If attackers extract the key (through reverse engineering, source code access, or firmware analysis), they can decrypt all data encrypted with that key, forge signatures, or impersonate systems. Unlike passwords, cryptographic keys may be used to protect massive amounts of data or establish trust. Key extraction from a single device compromises all devices using the same key.

Solution

Never embed cryptographic keys in source code or distributed binaries. Use secure key management systems (HSMs, cloud KMS services). Generate unique keys per installation during secure setup. Implement proper key derivation from user-provided secrets. Use environment variables or secure vaults for key storage. For embedded systems, use secure hardware elements (TPM, secure enclave). Implement key rotation procedures. Use asymmetric cryptography where possible to limit key exposure.

Common Consequences

ImpactDetails
ConfidentialityScope: Data Exposure

Attackers can decrypt all data protected with the hard-coded key.
IntegrityScope: Signature Forgery

Hard-coded signing keys allow creation of forged signatures.
AuthenticationScope: System Impersonation

Extracted keys enable impersonation of legitimate systems.

Example Code + Solution Code

Vulnerable Code

# VULNERABLE: Hard-coded encryption key
from cryptography.fernet import Fernet

# Same key in every installation!
ENCRYPTION_KEY = b'your-secret-key-here-32-bytes!!'

def encrypt_data(data):
    cipher = Fernet(ENCRYPTION_KEY)
    return cipher.encrypt(data.encode())

def decrypt_data(encrypted_data):
    cipher = Fernet(ENCRYPTION_KEY)
    return cipher.decrypt(encrypted_data).decode()

# VULNERABLE: Hard-coded JWT signing key
import jwt

JWT_SECRET = "super-secret-jwt-key-12345"  # Hard-coded!

def create_token(user_id):
    return jwt.encode({'user_id': user_id}, JWT_SECRET, algorithm='HS256')

def verify_token(token):
    return jwt.decode(token, JWT_SECRET, algorithms=['HS256'])

# VULNERABLE: Hard-coded API signing key
import hmac
import hashlib

API_SIGNING_KEY = b'api-signing-key-for-all-requests'  # Hard-coded!

def sign_request(data):
    return hmac.new(API_SIGNING_KEY, data.encode(), hashlib.sha256).hexdigest()
// VULNERABLE: Hard-coded AES key in Java
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class VulnerableCrypto {

    // Same key everywhere!
    private static final byte[] AES_KEY = "MySecretKey12345".getBytes();

    public byte[] encrypt(byte[] data) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(AES_KEY, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        return cipher.doFinal(data);
    }

    public byte[] decrypt(byte[] encryptedData) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(AES_KEY, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        return cipher.doFinal(encryptedData);
    }
}

// VULNERABLE: Hard-coded RSA private key
public class VulnerableRSA {

    private static final String PRIVATE_KEY_PEM = """
        -----BEGIN RSA PRIVATE KEY-----
        MIIEpAIBAAKCAQEA0Z3VS5JJcds3xfn/ygWyF8PbnGy...
        -----END RSA PRIVATE KEY-----
        """;

    public byte[] sign(byte[] data) throws Exception {
        // Using hard-coded private key to sign
        PrivateKey privateKey = loadPrivateKey(PRIVATE_KEY_PEM);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(data);
        return signature.sign();
    }
}
// VULNERABLE: Hard-coded key in Node.js
const crypto = require('crypto');

// Same key in all deployments!
const ENCRYPTION_KEY = Buffer.from('0123456789abcdef0123456789abcdef');
const IV = Buffer.from('0123456789abcdef');

function encrypt(text) {
    const cipher = crypto.createCipheriv('aes-256-cbc', ENCRYPTION_KEY, IV);
    let encrypted = cipher.update(text, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    return encrypted;
}

// VULNERABLE: Hard-coded HMAC key
const HMAC_SECRET = 'shared-hmac-secret-key';

function signData(data) {
    return crypto.createHmac('sha256', HMAC_SECRET)
        .update(data)
        .digest('hex');
}

// VULNERABLE: Hard-coded key in config
// config.js (committed to repo!)
module.exports = {
    encryptionKey: 'aes-key-for-all-installations',
    jwtSecret: 'jwt-signing-key-12345',
    apiKey: 'api-key-for-signing'
};

Fixed Code

# SAFE: Key from secure source
import os
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
import base64

def get_encryption_key():
    """Get encryption key from environment variable."""
    key = os.environ.get('ENCRYPTION_KEY')
    if not key:
        raise ValueError("ENCRYPTION_KEY environment variable not set")

    # Validate key length
    key_bytes = base64.urlsafe_b64decode(key)
    if len(key_bytes) != 32:
        raise ValueError("Invalid key length")

    return key

def encrypt_data(data):
    key = get_encryption_key()
    cipher = Fernet(key)
    return cipher.encrypt(data.encode())

# SAFE: Key derivation from master secret
def derive_key(master_secret, salt, purpose):
    """Derive purpose-specific key from master secret."""
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,
        salt=salt,
        iterations=100000,
    )
    return base64.urlsafe_b64encode(kdf.derive(master_secret.encode()))

# Usage: Different keys for different purposes
SALT = os.urandom(16)  # Store salt securely
encryption_key = derive_key(os.environ['MASTER_SECRET'], SALT, 'encryption')
signing_key = derive_key(os.environ['MASTER_SECRET'], SALT, 'signing')

# SAFE: Using AWS KMS
import boto3

def get_key_from_kms():
    """Get data key from AWS KMS."""
    kms = boto3.client('kms')

    # Generate data key encrypted with KMS master key
    response = kms.generate_data_key(
        KeyId=os.environ['KMS_KEY_ID'],
        KeySpec='AES_256'
    )

    # Plaintext key for encryption, encrypted key for storage
    return response['Plaintext'], response['CiphertextBlob']

# SAFE: Per-installation key generation
def initialize_installation():
    """Generate unique key during installation."""
    from cryptography.fernet import Fernet

    # Generate unique key for this installation
    key = Fernet.generate_key()

    # Store in secure location (not in code!)
    store_key_securely(key)

    return key

# SAFE: JWT with key from secure source
import jwt
import os

def get_jwt_secret():
    secret = os.environ.get('JWT_SECRET')
    if not secret or len(secret) < 32:
        raise ValueError("JWT_SECRET must be set and at least 32 characters")
    return secret

def create_token(user_id):
    return jwt.encode(
        {'user_id': user_id},
        get_jwt_secret(),
        algorithm='HS256'
    )
// SAFE: Key from secure source in Java
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;

public class SecureCrypto {

    private final SecretKey secretKey;

    public SecureCrypto() {
        this.secretKey = loadKeyFromSecureSource();
    }

    private SecretKey loadKeyFromSecureSource() {
        // Option 1: From environment variable
        String keyBase64 = System.getenv("ENCRYPTION_KEY");
        if (keyBase64 == null) {
            throw new IllegalStateException("ENCRYPTION_KEY not set");
        }
        byte[] keyBytes = Base64.getDecoder().decode(keyBase64);
        return new SecretKeySpec(keyBytes, "AES");
    }

    public byte[] encrypt(byte[] data) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        byte[] iv = new byte[12];
        new SecureRandom().nextBytes(iv);

        GCMParameterSpec spec = new GCMParameterSpec(128, iv);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec);

        byte[] encrypted = cipher.doFinal(data);

        // Prepend IV to ciphertext
        byte[] result = new byte[iv.length + encrypted.length];
        System.arraycopy(iv, 0, result, 0, iv.length);
        System.arraycopy(encrypted, 0, result, iv.length, encrypted.length);

        return result;
    }
}

// SAFE: Using Java KeyStore
public class KeyStoreManager {

    private final KeyStore keyStore;
    private final char[] password;

    public KeyStoreManager(String keystorePath, char[] password) throws Exception {
        this.password = password;
        this.keyStore = KeyStore.getInstance("PKCS12");

        try (FileInputStream fis = new FileInputStream(keystorePath)) {
            keyStore.load(fis, password);
        }
    }

    public SecretKey getSecretKey(String alias) throws Exception {
        return (SecretKey) keyStore.getKey(alias, password);
    }

    public PrivateKey getPrivateKey(String alias) throws Exception {
        return (PrivateKey) keyStore.getKey(alias, password);
    }
}

// SAFE: AWS KMS integration
import software.amazon.awssdk.services.kms.KmsClient;
import software.amazon.awssdk.services.kms.model.*;

public class KMSKeyManager {

    private final KmsClient kmsClient;
    private final String keyId;

    public KMSKeyManager(String keyId) {
        this.kmsClient = KmsClient.create();
        this.keyId = keyId;
    }

    public DataKeyResult generateDataKey() {
        GenerateDataKeyRequest request = GenerateDataKeyRequest.builder()
            .keyId(keyId)
            .keySpec(DataKeySpec.AES_256)
            .build();

        GenerateDataKeyResponse response = kmsClient.generateDataKey(request);

        return new DataKeyResult(
            response.plaintext().asByteArray(),
            response.ciphertextBlob().asByteArray()
        );
    }

    public byte[] decrypt(byte[] encryptedKey) {
        DecryptRequest request = DecryptRequest.builder()
            .ciphertextBlob(SdkBytes.fromByteArray(encryptedKey))
            .build();

        DecryptResponse response = kmsClient.decrypt(request);
        return response.plaintext().asByteArray();
    }
}
// SAFE: Key from environment in Node.js
const crypto = require('crypto');

function getEncryptionKey() {
    const keyBase64 = process.env.ENCRYPTION_KEY;
    if (!keyBase64) {
        throw new Error('ENCRYPTION_KEY environment variable not set');
    }

    const key = Buffer.from(keyBase64, 'base64');
    if (key.length !== 32) {
        throw new Error('Invalid key length');
    }

    return key;
}

function encrypt(text) {
    const key = getEncryptionKey();
    const iv = crypto.randomBytes(16);

    const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
    let encrypted = cipher.update(text, 'utf8', 'hex');
    encrypted += cipher.final('hex');

    const authTag = cipher.getAuthTag();

    // Return IV + authTag + ciphertext
    return iv.toString('hex') + authTag.toString('hex') + encrypted;
}

// SAFE: Using AWS KMS
const { KMSClient, GenerateDataKeyCommand, DecryptCommand } = require('@aws-sdk/client-kms');

const kmsClient = new KMSClient({ region: 'us-east-1' });

async function generateDataKey() {
    const command = new GenerateDataKeyCommand({
        KeyId: process.env.KMS_KEY_ID,
        KeySpec: 'AES_256'
    });

    const response = await kmsClient.send(command);

    return {
        plaintext: response.Plaintext,
        encrypted: response.CiphertextBlob
    };
}

// SAFE: HashiCorp Vault integration
const vault = require('node-vault')({
    endpoint: process.env.VAULT_ADDR,
    token: process.env.VAULT_TOKEN
});

async function getEncryptionKeyFromVault() {
    const secret = await vault.read('secret/data/encryption');
    return Buffer.from(secret.data.data.key, 'base64');
}

// SAFE: Key generation during setup
async function initializeApplication() {
    // Check if key exists
    try {
        await vault.read('secret/data/encryption');
        console.log('Key already exists');
    } catch (e) {
        if (e.response?.statusCode === 404) {
            // Generate new key
            const key = crypto.randomBytes(32).toString('base64');

            await vault.write('secret/data/encryption', {
                data: { key }
            });

            console.log('Generated new encryption key');
        } else {
            throw e;
        }
    }
}

// SAFE: Configuration template
// config.template.js (committed)
module.exports = {
    encryptionKey: process.env.ENCRYPTION_KEY,
    jwtSecret: process.env.JWT_SECRET,
    hmacKey: process.env.HMAC_KEY
};

// Validation on startup
function validateConfig() {
    const required = ['ENCRYPTION_KEY', 'JWT_SECRET', 'HMAC_KEY'];

    for (const key of required) {
        if (!process.env[key]) {
            throw new Error(`Missing required environment variable: ${key}`);
        }
    }
}

Exploited in the Wild

Mirai Botnet Variants

Many IoT devices have been compromised through extraction of hard-coded encryption keys used for firmware protection and communication.

Gaming Console Hacks

PlayStation and Xbox security has been repeatedly compromised through extraction of hard-coded cryptographic keys.

Industrial Control Systems

SCADA and ICS systems have been found with hard-coded keys, enabling attackers to intercept and forge control commands.


Tools to test/exploit

  • strings — extract embedded strings from binaries.

  • binwalk — firmware analysis.

  • Ghidra — reverse engineering.

  • TruffleHog — scan for embedded secrets.


CVE Examples


References

  1. MITRE. "CWE-321: Use of Hard-coded Cryptographic Key." https://cwe.mitre.org/data/definitions/321.html

  2. OWASP. "Key Management Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Key_Management_Cheat_Sheet.html