Skip to content

Latest commit

 

History

History
173 lines (141 loc) · 10.3 KB

File metadata and controls

173 lines (141 loc) · 10.3 KB

Mitigation Strategies Analysis for krzyzanowskim/cryptoswift

  1. Whitelist Approach (CryptoSwift Focus): Define a whitelist of CryptoSwift Cipher and BlockMode instances (or their corresponding enum values, if applicable). This is not just a list of strings; it's a list of the actual types or enums used by CryptoSwift. Example (conceptual):

    // SecurityConstants.swift
    import CryptoSwift
    
    let allowedCiphers: [Cipher] = [
        AES(keySize: .aes256, blockMode: .gcm), // Example: AES-256-GCM
        ChaCha20(keySize: .keySize256, ivSize: .ivSize128) // Example: ChaCha20
    ]
  2. Configuration Validation (CryptoSwift Focus): When initializing CryptoSwift objects, validate against the whitelist. This is not just checking strings; it's checking the type or instance of the Cipher and BlockMode.

    // CryptoManager.swift
    import CryptoSwift
    
    func createCipher(algorithm: String, mode: String, key: [UInt8], iv: [UInt8]) throws -> Cipher {
        // ... (Get Cipher and BlockMode instances based on 'algorithm' and 'mode' strings) ...
        // Example (Conceptual - adapt to your actual configuration method):
        let selectedCipher = try AES(key: key, blockMode: .gcm(iv: iv)) // Example
    
        guard allowedCiphers.contains(where: { $0.blockSize == selectedCipher.blockSize && type(of: $0) == type(of: selectedCipher) }) else {
            throw CryptoError.invalidAlgorithmOrMode
        }
    
        return selectedCipher
    }
  3. Key and IV Size Validation: Within the createCipher (or similar) function, explicitly validate the key and IV sizes against the requirements of the chosen algorithm and mode. Use CryptoSwift's properties (e.g., keySize, blockSize, ivSize) to perform these checks.

     guard key.count == selectedCipher.keySize else {
        throw CryptoError.invalidKeySize
    }
    if let gcmMode = selectedCipher.blockMode as? GCM { // Example for GCM
        guard iv.count == gcmMode.ivSize else {
            throw CryptoError.invalidIVSize
        }
    }
  4. Documentation (CryptoSwift Focus): Document precisely how to use the approved CryptoSwift configurations, including code examples.

    • Threats Mitigated:

      • Incorrect Algorithm/Mode Selection (Severity: High): Prevents direct instantiation of vulnerable CryptoSwift configurations (e.g., AES(key: key, blockMode: .ecb)).
      • Configuration Errors (Severity: High): Reduces the risk of passing incorrect parameters to CryptoSwift's constructors.
      • Key/IV Size Mismatches (Severity: High): Prevents using keys or IVs of incorrect lengths with specific CryptoSwift algorithms and modes.
    • Impact:

      • Incorrect Algorithm/Mode Selection: Risk reduced significantly (from High to Low/Negligible).
      • Configuration Errors: Risk reduced significantly (from High to Low).
      • Key/IV Size Mismatches: Risk reduced from High to Negligible.
    • Currently Implemented:

      • Basic key and IV size validation in CryptoManager.swift.
    • Missing Implementation:

      • Strict whitelist enforcement using CryptoSwift types/instances (as described above) is not yet fully implemented. Current validation relies on string comparisons, which is less robust.
      • Comprehensive documentation with CryptoSwift-specific code examples is needed.
  1. CSPRNG for IVs (CryptoSwift Focus): Always use SecRandomCopyBytes to generate IVs that are passed to CryptoSwift. Never use random() or derive IVs in any other way.

    // SecureRandomGenerator.swift
    import CryptoSwift
    import Security
    
    func generateSecureIV(size: Int) -> [UInt8] {
        var iv = [UInt8](repeating: 0, count: size)
        let result = SecRandomCopyBytes(kSecRandomDefault, size, &iv)
        guard result == errSecSuccess else {
            fatalError("Failed to generate secure IV")
        }
        return iv
    }
  2. Nonce Management (CryptoSwift Focus): When using CryptoSwift's authenticated encryption modes (GCM, CCM), ensure that nonces are never reused with the same key. This is critical.

    • Random Nonces: For GCM, a 96-bit (12-byte) random nonce is generally recommended. Generate this using SecureRandomGenerator.
    • Counter-Based Nonces (If Required): If a counter-based approach is absolutely necessary, ensure the counter is:
      • Persisted securely (e.g., Keychain).
      • Incremented before each encryption operation.
      • Combined with a key-specific prefix (if needed for multi-device scenarios).
  3. Direct CryptoSwift API Usage: Use the generated IVs directly with CryptoSwift's APIs. For example:

    let iv = SecureRandomGenerator.generateSecureIV(size: 12) // For AES-GCM
    let aes = try AES(key: key, blockMode: GCM(iv: iv)) // Pass IV directly to GCM
    let ciphertext = try aes.encrypt(plaintext)
  4. Documentation: Clearly document the nonce management strategy and how it interacts with CryptoSwift.

    • Threats Mitigated:

      • Weak/Predictable IVs/Nonces (Severity: Critical): Ensures that IVs passed to CryptoSwift are cryptographically secure and non-repeating.
      • Replay Attacks (Severity: High): Proper nonce management with CryptoSwift's authenticated modes prevents replay attacks.
    • Impact:

      • Weak/Predictable IVs/Nonces: Risk reduced from Critical to Negligible.
      • Replay Attacks: Risk reduced from High to Negligible.
    • Currently Implemented:

      • SecureRandomGenerator class uses SecRandomCopyBytes.
      • Random nonces are generated and passed to CryptoSwift's GCM initializer.
    • Missing Implementation:

      • No counter-based nonce implementation (not currently needed).
      • Documentation could be improved to explicitly highlight the importance of nonce uniqueness with CryptoSwift.
  1. Use CryptoSwift's Conversion Methods: Always use CryptoSwift's provided methods for converting between String, Data, and [UInt8]. Examples:

    • string.bytes (to get a [UInt8] from a String)
    • Data(bytes) (to create a Data object from a [UInt8])
    • String(data:encoding:) (to create a String from a Data object)
  2. Explicit Encoding (CryptoSwift Focus): When converting between strings and byte arrays for use with CryptoSwift, always specify the encoding explicitly. UTF-8 is generally recommended.

    let plaintextString = "Hello, world!"
    let plaintextBytes = plaintextString.bytes(using: .utf8) // Explicit UTF-8 encoding
    
    // ... (Use plaintextBytes with CryptoSwift) ...
    
    let decryptedBytes = try aes.decrypt(ciphertext)
    let decryptedString = String(bytes: decryptedBytes, encoding: .utf8) // Explicit UTF-8 decoding
  3. Avoid Manual Byte Manipulation: Minimize manual manipulation of byte arrays. If necessary, ensure it's thoroughly reviewed and tested.

    • Threats Mitigated:

      • Incorrect Data Conversions (Severity: Medium): Reduces the risk of errors when converting data for use with CryptoSwift.
      • Encoding-Related Issues (Severity: Medium): Ensures consistent and correct encoding when working with strings and CryptoSwift.
    • Impact:

      • Incorrect Data Conversions: Risk reduced from Medium to Low.
      • Encoding-Related Issues: Risk reduced from Medium to Low.
    • Currently Implemented:

      • CryptoSwift's conversion methods are generally used.
      • UTF-8 encoding is explicitly specified in most cases.
    • Missing Implementation:

      • A review of all string/byte conversions to ensure consistent use of explicit encoding is needed.
  1. Unit Tests (CryptoSwift Focus): Create unit tests that specifically exercise CryptoSwift's functionality.

  2. Known Answer Tests (KATs) (CryptoSwift Focus): Use known input/output pairs (test vectors) to verify that CryptoSwift's encryption and decryption are working correctly for the specific algorithms and modes used. Find KATs from reliable sources (NIST, RFCs, etc.).

  3. Edge Case Testing (CryptoSwift Focus): Test CryptoSwift with:

    • Empty inputs ([] for byte arrays).
    • Very large inputs.
    • Inputs with special characters.
    • Inputs near the boundaries of allowed key and IV sizes.
  4. Error Handling Tests (CryptoSwift Focus): Test how CryptoSwift and your wrapper code handle:

    • Invalid keys (wrong size, incorrect format).
    • Invalid IVs/nonces (wrong size, reuse).
    • Invalid ciphertexts (tampered data).
    • Incorrect padding (if CBC is used – but avoid CBC). Use CryptoSwift.CryptoError.
  5. Algorithm/Mode Coverage: Ensure tests cover all CryptoSwift algorithms and modes used in the application.

    • Threats Mitigated:

      • Implementation Errors (Severity: Variable, potentially High): Catches bugs in how CryptoSwift is being used.
      • Incorrect Usage (Severity: Medium): Identifies cases where CryptoSwift's APIs are called with incorrect parameters.
    • Impact:

      • Implementation Errors: Risk reduced significantly.
      • Incorrect Usage: Risk reduced from Medium to Low.
    • Currently Implemented:

      • Basic unit tests for AES-GCM encryption/decryption using CryptoSwift.
      • Some KATs are included.
    • Missing Implementation:

      • Comprehensive edge case and error handling tests are incomplete.
      • Full coverage of all used CryptoSwift algorithms and modes is lacking.