| name | axiom-cryptokit-ref |
| description | Use when needing CryptoKit API details — hash functions (SHA2/SHA3), HMAC, AES-GCM/ChaChaPoly encryption, ECDSA/EdDSA signatures, ECDH key agreement, ML-KEM/ML-DSA post-quantum algorithms, HPKE encryption, Secure Enclave key types, key representations (raw/DER/PEM/x963), or Swift Crypto cross-platform parity. Covers complete CryptoKit API surface. |
| license | MIT |
CryptoKit API Reference
Complete API reference for Apple CryptoKit: hashing, HMAC, symmetric encryption, key agreement, digital signatures, post-quantum cryptography, HPKE, Secure Enclave, key derivation, and Swift Crypto cross-platform parity.
Quick Reference
import CryptoKit
let key = SymmetricKey(size: .bits256)
let sealed = try AES.GCM.seal(plaintext, using: key)
let combined = sealed.combined!
let sealedBox = try AES.GCM.SealedBox(combined: combined)
let decrypted = try AES.GCM.open(sealedBox, using: key)
let signingKey = P256.Signing.PrivateKey()
let signature = try signingKey.signature(for: data)
let valid = signingKey.publicKey.isValidSignature(signature, for: data)
let seKey = try SecureEnclave.P256.Signing.PrivateKey()
let seSignature = try seKey.signature(for: data)
Hashing
Hash Functions
| Algorithm | Type | Output Size | Use |
|---|
| SHA256 | SHA256 | 32 bytes | General purpose, most common |
| SHA384 | SHA384 | 48 bytes | TLS, certificate chains |
| SHA512 | SHA512 | 64 bytes | High-security contexts |
| SHA3_256 | SHA3_256 | 32 bytes | NIST post-quantum companion |
| SHA3_384 | SHA3_384 | 48 bytes | Post-quantum companion |
| SHA3_512 | SHA3_512 | 64 bytes | Post-quantum companion |
| Insecure.MD5 | Insecure.MD5 | 16 bytes | Legacy interop only |
| Insecure.SHA1 | Insecure.SHA1 | 20 bytes | Legacy interop only |
Single-Call Hashing
let digest = SHA256.hash(data: data)
let hex = digest.map { String(format: "%02x", $0) }.joined()
Streaming (Incremental) Hashing
var hasher = SHA256()
hasher.update(data: chunk1)
hasher.update(data: chunk2)
hasher.update(bufferPointer: unsafePointer)
let digest = hasher.finalize()
HashFunction Protocol
All hash types conform to HashFunction with: byteCount, blockByteCount, init(), update(data:), update(bufferPointer:), finalize(), and hash(data:).
Digest conforms to Sequence (of UInt8), supports constant-time ==, and converts to Data(digest) or Array(digest). description returns hex string.
Message Authentication (HMAC)
SymmetricKey
let key = SymmetricKey(size: .bits128)
let key = SymmetricKey(size: SymmetricKeySize(bitCount: 512))
let key = SymmetricKey(data: existingKeyData)
key.bitCount
key.withUnsafeBytes { bytes in }
HMAC Generation and Verification
let authCode = HMAC<SHA256>.authenticationCode(for: data, using: key)
let valid = HMAC<SHA256>.isValidAuthenticationCode(authCode, authenticating: data, using: key)
let macData = Data(authCode)
Iterative HMAC
var hmac = HMAC<SHA256>(key: key)
hmac.update(data: chunk1)
hmac.update(data: chunk2)
let authCode = hmac.finalize()
Symmetric Encryption
AES-GCM
let sealed = try AES.GCM.seal(plaintext, using: key)
let sealed = try AES.GCM.seal(plaintext, using: key, nonce: customNonce)
let sealed = try AES.GCM.seal(
plaintext,
using: key,
nonce: customNonce,
authenticating: associatedData
)
sealed.nonce
sealed.ciphertext
sealed.tag
sealed.combined
let plaintext = try AES.GCM.open(sealedBox, using: key)
let plaintext = try AES.GCM.open(sealedBox, using: key, authenticating: associatedData)
AES-GCM SealedBox Construction
let box = try AES.GCM.SealedBox(combined: combinedData)
let box = try AES.GCM.SealedBox(
nonce: AES.GCM.Nonce(data: nonceData),
ciphertext: ciphertextData,
tag: tagData
)
AES-GCM Nonce
let nonce = AES.GCM.Nonce()
let nonce = try AES.GCM.Nonce(data: nonceData)
ChaChaPoly
Identical interface to AES-GCM. Preferred for software-only environments without AES-NI.
let sealed = try ChaChaPoly.seal(plaintext, using: key)
let sealed = try ChaChaPoly.seal(plaintext, using: key, authenticating: aad)
let plaintext = try ChaChaPoly.open(sealed, using: key)
let plaintext = try ChaChaPoly.open(sealed, using: key, authenticating: aad)
let box = try ChaChaPoly.SealedBox(combined: combined)
let nonce = ChaChaPoly.Nonce()
AES Key Wrapping
let wrapped = try AES.KeyWrap.wrap(keyToWrap, using: wrappingKey)
let unwrapped = try AES.KeyWrap.unwrap(wrapped, using: wrappingKey)
Key Agreement (ECDH)
Supported Curves
| Curve | Type Prefix | Key Size | Use |
|---|
| Curve25519 | Curve25519.KeyAgreement | 32 bytes | Modern, fast, safe defaults |
| P-256 | P256.KeyAgreement | 32 bytes | NIST standard, Secure Enclave |
| P-384 | P384.KeyAgreement | 48 bytes | Higher security NIST |
| P-521 | P521.KeyAgreement | 66 bytes | Maximum NIST security |
Private Key Creation
let privateKey = Curve25519.KeyAgreement.PrivateKey()
let privateKey = P256.KeyAgreement.PrivateKey()
let privateKey = P256.KeyAgreement.PrivateKey(compactRepresentable: true)
let privateKey = try P256.KeyAgreement.PrivateKey(rawRepresentation: rawData)
let privateKey = try P256.KeyAgreement.PrivateKey(derRepresentation: derData)
let privateKey = try P256.KeyAgreement.PrivateKey(pemRepresentation: pemString)
let privateKey = try P256.KeyAgreement.PrivateKey(x963Representation: x963Data)
Public Key Representations
let publicKey = privateKey.publicKey
publicKey.rawRepresentation
publicKey.derRepresentation
publicKey.pemRepresentation
publicKey.x963Representation
publicKey.compactRepresentation
publicKey.compressedRepresentation
Shared Secret Derivation
let sharedSecret = try privateKey.sharedSecretFromKeyAgreement(with: peerPublicKey)
let symmetricKey = sharedSecret.hkdfDerivedSymmetricKey(
using: SHA256.self,
salt: saltData,
sharedInfo: infoData,
outputByteCount: 32
)
let symmetricKey = sharedSecret.x963DerivedSymmetricKey(
using: SHA256.self,
sharedInfo: infoData,
outputByteCount: 32
)
Signatures (ECDSA/EdDSA)
Supported Algorithms
| Curve | Algorithm | Type Prefix |
|---|
| Curve25519 | Ed25519 (EdDSA) | Curve25519.Signing |
| P-256 | ECDSA | P256.Signing |
| P-384 | ECDSA | P384.Signing |
| P-521 | ECDSA | P521.Signing |
Key Creation
let privateKey = P256.Signing.PrivateKey()
let privateKey = Curve25519.Signing.PrivateKey()
Sign and Verify
let signature = try privateKey.signature(for: data)
let digest = SHA256.hash(data: data)
let signature = try privateKey.signature(for: digest)
let valid = privateKey.publicKey.isValidSignature(signature, for: data)
let valid = privateKey.publicKey.isValidSignature(signature, for: digest)
Signature Representations
signature.derRepresentation
signature.rawRepresentation
let sig = try P256.Signing.ECDSASignature(derRepresentation: derData)
let sig = try P256.Signing.ECDSASignature(rawRepresentation: rawData)
signature.rawRepresentation
Cross-Platform Encoding
Use derRepresentation when exchanging signatures with non-CryptoKit systems (OpenSSL, Java, Go). Use rawRepresentation for CryptoKit-to-CryptoKit or when wire size matters (DER adds 6-8 bytes overhead).
Post-Quantum Cryptography: ML-KEM
Key Encapsulation Mechanism based on Module-Lattice (FIPS 203). iOS 18.4+.
Parameter Sets
| Type | Security Level | Public Key | Ciphertext | Shared Secret |
|---|
| MLKEM768 | 128-bit (AES-128 equivalent) | 1,184 bytes | 1,088 bytes | 32 bytes |
| MLKEM1024 | 256-bit (AES-256 equivalent) | 1,568 bytes | 1,568 bytes | 32 bytes |
Key Generation
let privateKey = MLKEM768.PrivateKey()
let publicKey = privateKey.publicKey
let privateKey = MLKEM1024.PrivateKey()
Encapsulation and Decapsulation
let result = try recipientPublicKey.encapsulate()
let sharedSecret = try privateKey.decapsulate(result.encapsulatedKey)
Key Representations
publicKey.rawRepresentation
privateKey.rawRepresentation
privateKey.seedRepresentation
let pk = try MLKEM768.PrivateKey(rawRepresentation: rawData)
let pk = try MLKEM768.PrivateKey(seedRepresentation: seedData)
let pk = try MLKEM768.PrivateKey(integrityCheckedRepresentation: data)
Post-Quantum Cryptography: ML-DSA
Digital Signature Algorithm based on Module-Lattice (FIPS 204). iOS 18.4+.
Parameter Sets
| Type | Security Level | Public Key | Signature |
|---|
| MLDSA65 | 128-bit | 1,952 bytes | 3,309 bytes |
| MLDSA87 | 256-bit | 2,592 bytes | 4,627 bytes |
Key Generation
let privateKey = MLDSA65.PrivateKey()
let publicKey = privateKey.publicKey
let privateKey = MLDSA87.PrivateKey()
Sign and Verify
let signature = try privateKey.signature(for: data)
let signature = try privateKey.signature(for: data, context: contextData)
let valid = publicKey.isValidSignature(signature, for: data)
let valid = publicKey.isValidSignature(signature, for: data, context: contextData)
Key and Signature Representations
publicKey.rawRepresentation
privateKey.rawRepresentation
privateKey.seedRepresentation
let pk = try MLDSA65.PrivateKey(rawRepresentation: rawData)
let pk = try MLDSA65.PrivateKey(seedRepresentation: seedData)
signature.rawRepresentation
let sig = try MLDSA65.Signature(rawRepresentation: rawData)
Hybrid Post-Quantum: X-Wing KEM
Combines ML-KEM768 + Curve25519 ECDH for hybrid post-quantum key exchange. If either algorithm holds, the combined scheme holds. iOS 18.4+.
let privateKey = XWingMLKEM768X25519.PrivateKey()
let publicKey = privateKey.publicKey
let result = try publicKey.encapsulate()
let sharedSecret = try privateKey.decapsulate(result.encapsulatedKey)
publicKey.rawRepresentation
privateKey.rawRepresentation
privateKey.seedRepresentation
HPKE (Hybrid Public Key Encryption)
Hybrid Public Key Encryption (RFC 9180). Combines KEM + KDF + AEAD into a single encryption scheme. iOS 17+ (classical ciphersuites). Post-quantum ciphersuites (XWing) require iOS 26+.
Predefined Ciphersuites
| Ciphersuite | KEM | KDF | AEAD |
|---|
.XWingMLKEM768X25519_SHA256_AES_GCM_256 | X-Wing | HKDF-SHA256 | AES-256-GCM |
.Curve25519_SHA256_ChachaPoly | Curve25519 | HKDF-SHA256 | ChaCha20Poly1305 |
.Curve25519_SHA256_AES_GCM_128 | Curve25519 | HKDF-SHA256 | AES-128-GCM |
.Curve25519_SHA256_AES_GCM_256 | Curve25519 | HKDF-SHA256 | AES-256-GCM |
.P256_SHA256_AES_GCM_128 | P-256 | HKDF-SHA256 | AES-128-GCM |
.P256_SHA256_AES_GCM_256 | P-256 | HKDF-SHA256 | AES-256-GCM |
.P384_SHA384_AES_GCM_256 | P-384 | HKDF-SHA384 | AES-256-GCM |
.P521_SHA512_AES_GCM_256 | P-521 | HKDF-SHA512 | AES-256-GCM |
Custom Ciphersuite Composition
let ciphersuite = HPKE.Ciphersuite(
kem: .Curve25519_HKDF_SHA256,
kdf: .HKDF_SHA256,
aead: .AES_GCM_128
)
KEM Options
.Curve25519_HKDF_SHA256, .P256_HKDF_SHA256, .P384_HKDF_SHA384, .P521_HKDF_SHA512, .XWingMLKEM768X25519_SHA256
KDF Options
.HKDF_SHA256, .HKDF_SHA384, .HKDF_SHA512
AEAD Options
.AES_GCM_128, .AES_GCM_256, .chaChaPoly, .exportOnly
Sender (Encrypt)
var sender = try HPKE.Sender(
recipientKey: recipientPublicKey,
ciphersuite: .Curve25519_SHA256_ChachaPoly,
info: infoData
)
let ciphertext = try sender.seal(plaintext)
let ciphertext = try sender.seal(plaintext, authenticating: aad)
let encapsulatedKey = sender.encapsulatedKey
let exported = try sender.exportSecret(context: ctx, outputByteCount: 32)
Recipient (Decrypt)
var recipient = try HPKE.Recipient(
privateKey: recipientPrivateKey,
ciphersuite: .Curve25519_SHA256_ChachaPoly,
info: infoData,
encapsulatedKey: encapsulatedKey
)
let plaintext = try recipient.open(ciphertext)
let plaintext = try recipient.open(ciphertext, authenticating: aad)
let exported = try recipient.exportSecret(context: ctx, outputByteCount: 32)
Additional Modes
Both Sender and Recipient accept optional authentication and PSK parameters:
var sender = try HPKE.Sender(
recipientKey: recipientPublicKey, ciphersuite: ciphersuite, info: infoData,
authenticatedBy: senderPrivateKey
)
var recipient = try HPKE.Recipient(
privateKey: recipientPrivateKey, ciphersuite: ciphersuite, info: infoData,
encapsulatedKey: encapsulatedKey, authenticatedBy: senderPublicKey
)
HPKE Error Types
HPKE.Errors.sealFailure
HPKE.Errors.openFailure
HPKE.Errors.encapsulationFailure
HPKE.Errors.decapsulationFailure
HPKE.Errors.exportFailure
Secure Enclave
Hardware-backed key storage. Keys never leave the Secure Enclave chip. Device-bound and non-exportable.
Availability Check
SecureEnclave.isAvailable
Supported Key Types
| Type | Use |
|---|
SecureEnclave.P256.Signing.PrivateKey | ECDSA signatures |
SecureEnclave.P256.KeyAgreement.PrivateKey | ECDH key agreement |
SecureEnclave.MLKEM768.PrivateKey | Post-quantum KEM (iOS 18.4+) |
SecureEnclave.MLKEM1024.PrivateKey | Post-quantum KEM (iOS 18.4+) |
SecureEnclave.MLDSA65.PrivateKey | Post-quantum signatures (iOS 18.4+) |
SecureEnclave.MLDSA87.PrivateKey | Post-quantum signatures (iOS 18.4+) |
Key Creation
let key = try SecureEnclave.P256.Signing.PrivateKey()
let accessControl = SecAccessControlCreateWithFlags(
nil, kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
[.privateKeyUsage, .biometryCurrentSet], nil
)!
let key = try SecureEnclave.P256.Signing.PrivateKey(accessControl: accessControl)
let context = LAContext()
context.localizedReason = "Sign transaction"
let key = try SecureEnclave.P256.Signing.PrivateKey(
accessControl: accessControl, authenticationContext: context
)
Persistence and Usage
let wrapped = key.dataRepresentation
let restored = try SecureEnclave.P256.Signing.PrivateKey(dataRepresentation: wrapped)
let restored = try SecureEnclave.P256.Signing.PrivateKey(
dataRepresentation: wrapped, authenticationContext: context
)
let signature = try seKey.signature(for: data)
let valid = seKey.publicKey.isValidSignature(signature, for: data)
let publicKeyData = seKey.publicKey.derRepresentation
Key Derivation (HKDF)
HMAC-based Key Derivation Function (RFC 5869).
One-Step Derivation
let derivedKey = HKDF<SHA256>.deriveKey(
inputKeyMaterial: SymmetricKey(data: ikm),
salt: saltData,
info: infoData,
outputByteCount: 32
)
Two-Step (Extract + Expand)
Use two-step when deriving multiple keys from the same input: extract once, expand with different info values.
let prk = HKDF<SHA256>.extract(inputKeyMaterial: SymmetricKey(data: ikm), salt: saltData)
let encKey = HKDF<SHA256>.expand(pseudoRandomKey: prk, info: Data("enc".utf8), outputByteCount: 32)
let macKey = HKDF<SHA256>.expand(pseudoRandomKey: prk, info: Data("mac".utf8), outputByteCount: 32)
Error Types
CryptoKitError
CryptoKitError.incorrectKeySize
CryptoKitError.incorrectParameterSize
CryptoKitError.authenticationFailure
CryptoKitError.underlyingCoreCryptoError(error:)
CryptoKitError.wrapFailure
CryptoKitError.unwrapFailure
CryptoKitASN1Error
CryptoKitASN1Error.invalidASN1Object
CryptoKitASN1Error.invalidASN1IntegerEncoding
CryptoKitASN1Error.truncatedASN1Field
CryptoKitASN1Error.invalidFieldIdentifier
CryptoKitASN1Error.unexpectedFieldType
CryptoKitASN1Error.invalidObjectIdentifier
CryptoKitASN1Error.invalidPEMDocument
HPKE and KEM Errors
HPKE.Errors.sealFailure
HPKE.Errors.openFailure
HPKE.Errors.encapsulationFailure
HPKE.Errors.decapsulationFailure
HPKE.Errors.exportFailure
KEM.Errors.decapsulationFailed
Swift Crypto Cross-Platform Parity
Apple's open-source swift-crypto provides CryptoKit APIs on Linux, Windows, and other platforms.
Import Difference
#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif
API Parity
Everything maps 1:1 except SecureEnclave.* (requires Apple hardware). Hashing, HMAC, AES-GCM, ChaChaPoly, ECDH, ECDSA/EdDSA, ML-KEM, ML-DSA, X-Wing, HPKE, HKDF, and AES Key Wrap are all available cross-platform.
.package(url: "https://github.com/apple/swift-crypto.git", from: "3.0.0")
Resources
WWDC: 2019-709, 2024-10120
Docs: /cryptokit, /cryptokit/performing-common-cryptographic-operations, /security/certificate-key-and-trust-services/keys/storing-keys-in-the-secure-enclave
Skills: axiom-cryptokit