Skip to content

Swift Crypto

SecuritySecurity / CryptographySwift

What it is

Apple's open-source implementation of the CryptoKit API, providing hashing, HMAC, symmetric and public-key cryptography across Apple platforms and Linux.

The API is deliberately narrow and hard to misuse: modern algorithms only, authenticated encryption by default, and no way to select a broken cipher.

Installation

.package(url: "https://github.com/apple/swift-crypto.git", from: "3.8.0")

Getting started

The smallest useful thing you can do with it, and what each part means.

Hashing, HMAC and authenticated encryption
import Crypto

let digest = SHA256.hash(data: Data(payload.utf8))
let hex = digest.compactMap { String(format: "%02x", $0) }.joined()

// Verify a webhook signature — constant-time comparison.
let key = SymmetricKey(data: secret)
let valid = HMAC<SHA256>.isValidAuthenticationCode(
    receivedSignature, authenticating: body, using: key
)

// AES-GCM: encryption and authentication together.
let sealed = try AES.GCM.seal(plaintext, using: key)
let combined = sealed.combined!          // nonce + ciphertext + tag

let box = try AES.GCM.SealedBox(combined: combined)
let decrypted = try AES.GCM.open(box, using: key)
isValidAuthenticationCode compares in constant time. Comparing signatures with == leaks timing information and is a real vulnerability, which is why the API provides this.

Advanced usage

Where the library earns its place over a simpler alternative.

Key agreement and signatures
// Ephemeral key agreement (X25519).
let privateKey = Curve25519.KeyAgreement.PrivateKey()
let shared = try privateKey.sharedSecretFromKeyAgreement(
    with: peerPublicKey
)

// Never use the raw shared secret as a key — derive one.
let symmetricKey = shared.hkdfDerivedSymmetricKey(
    using: SHA256.self,
    salt: salt,
    sharedInfo: Data("app-v1".utf8),
    outputByteCount: 32
)

// Signing (Ed25519).
let signingKey = Curve25519.Signing.PrivateKey()
let signature = try signingKey.signature(for: message)
let ok = signingKey.publicKey.isValidSignature(signature, for: message)
The HKDF step is not optional. Using a raw Diffie-Hellman output directly as an encryption key is a classic mistake — it is not uniformly distributed.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

CryptoKitError.authenticationFailure
The ciphertext or tag was altered, or the wrong key was used. This is the integrity check working — do not ignore it.
incorrectKeySize
The key length does not match the algorithm. Derive a correctly sized key with HKDF.

Best practices

  • Never compare secrets with ==; use the constant-time verification functions.
  • Derive keys with HKDF rather than using raw shared secrets or passwords directly.
  • Store keys in the Keychain, not in UserDefaults or a file.
  • Prefer AES.GCM or ChaChaPoly — both authenticate as well as encrypt.

Background

Why it exists, and what it was reacting to.

CryptoKit is Apple-only. Swift Crypto reimplements the same API on top of BoringSSL so server-side Swift on Linux can use identical code, which matters for shared client and server logic.