Verwendung hartcodierter, sicherheitsrelevanter Konstanten

Beschreibung

Verwendung hartcodierter, sicherheitsrelevanter Konstanten ist eine Schwachstelle, bei der ein Produkt hartcodierte Konstanten anstelle von konfigurierbaren Werten für sicherheitskritische Parameter verwendet. Dies umfasst hartcodierte kryptografische Schlüssel, Salts, Initialisierungsvektoren, Algorithmus-Identifikatoren, Iterationszähler, Schlüsselgrößen, Timeout-Werte und andere sicherheitsrelevante Parameter. Wenn diese Werte direkt im Code eingebettet sind, werden sie schwer zu ändern, können durch Reverse-Engineering offengelegt werden und erzeugen Konsistenzprobleme zwischen Deployments, wo unterschiedliche Sicherheitskonfigurationen benötigt werden könnten.

Risiko

Hartcodierte Sicherheitskonstanten erzeugen erhebliche Schwachstellen. Im Code eingebettete kryptografische Schlüssel können durch Reverse-Engineering, Dekompilierung oder Quellcode-Lecks extrahiert werden und kompromittieren alle Systeme, die diesen Schlüssel verwenden. Hartcodierte Salts eliminieren den Einzigartigkeitsvorteil, den Salts bieten, und machen Rainbow-Table-Angriffe machbar. Feste Iterationszähler können mit zunehmender Rechenleistung unzureichend werden, können aber ohne Codeänderungen nicht aktualisiert werden. Hartcodierte Timeouts können für verschiedene Deployment-Umgebungen unangemessen lang oder kurz sein. Wenn Sicherheitskonstanten entdeckt werden, erfordert ihre Änderung Code-Updates, Tests und Deployment anstelle einfacher Konfigurationsänderungen, was zu verzögerten Reaktionen auf Sicherheitsvorfälle führt.

Lösung

Externalisieren Sie alle sicherheitsrelevanten Konstanten in Konfigurationsdateien, Umgebungsvariablen oder sichere Parameterspeicher. Verwenden Sie Schlüsselverwaltungssysteme für kryptografische Schlüssel. Generieren Sie einzigartige Salts pro Operation anstelle fester Werte. Machen Sie Iterationszähler und Schlüsselgrößen konfigurierbar mit sicheren Standardwerten. Speichern Sie Sicherheits-Timeouts in Konfiguration, die pro Umgebung angepasst werden kann. Wenn Konstanten im Code sein müssen, verwenden Sie benannte Konstanten mit klarer Dokumentation anstelle magischer Zahlen. Implementieren Sie Konfigurationsvalidierung, um sicherzustellen, dass Sicherheitsparameter Mindestanforderungen erfüllen. Verwenden Sie verschiedene Sicherheitskonfigurationen für Entwicklungs-, Test- und Produktionsumgebungen.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Anwendungsdaten lesen - Hartcodierte kryptografische Schlüssel oder andere Geheimnisse können aus dem Code extrahiert werden, was Angreifern ermöglicht, sensible Daten zu entschlüsseln oder Authentifizierung zu umgehen.
ZugriffskontrolleBereich: Zugriffskontrolle

Schutzmechanismus umgehen - Hartcodierte Sicherheitsparameter wie Timeouts oder Wiederholungslimits können unzureichend sein, was Brute-Force-Angriffe oder Session-Fixation ermöglicht.
SonstigeBereich: Sonstige

Wartbarkeit reduzieren - Hartcodierte Konstanten erschweren das Aktualisieren von Sicherheitsparametern als Reaktion auf neue Bedrohungen oder sich ändernde Anforderungen ohne Codeänderungen.

Beispielcode + Lösungscode

Verwundbarer Code

// Verwundbar: Hartcodierte sicherheitsrelevante Konstanten
public class VerwundbareCrypto {

    // Verwundbar: Hartcodierter Verschlüsselungsschlüssel
    private static final byte[] SECRET_KEY =
        "MySecretKey12345".getBytes(StandardCharsets.UTF_8);

    // Verwundbar: Hartcodierter IV (sollte pro Verschlüsselung zufällig sein)
    private static final byte[] INIT_VECTOR =
        {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};

    // Verwundbar: Hartcodiertes Salt (hebt Zweck des Saltens auf)
    private static final String PASSWORD_SALT = "FixedSalt123";

    // Verwundbar: Hartcodierter Iterationszähler (kann unsicher werden)
    private static final int PBKDF2_ITERATIONS = 1000;  // Zu niedrig!

    // Verwundbar: Hartcodierte Schlüsselgröße
    private static final int KEY_SIZE = 128;  // Sollte 256 sein

    public byte[] encrypt(String plaintext) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(INIT_VECTOR);

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);

        return cipher.doFinal(plaintext.getBytes());
    }

    public String hashPassword(String password) {
        // Verwundbar: Gleiches Salt für alle Passwörter
        String salted = PASSWORD_SALT + password;
        return DigestUtils.sha256Hex(salted);
    }
}

// Verwundbar: Hartcodierte Sicherheits-Timeouts
public class VerwundbareSession {
    // Verwundbar: Hartcodierte Timeout-Werte
    private static final int SESSION_TIMEOUT = 3600;      // 1 Stunde
    private static final int TOKEN_EXPIRY = 86400;        // 24 Stunden
    private static final int MAX_LOGIN_ATTEMPTS = 3;
    private static final int LOCKOUT_DURATION = 300;      // 5 Minuten

    // Diese können für verschiedene Umgebungen zu lang oder zu kurz sein
}
# Verwundbar: Hartcodierte Sicherheitskonstanten in Python
import hashlib
from Crypto.Cipher import AES

class VerwundbareSecurity:
    # Verwundbar: Hartcodierter API-Schlüssel
    API_SECRET_KEY = "sk_live_hardcoded_key_12345"

    # Verwundbar: Hartcodierter Verschlüsselungsschlüssel
    ENCRYPTION_KEY = b"0123456789ABCDEF"  # 16 Bytes für AES-128

    # Verwundbar: Hartcodiertes JWT-Geheimnis
    JWT_SECRET = "super_secret_jwt_key"

    # Verwundbar: Hartcodierter HMAC-Schlüssel
    HMAC_KEY = b"hmac_secret_key_value"

    # Verwundbar: Hartcodierter Passwort-Pepper
    PASSWORD_PEPPER = "application_pepper_2023"

    def encrypt_data(self, data):
        # Verwundbar: Verwendung hartcodiertem Schlüssel und kein IV
        cipher = AES.new(self.ENCRYPTION_KEY, AES.MODE_ECB)  # ECB ist auch schlecht
        return cipher.encrypt(self._pad(data))

    def hash_password(self, password):
        # Verwundbar: Hartcodierter Pepper, kein einzigartiges Salt
        peppered = password + self.PASSWORD_PEPPER
        return hashlib.sha256(peppered.encode()).hexdigest()

    def generate_token(self, user_id):
        # Verwundbar: Hartcodiertes JWT-Geheimnis
        import jwt
        return jwt.encode(
            {"user_id": user_id},
            self.JWT_SECRET,
            algorithm="HS256"
        )


# Verwundbar: Hartcodierte Sicherheitslimits
MAX_FILE_SIZE = 10485760       # 10MB - könnte Anpassung brauchen
MAX_REQUEST_SIZE = 1048576     # 1MB - festes Limit
RATE_LIMIT = 100               # Anfragen pro Minute
BCRYPT_ROUNDS = 10             # Sollte konfigurierbar und höher sein
// Verwundbar: Hartcodierte Konstanten in Node.js
const crypto = require('crypto');

// Verwundbar: Hartcodierter Verschlüsselungsschlüssel
const ENCRYPTION_KEY = 'abcdefghijklmnop';  // 16 Bytes

// Verwundbar: Hartcodiertes HMAC-Geheimnis
const HMAC_SECRET = 'hmac_secret_123';

// Verwundbar: Hartcodiertes JWT-Geheimnis
const JWT_SECRET = 'my_jwt_secret_key';

// Verwundbar: Hartcodierte Session-Einstellungen
const SESSION_CONFIG = {
    secret: 'session_secret_value',      // Hartcodiert
    maxAge: 3600000,                      // Feste 1 Stunde
    secure: false,                        // Sollte von Umgebung abhängen
    sameSite: 'lax'                       // Feste Richtlinie
};

// Verwundbar: Hartcodierte Krypto-Parameter
const CRYPTO_CONFIG = {
    algorithm: 'aes-128-cbc',            // Sollte konfigurierbar sein
    iterations: 10000,                    // Feste PBKDF2-Iterationen
    keyLength: 16,                        // Feste Schlüssellänge
    saltLength: 16                        // Feste Salt-Länge
};

function encryptData(data) {
    // Verwundbar: Verwendung hartcodiertem Schlüssel
    const cipher = crypto.createCipheriv(
        'aes-128-cbc',
        ENCRYPTION_KEY,
        Buffer.alloc(16)  // Null-IV - noch schlimmer!
    );
    return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
}

function signData(data) {
    // Verwundbar: Hartcodierter HMAC-Schlüssel
    return crypto.createHmac('sha256', HMAC_SECRET)
        .update(data)
        .digest('hex');
}
<?php
// Verwundbar: Hartcodierte Sicherheitskonstanten in PHP

class VerwundbareCrypto {
    // Verwundbar: Hartcodierter Verschlüsselungsschlüssel
    private const ENCRYPTION_KEY = 'MySuperSecretKey';

    // Verwundbar: Hartcodierter IV
    private const IV = '1234567890123456';

    // Verwundbar: Hartcodierter HMAC-Schlüssel
    private const HMAC_KEY = 'hmac_key_fixed';

    // Verwundbar: Hartcodierter bcrypt-Kostenfaktor (zu niedrig)
    private const BCRYPT_COST = 4;  // Sollte mindestens 12 sein

    // Verwundbar: Hartcodierte Passwortanforderungen
    private const MIN_PASSWORD_LENGTH = 6;   // Zu kurz
    private const REQUIRE_SPECIAL_CHAR = false;  // Sollte true sein

    public function encrypt($data) {
        // Verwundbar: Verwendung hartcodiertem Schlüssel und IV
        return openssl_encrypt(
            $data,
            'AES-128-CBC',
            self::ENCRYPTION_KEY,
            0,
            self::IV
        );
    }

    public function hashPassword($password) {
        // Verwundbar: Fester niedriger Kostenfaktor
        return password_hash($password, PASSWORD_BCRYPT, [
            'cost' => self::BCRYPT_COST
        ]);
    }

    public function signData($data) {
        // Verwundbar: Hartcodierter HMAC-Schlüssel
        return hash_hmac('sha256', $data, self::HMAC_KEY);
    }
}

// Verwundbar: Hartcodierte Sicherheits-Timeouts
define('SESSION_TIMEOUT', 3600);
define('CSRF_TOKEN_EXPIRY', 1800);
define('PASSWORD_RESET_EXPIRY', 86400);
define('MAX_LOGIN_ATTEMPTS', 5);
?>

Lösungscode

// Behoben: Konfigurierbare Sicherheitskonstanten
public class SichereCrypto {
    private final SecureRandom secureRandom;
    private final SecurityConfig config;
    private final KeyManagementService keyService;

    public SichereCrypto(SecurityConfig config, KeyManagementService keyService) {
        this.config = config;
        this.keyService = keyService;
        this.secureRandom = new SecureRandom();
    }

    public EncryptedData encrypt(String plaintext) throws Exception {
        // Behoben: Schlüssel von Schlüsselverwaltungsdienst abrufen
        byte[] key = keyService.getEncryptionKey();

        // Behoben: Zufälligen IV für jede Verschlüsselung generieren
        byte[] iv = new byte[config.getIvSize()];
        secureRandom.nextBytes(iv);

        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);

        // Behoben: Algorithmus konfigurierbar
        Cipher cipher = Cipher.getInstance(config.getCipherAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);

        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

        // IV mit Chiffretext zurückgeben (IV muss nicht geheim sein)
        return new EncryptedData(iv, ciphertext);
    }

    public String hashPassword(String password) {
        // Behoben: Einzigartiges Salt pro Passwort generieren
        byte[] salt = new byte[config.getSaltSize()];
        secureRandom.nextBytes(salt);

        // Behoben: Konfigurierbarer Iterationszähler aus Konfiguration
        int iterations = config.getPbkdf2Iterations();
        int keyLength = config.getDerivedKeyLength();

        PBEKeySpec spec = new PBEKeySpec(
            password.toCharArray(),
            salt,
            iterations,
            keyLength
        );

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        byte[] hash = factory.generateSecret(spec).getEncoded();

        // Salt und Hash zusammen zurückgeben
        return Base64.getEncoder().encodeToString(salt) + ":" +
               Base64.getEncoder().encodeToString(hash);
    }
}

// Behoben: Sicherheitskonfigurationsklasse
public class SecurityConfig {
    private final int ivSize;
    private final int saltSize;
    private final int pbkdf2Iterations;
    private final int derivedKeyLength;
    private final String cipherAlgorithm;

    public SecurityConfig() {
        // Aus Umgebung oder Konfigurationsdatei laden
        this.ivSize = getIntProperty("CRYPTO_IV_SIZE", 16);
        this.saltSize = getIntProperty("CRYPTO_SALT_SIZE", 32);
        this.pbkdf2Iterations = getIntProperty("PBKDF2_ITERATIONS", 310000);
        this.derivedKeyLength = getIntProperty("DERIVED_KEY_LENGTH", 256);
        this.cipherAlgorithm = getProperty("CIPHER_ALGORITHM", "AES/GCM/NoPadding");

        // Minimale Sicherheitsanforderungen validieren
        validateConfig();
    }

    private void validateConfig() {
        if (pbkdf2Iterations < 100000) {
            throw new SecurityException("PBKDF2-Iterationen zu niedrig");
        }
        if (derivedKeyLength < 256) {
            throw new SecurityException("Schlüssellänge zu kurz");
        }
    }

    // Getter...
}
# Behoben: Konfigurierbare Sicherheitsparameter in Python
import os
import secrets
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend

class SichereSecurity:
    def __init__(self, config=None):
        self.config = config or SecurityConfig()
        self.key_service = KeyManagementService()

    def encrypt_data(self, data: bytes) -> dict:
        # Behoben: Schlüssel von Schlüsselverwaltungsdienst abrufen
        key = self.key_service.get_encryption_key()

        # Behoben: Zufälligen IV für jede Verschlüsselung generieren
        iv = secrets.token_bytes(self.config.iv_size)

        # Behoben: Authentifizierte Verschlüsselung verwenden (GCM)
        cipher = Cipher(
            algorithms.AES(key),
            modes.GCM(iv),
            backend=default_backend()
        )
        encryptor = cipher.encryptor()
        ciphertext = encryptor.update(data) + encryptor.finalize()

        return {
            'iv': iv,
            'ciphertext': ciphertext,
            'tag': encryptor.tag
        }

    def hash_password(self, password: str) -> str:
        # Behoben: Einzigartiges Salt pro Passwort generieren
        salt = secrets.token_bytes(self.config.salt_size)

        # Behoben: Konfigurierbare Iterationen
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA256(),
            length=self.config.derived_key_length,
            salt=salt,
            iterations=self.config.pbkdf2_iterations,
            backend=default_backend()
        )

        key = kdf.derive(password.encode())

        import base64
        return base64.b64encode(salt).decode() + ':' + base64.b64encode(key).decode()

    def generate_token(self, user_id: str) -> str:
        import jwt
        # Behoben: Geheimnis von Schlüsseldienst abrufen
        secret = self.key_service.get_jwt_secret()
        return jwt.encode(
            {"user_id": user_id},
            secret,
            algorithm=self.config.jwt_algorithm
        )


class SecurityConfig:
    """Sicherheitskonfiguration aus Umgebung geladen."""

    def __init__(self):
        # Behoben: Alle Parameter aus Umgebung mit sicheren Standardwerten
        self.iv_size = int(os.environ.get('CRYPTO_IV_SIZE', '12'))  # 96 Bits für GCM
        self.salt_size = int(os.environ.get('CRYPTO_SALT_SIZE', '32'))
        self.pbkdf2_iterations = int(os.environ.get('PBKDF2_ITERATIONS', '310000'))
        self.derived_key_length = int(os.environ.get('DERIVED_KEY_LENGTH', '32'))
        self.jwt_algorithm = os.environ.get('JWT_ALGORITHM', 'HS256')

        # Behoben: Mindestanforderungen validieren
        self._validate()

    def _validate(self):
        if self.pbkdf2_iterations < 100000:
            raise ValueError("PBKDF2-Iterationen müssen mindestens 100000 sein")
        if self.salt_size < 16:
            raise ValueError("Salt-Größe muss mindestens 16 Bytes sein")
// Behoben: Konfigurierbare Sicherheitskonstanten in Node.js
const crypto = require('crypto');

class SecurityConfig {
    constructor() {
        // Behoben: Aus Umgebung laden
        this.ivSize = parseInt(process.env.CRYPTO_IV_SIZE || '12');
        this.saltSize = parseInt(process.env.CRYPTO_SALT_SIZE || '32');
        this.pbkdf2Iterations = parseInt(process.env.PBKDF2_ITERATIONS || '310000');
        this.keyLength = parseInt(process.env.KEY_LENGTH || '32');
        this.algorithm = process.env.CIPHER_ALGORITHM || 'aes-256-gcm';

        // Behoben: Konfiguration validieren
        this.validate();
    }

    validate() {
        if (this.pbkdf2Iterations < 100000) {
            throw new Error('PBKDF2-Iterationen zu niedrig');
        }
        if (this.keyLength < 32) {
            throw new Error('Schlüssellänge zu kurz');
        }
    }
}

class SichereCrypto {
    constructor(config, keyService) {
        this.config = config || new SecurityConfig();
        this.keyService = keyService;
    }

    async encrypt(data) {
        // Behoben: Schlüssel von Schlüsseldienst abrufen
        const key = await this.keyService.getEncryptionKey();

        // Behoben: Zufälligen IV für jede Verschlüsselung generieren
        const iv = crypto.randomBytes(this.config.ivSize);

        // Behoben: Authentifizierte Verschlüsselung verwenden
        const cipher = crypto.createCipheriv(this.config.algorithm, key, iv);

        let ciphertext = cipher.update(data, 'utf8');
        ciphertext = Buffer.concat([ciphertext, cipher.final()]);

        const authTag = cipher.getAuthTag();

        return {
            iv: iv.toString('base64'),
            ciphertext: ciphertext.toString('base64'),
            authTag: authTag.toString('base64')
        };
    }

    hashPassword(password) {
        // Behoben: Einzigartiges Salt generieren
        const salt = crypto.randomBytes(this.config.saltSize);

        // Behoben: Konfigurierbare Iterationen verwenden
        const hash = crypto.pbkdf2Sync(
            password,
            salt,
            this.config.pbkdf2Iterations,
            this.config.keyLength,
            'sha256'
        );

        return salt.toString('base64') + ':' + hash.toString('base64');
    }
}

// Behoben: Session-Konfiguration aus Umgebung
const sessionConfig = {
    secret: process.env.SESSION_SECRET,  // Erforderlich, kein Standard
    maxAge: parseInt(process.env.SESSION_MAX_AGE || '3600000'),
    secure: process.env.NODE_ENV === 'production',
    sameSite: process.env.SESSION_SAME_SITE || 'strict'
};

if (!sessionConfig.secret) {
    throw new Error('SESSION_SECRET Umgebungsvariable erforderlich');
}

module.exports = { SecurityConfig, SichereCrypto, sessionConfig };
<?php
// Behoben: Konfigurierbare Sicherheitsparameter in PHP

class SecurityConfig {
    private int $ivSize;
    private int $saltSize;
    private int $pbkdf2Iterations;
    private int $bcryptCost;
    private string $cipherAlgorithm;

    public function __construct() {
        // Behoben: Aus Umgebung mit sicheren Standardwerten laden
        $this->ivSize = (int)getenv('CRYPTO_IV_SIZE') ?: 16;
        $this->saltSize = (int)getenv('CRYPTO_SALT_SIZE') ?: 32;
        $this->pbkdf2Iterations = (int)getenv('PBKDF2_ITERATIONS') ?: 310000;
        $this->bcryptCost = (int)getenv('BCRYPT_COST') ?: 12;
        $this->cipherAlgorithm = getenv('CIPHER_ALGORITHM') ?: 'aes-256-gcm';

        $this->validate();
    }

    private function validate(): void {
        if ($this->pbkdf2Iterations < 100000) {
            throw new SecurityException('PBKDF2-Iterationen zu niedrig');
        }
        if ($this->bcryptCost < 10) {
            throw new SecurityException('Bcrypt-Kostenfaktor zu niedrig');
        }
    }

    // Getter...
    public function getIvSize(): int { return $this->ivSize; }
    public function getSaltSize(): int { return $this->saltSize; }
    public function getPbkdf2Iterations(): int { return $this->pbkdf2Iterations; }
    public function getBcryptCost(): int { return $this->bcryptCost; }
    public function getCipherAlgorithm(): string { return $this->cipherAlgorithm; }
}

class SichereCrypto {
    private SecurityConfig $config;
    private KeyManagementService $keyService;

    public function __construct(SecurityConfig $config, KeyManagementService $keyService) {
        $this->config = $config;
        $this->keyService = $keyService;
    }

    public function encrypt(string $data): array {
        // Behoben: Schlüssel von Schlüsseldienst abrufen
        $key = $this->keyService->getEncryptionKey();

        // Behoben: Zufälligen IV generieren
        $iv = random_bytes($this->config->getIvSize());

        // Behoben: Authentifizierte Verschlüsselung verwenden
        $ciphertext = openssl_encrypt(
            $data,
            $this->config->getCipherAlgorithm(),
            $key,
            OPENSSL_RAW_DATA,
            $iv,
            $tag
        );

        return [
            'iv' => base64_encode($iv),
            'ciphertext' => base64_encode($ciphertext),
            'tag' => base64_encode($tag)
        ];
    }

    public function hashPassword(string $password): string {
        // Behoben: Konfigurierbaren bcrypt-Kostenfaktor verwenden
        return password_hash($password, PASSWORD_BCRYPT, [
            'cost' => $this->config->getBcryptCost()
        ]);
    }
}

// Behoben: Sicherheits-Timeouts aus Umgebung
class SecurityTimeouts {
    public static function getSessionTimeout(): int {
        return (int)getenv('SESSION_TIMEOUT') ?: 3600;
    }

    public static function getCsrfTokenExpiry(): int {
        return (int)getenv('CSRF_TOKEN_EXPIRY') ?: 1800;
    }

    public static function getPasswordResetExpiry(): int {
        return (int)getenv('PASSWORD_RESET_EXPIRY') ?: 3600;  // 1 Stunde, nicht 24
    }

    public static function getMaxLoginAttempts(): int {
        return (int)getenv('MAX_LOGIN_ATTEMPTS') ?: 5;
    }
}
?>

CVE-Beispiele

  • CVE-2022-26138: Atlassian Confluence Questions verwendete hartcodiertes Passwort für das disabledsystemuser-Konto.
  • CVE-2021-29078: NetModule Router Software enthielt hartcodierte kryptografische Schlüssel.
  • CVE-2020-4574: IBM Security Key Lifecycle Manager verwendete hartcodierte Anmeldedaten.

Referenzen

  1. MITRE Corporation. "CWE-547: Use of Hard-coded, Security-relevant Constants." https://cwe.mitre.org/data/definitions/547.html
  2. OWASP. "Cryptographic Storage Cheat Sheet."
  3. NIST. "Key Management Guidelines."