CryptoSwift Documentation

repository·main·Indexed 27 days ago

https://github.com/krzyzanowskim/cryptoswift

A pure Swift implementation of cryptographic primitives and utilities for Apple platforms, Linux, and Android. It provides support for hashing (MD5, SHA1, SHA2, SHA3), CRC, ciphers (AES, ChaCha20, XChaCha20, Rabbit, Blowfish), RSA encryption and signatures, message authenticators (Poly1305, HMAC, CMAC), key derivation functions (PBKDF1, PBKDF2, HKDF, Scrypt), and various padding schemes. The library includes extensions for String, Data, and Array<UInt8>, and supports incremental updates and streaming APIs.

Tokens
3.5K
Snippets
14
Records
19
Agent score
45%

What's inside CryptoSwift

  1. CryptoSwift Overview and Features

    main

    CryptoSwift is a pure Swift implementation of cryptographic primitives and utilities. It provides convenient extensions for String, Data, and Array<UInt8>, supports incremental updates and streaming APIs, and is compatible with Apple platforms, Linux, and Android.

    Supported Cryptographic Features:

    • Hash (Digest): MD5, SHA1, SHA2 (224, 256, 384, 512), SHA3
    • CRC: CRC32, CRC32C, CRC16
    • Cipher: AES (128, 192, 256), ChaCha20, XChaCha20, Rabbit, Blowfish
    • RSA: Encryption and Signature
    • Message Authenticators: Poly1305, HMAC (MD5, SHA1, SHA256), CMAC, CBC-MAC
    • Cipher Modes: ECB, CBC, PCBC, CFB, OFB, CTR, GCM, CCM, OCB
    • Key Derivation (KDF): PBKDF1, PBKDF2, HKDF, Scrypt
    • Padding: PKCS#5, EMSA-PKCS1-v1_5, EME-PKCS1-v1_5, PKCS#7, Zero padding, ISO/IEC 7816-4, ISO10126, No padding
    • AEAD: AEAD_CHACHA20_POLY1305, AEAD_XCHACHA20_POLY1305
  2. CryptoSwift Requirements

    main

    To use the current release of CryptoSwift, ensure your environment meets the following requirements:

    • Swift Version: 5.6 or newer
    • Apple Deployment Targets:
      • iOS 11+
      • macOS 10.13+
      • Mac Catalyst 13+
      • tvOS 11+
      • watchOS 4+
      • visionOS 1+
    • Other Platforms: Linux and Android are supported (exercised in CI).
  3. Install CryptoSwift via Swift Package Manager

    main

    Swift Package Manager is the primary distribution method. Add the dependency to your Package.swift and then include the product in your target.

    Note: If profiling crypto-heavy workloads in Xcode, compare Debug and Release builds. Debug builds are significantly slower than optimized Release builds.

    dependencies: [
      .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "1.10.0")
    ]
    
    // In your target definition:
    .target(
      name: "MyTarget",
      dependencies: [
        .product(name: "CryptoSwift", package: "CryptoSwift")
      ]
    )
  4. Convert between Data and Byte Arrays

    main

    CryptoSwift uses Array<UInt8> as its base type for all operations. You can easily convert between Data and byte arrays using convenience properties and methods.

    • Data to Bytes: Use the .byteArray property on a Data object.
    • Bytes to Data: Initialize Data with an array of bytes.
    • Hexadecimal: Use Array<UInt8>(hex: "...") to create bytes from a hex string, and .toHexString() to convert bytes to a hex string.
    • String to Bytes: Use the .bytes property on a String.
    • Base64: Use .toBase64() to encode bytes, and .decryptBase64ToString(cipher) or .decryptBase64(cipher) on a Base64 string to decode.
    // Data from bytes
    let data = Data([0x01, 0x02, 0x03])
    
    // Data to Array<UInt8>
    let bytes = data.byteArray                // [1,2,3]
    
    // Hexadecimal encoding
    let bytes = Array<UInt8>(hex: "0x010203")  // [1,2,3]
    let hex   = bytes.toHexString()            // "010203"
    
    // Build bytes out of String
    let bytes: Array<UInt8> = "cipherkey".bytes  // Array("cipherkey".utf8)
    
    // Base64 helpers
    "aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64ToString(cipher)
    "aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64(cipher)
    bytes.toBase64()
  5. Install CryptoSwift via CocoaPods

    main

    CocoaPods is deprecated for new integrations; use Swift Package Manager instead. For existing projects, add the following to your Podfile:

    Note: CocoaPods builds may require manual optimization settings (e.g., using the cocoapods-wholemodule plugin) to ensure performance.

    pod 'CryptoSwift', '~> 1.10.0'
  6. Vendor CryptoSwift via Git Submodule

    main

    To vendor CryptoSwift directly in an Xcode project, add it as a submodule from the top-level project directory. For best performance, enable Whole-Module Optimization.

    git submodule add https://github.com/krzyzanowskim/CryptoSwift.git
  7. Configure macOS Hardened Runtime for XCFramework

    main

    If you embed the prebuilt CryptoSwift.xcframework in a hardened macOS app, library validation might prevent the binary from loading when the app is signed with Sign to Run Locally. To resolve this, either:

    • Sign the app with a proper Development certificate.
    • Enable Disable Library Validation (com.apple.security.cs.disable-library-validation) for the app.
  8. Encrypt and Decrypt with AES

    main

    CryptoSwift supports various AES modes (CBC, CFB, OFB, CTR, GCM, CCM).

    Key Lengths:

    • AES-128: 16 bytes
    • AES-192: 24 bytes
    • AES-256: 32 bytes

    Important Notes:

    • Padding: CryptoSwift uses PKCS7 padding by default. To disable it, set padding: .noPadding in the initializer.
    • Incremental Updates: For large files, use .makeEncryptor() to create a Cryptor instance and process data in chunks using .update(withBytes:) and .finish() to save memory.
    • AES-GCM: In .combined mode, the authentication tag is automatically appended to the ciphertext. Note that a GCM instance should not be reused for both encoding and decoding.
    // Standard AES-CBC encryption
    let aes = try AES(key: [1,2,3 /* ... 32 bytes total */], blockMode: CBC(iv: [1,2,3 /* ... 16 bytes total */]), padding: .pkcs7)
    let encryptedBytes = try aes.encrypt(Array("secret message".utf8))
    
    // Incremental AES encryption
    do {
        var encryptor = try AES(key: "keykeykeykeykeyk", iv: "drowssapdrowssap").makeEncryptor()
        var ciphertext = Array<UInt8>()
        ciphertext += try encryptor.update(withBytes: Array("Nullam quis risus ".utf8))
        ciphertext += try encryptor.update(withBytes: Array("eget urna mollis ".utf8))
        ciphertext += try encryptor.finish()
    } catch {
        print(error)
    }
    
    // AES-GCM (Combined mode)
    do {
        let gcm = GCM(iv: iv, mode: .combined)
        let aes = try AES(key: key, blockMode: gcm, padding: .noPadding)
        let encrypted = try aes.encrypt(plaintext)
        let tag = gcm.authenticationTag
    } catch {
        // failed
    }
  9. Apply Data Padding

    main

    Manually add padding to an input array using Padding.pkcs7.add(to:blockSize:). This is useful for algorithms that require input lengths to be multiples of a specific block size.

    let input = Array("hello".utf8)
    let padded = Padding.pkcs7.add(to: input, blockSize: AES.blockSize)
  10. Calculate Digests (Hashing)

    main

    You can calculate cryptographic digests (MD5, SHA1, SHA256, etc.) on Array<UInt8>, Data, or String types.

    Hashing Array<UInt8> or Data: Use the direct extension methods like .md5(), .sha1(), .sha256(), etc.

    Incremental Hashing: For large inputs, use the Digest class to update the hash state incrementally to save memory.

    Hashing Strings: You can call .md5() directly on a String (which internally converts it to bytes).

    // Hashing an array of bytes
    let input: Array<UInt8> = [0x01, 0x02, 0x03]
    let md5Digest = input.md5()
    
    // Hashing Data
    let data = Data([0x01, 0x02, 0x03])
    let sha256Digest = data.sha256()
    
    // Incremental hashing
    do {
        var digest = MD5()
        _ = try digest.update(withBytes: [0x31, 0x32])
        _ = try digest.update(withBytes: [0x33])
        let result = try digest.finish()
    } catch {
        print(error)
    }
    
    // Hashing a String
    let hash = "123".md5()