Covert Timing Channel

Description

Covert Timing Channel is a vulnerability that occurs when sensitive information can be inferred by observing the timing of system operations. These channels convey information by modulating some aspect of system behavior over time, so that an attacker monitoring the timing can deduce protected information. Common examples include cryptographic operations that take different amounts of time based on the input or key material, password validation that returns early on mismatch, and database queries whose execution time varies based on the data accessed.

Risk

Timing channels can leak cryptographic keys, passwords, and other sensitive data. Attackers can determine valid usernames by comparing response times for valid versus invalid accounts. Cryptographic implementations vulnerable to timing attacks may have their keys extracted through statistical analysis of operation timing. Database queries can reveal information about data existence and content through query execution time analysis. These attacks are particularly dangerous because they leave no trace in application logs and can be conducted remotely. Modern CPU features like branch prediction and caching make timing attacks more practical.

Solution

Design implementations that eliminate time variances in security-sensitive operations. Use constant-time comparison functions for passwords, MACs, and other secrets. Add artificial or random delays so that the amount of CPU time consumed is independent of the action being taken. Use cryptographic libraries that implement constant-time operations. Avoid early-return patterns in authentication code. Consider adding random jitter to mask timing information. For particularly sensitive operations, ensure the execution time is uniform regardless of the path taken through the code.

Common Consequences

ImpactDetails
ConfidentialityScope: Confidentiality

Information exposure through the ability to read application data by analyzing operation timing.

Example Code

Vulnerable Code

// Vulnerable: Early return on password mismatch
int vulnerable_check_password(const char *provided, const char *stored) {
    size_t provided_len = strlen(provided);
    size_t stored_len = strlen(stored);

    // Vulnerable: Length comparison reveals password length
    if (provided_len != stored_len) {
        return 0;  // Early return
    }

    // Vulnerable: Character-by-character comparison
    for (size_t i = 0; i < stored_len; i++) {
        if (provided[i] != stored[i]) {
            return 0;  // Early return reveals position of mismatch
        }
    }

    return 1;
}
# Vulnerable: Timing-based username enumeration
def vulnerable_login(username, password):
    user = database.find_user(username)

    if user is None:
        # Vulnerable: Fast return for invalid username
        return False

    # Slow hash computation only for valid usernames
    hashed = hash_password(password, user.salt)

    if hashed == user.password_hash:
        return True

    return False

# Vulnerable: String comparison
def vulnerable_verify_token(provided, expected):
    # Vulnerable: Early termination reveals match position
    return provided == expected
// Vulnerable: MAC verification with timing leak
public class VulnerableMacVerifier {

    public boolean verifyMac(byte[] message, byte[] providedMac, SecretKey key) {
        byte[] computedMac = computeMac(message, key);

        // Vulnerable: Arrays.equals returns early on mismatch
        return Arrays.equals(computedMac, providedMac);
    }

    public boolean verifySignature(byte[] data, byte[] signature) {
        byte[] expected = computeSignature(data);

        // Vulnerable: Byte-by-byte comparison leaks info
        if (signature.length != expected.length) {
            return false;  // Length leak
        }

        for (int i = 0; i < expected.length; i++) {
            if (signature[i] != expected[i]) {
                return false;  // Position leak
            }
        }
        return true;
    }
}

Fixed Code

// Fixed: Constant-time password comparison
#include <stdint.h>
#include <string.h>

int secure_check_password(const char *provided, const char *stored,
                          size_t max_len) {
    volatile uint8_t result = 0;
    size_t i;

    // Fixed: Always process max_len bytes
    for (i = 0; i < max_len; i++) {
        // XOR accumulates differences without early exit
        result |= provided[i] ^ stored[i];
    }

    // Fixed: Additional check for null terminators
    // This is constant-time because both strings are processed

    return result == 0;
}

// Fixed: Using OpenSSL's constant-time comparison
#include <openssl/crypto.h>

int secure_compare(const void *a, const void *b, size_t len) {
    // Fixed: CRYPTO_memcmp is constant-time
    return CRYPTO_memcmp(a, b, len) == 0;
}
# Fixed: Constant-time comparison using hmac.compare_digest
import hmac
import secrets
import time

def secure_login(username, password):
    user = database.find_user(username)

    # Fixed: Always compute hash, even for invalid username
    if user is None:
        # Use dummy values for timing consistency
        dummy_salt = secrets.token_bytes(16)
        dummy_hash = hash_password(password, dummy_salt)
        # Compare against random value to maintain timing
        hmac.compare_digest(dummy_hash, secrets.token_bytes(len(dummy_hash)))
        return False

    hashed = hash_password(password, user.salt)

    # Fixed: Constant-time comparison
    if hmac.compare_digest(hashed, user.password_hash):
        return True

    return False

# Fixed: Constant-time token verification
def secure_verify_token(provided, expected):
    # Fixed: hmac.compare_digest is constant-time
    if len(provided) != len(expected):
        # Fixed: Still do comparison to avoid timing leak
        # Compare against itself to burn same time
        hmac.compare_digest(provided, provided)
        return False

    return hmac.compare_digest(provided.encode(), expected.encode())

# Fixed: Add artificial delay for additional protection
def secure_login_with_delay(username, password):
    start_time = time.monotonic()

    result = secure_login(username, password)

    # Fixed: Ensure minimum operation time
    elapsed = time.monotonic() - start_time
    min_time = 0.1  # 100ms minimum

    if elapsed < min_time:
        time.sleep(min_time - elapsed)

    return result
// Fixed: Constant-time MAC verification
import java.security.MessageDigest;

public class SecureMacVerifier {

    public boolean verifyMac(byte[] message, byte[] providedMac, SecretKey key) {
        byte[] computedMac = computeMac(message, key);

        // Fixed: MessageDigest.isEqual is constant-time
        return MessageDigest.isEqual(computedMac, providedMac);
    }

    // Fixed: Manual constant-time comparison
    public static boolean constantTimeEquals(byte[] a, byte[] b) {
        if (a == null || b == null) {
            return a == b;
        }

        if (a.length != b.length) {
            // Fixed: Still compare to avoid length timing leak
            // Compare a against itself
            int dummy = 0;
            for (int i = 0; i < a.length; i++) {
                dummy |= a[i] ^ a[i];
            }
            return false;
        }

        // Fixed: Accumulate all differences
        int result = 0;
        for (int i = 0; i < a.length; i++) {
            result |= a[i] ^ b[i];
        }

        return result == 0;
    }

    // Fixed: Constant-time string comparison
    public static boolean constantTimeStringEquals(String a, String b) {
        if (a == null || b == null) {
            return a == b;
        }

        byte[] aBytes = a.getBytes(StandardCharsets.UTF_8);
        byte[] bBytes = b.getBytes(StandardCharsets.UTF_8);

        return MessageDigest.isEqual(aBytes, bBytes);
    }
}

CVE Examples

No specific CVEs are listed for this CWE. The vulnerability pattern appears in:

  • Cryptographic implementations (timing attacks on AES, RSA)
  • Password verification systems
  • HMAC and digital signature verification

References

  1. MITRE Corporation. "CWE-385: Covert Timing Channel." https://cwe.mitre.org/data/definitions/385.html
  2. Kocher, Paul. "Timing Attacks on Implementations of Diffie-Hellman, RSA, DSS, and Other Systems."