# swift-crypto: CryptoKit's API on Linux, with BoringSSL underneath

> swift-crypto re-implements the parts of Apple's CryptoKit API that do not need specialised hardware so the same Swift code runs on Linux and ARM64 Windows. On Apple platforms it compiles away and forwards to CryptoKit; everywhere else it links vendored BoringSSL and XKCP.

**apple/swift-crypto** — Open-source implementation of a substantial portion of the API of Apple CryptoKit suitable for use on all Swift supported platforms.

- Repository: https://github.com/apple/swift-crypto
- Website: https://swiftpackageindex.com/apple/swift-crypto/documentation/crypto
- Stars: 1,734 · Forks: 236
- Language: Assembly
- License: Apache-2.0
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/apple-swift-crypto

## One API surface, two completely different builds

The defining design decision of swift-crypto is that the same source code behaves differently depending on where it is compiled. On an Apple platform where CryptoKit already exists, the package compiles its entire API surface down to nothing and re-exports CryptoKit. The README is blunt about the consequence: all work is delegated to Apple's implementation, as though swift-crypto were not there.

On other platforms the build is real. The project vendors a copy of BoringSSL's libcrypto and a copy of XKCP's libXKCP, layers the shared API on top, and implements that API by calling into those two libraries. The API code and some primitives written directly in Swift are identical in both builds; only the backing implementation is unique to swift-crypto.

This means your source does not change when you deploy to a different operating system, which is the whole point for server applications. It also means you cannot assume identical behaviour across platforms just because the calls look the same. The Linux path runs BoringSSL; the macOS path runs whatever CryptoKit runs.

## Adding it takes one package entry and one import

Integration is Swift Package Manager only. There is no CocoaPods or Carthage path described in the README, and no manual vendoring instructions. Declare the dependency in Package.swift, then add `Crypto` to your target dependencies and import it:

```swift
// swift-crypto 1.x, 2.x, 3.x, 4.x, and 5.x are almost API compatible, so most clients
// should allow any of them
.package(url: "https://github.com/apple/swift-crypto.git", "1.0.0" ..< "6.0.0"),
```

```swift
import Crypto
```

That version range is unusually wide and it is deliberate: the comment in the README says the 1.x through 5.x lines are almost API compatible, so most clients should allow any of them. The trade-off is real. A range that wide lets a dependency update land under you without a code change on your side, and the qualifier is almost API compatible rather than API compatible. Teams that need reproducible builds should narrow the range to the major line they have validated.

## CryptoExtras pulls BoringSSL into your binary on every platform

There is a third product in the repository, `CryptoExtras`, which offers functionality that CryptoKit does not have, described as cryptographic APIs predominantly useful in the server ecosystem. The README attaches a warning that is easy to skim past: if you depend on CryptoExtras you will bundle the BoringSSL and XKCP implementation of the library in your application, no matter the platform.

That sentence removes the main operational advantage of the re-export design. On Apple platforms swift-crypto normally costs you nothing at runtime because CryptoKit does the work; depend on CryptoExtras and you carry a vendored copy of two C libraries in every binary, including the ones you ship to iOS or macOS. Binary size and the licence obligations of the vendored code become your problem at that point, on every target.

## New APIs land in Staging or Server and may never graduate

swift-crypto tracks the current version of CryptoKit, and patches that extend the API are evaluated cautiously. A new API has two possible destinations. If it is judged generally valuable and suitable for contribution to CryptoKit, it is merged into a `Staging` namespace: a temporary home for something expected to arrive in CryptoKit but unavailable today. Once it ships in CryptoKit, the Staging copy is deprecated and the API is promoted to the main namespace.

If an API does not meet the bar for general CryptoKit but matters for server use, it is merged into a `Server` namespace instead, and the README states plainly that APIs are not expected to leave it. Anything you call from `Server` is Swift-Crypto-only and has no upstream destination.

The practical consequence is a three-tier namespace to check before you commit to a function: main, Staging, Server. Code written against Staging will need a source change when the API graduates, because the deprecation is deliberate rather than accidental.

## 3DES will never be there, and other legacy primitives are refused on purpose

swift-crypto does not attempt to cover every cryptographic algorithm, and the README says so without hedging. The stated focus is safe, modern primitives that are broadly useful and do not lend themselves to misuse. The worked example is 3DES: the project says it is highly unlikely to ever be supported, because of the difficulty of deploying it safely and its legacy status.

The contribution guide turns that into a screening process. Anyone proposing a new primitive is expected to answer what the primitive is for, how widely it is deployed, whether it appears in a public specification, how easy it is to misuse, and in what way swift-crypto fails to satisfy the use case today. A proposal may simply be refused on those grounds, and the maintainers say so in advance.

This is the clearest wrong-tool case in the project. If your system has to interoperate with a legacy peer that only speaks an old cipher or an old hash, no amount of waiting will produce a swift-crypto implementation, and you need a different library that offers the primitive with its sharp edges exposed.

## The _boring and _xkcp suffixes decide how hard your change is

The repository layout encodes its own contribution policy. Files whose names end in `_boring` or `_xkcp`, or that live under a `BoringSSL` or `XKCP` directory, are implementation-specific and easy to change. The test is mechanical: if the file needs to `import CCryptoBoringSSL` or `import CXKCP`, or touches a BoringSSL or XKCP API, it belongs in that group.

Everything else is public CryptoKit API surface, and changing it carries a higher bar because any such change has to be accompanied by a matching change in CryptoKit itself. That is a sensible proxy for blast radius, and it also tells a reader of the codebase where to look when behaviour differs between platforms: the difference has to be in a `_boring` or `_xkcp` file.

The top level also carries a Benchmarks directory, CMakeLists.txt, cmake/, dev/ and scripts/, plus SECURITY.md, CONTRIBUTING.md and LICENSE.txt. Part of the source is autogenerated with Apple's gyb tool, described in the README as generate your boilerplate, so some files are templates rather than files to edit by hand.

## Version 5 is current, and the Apache-2.0 licence covers the vendored C

Release 5.0.0 was tagged on 2026-09-16, followed by 5.0.1 on 2026-10-12, with 4.5.2 on 2026-09-02 before it. The last push to the repository was on 2026-10-12, the same day as 5.0.1, so the project is being worked on and released on a regular cadence rather than left to drift. Since BoringSSL is vendored, a swift-crypto update is also how you pick up upstream C library fixes, which is the main reason to move promptly when a release lands.

The repository is licensed under Apache-2.0, with LICENSE.txt and NOTICE.txt at the top level and a .licenseignore file. Apache-2.0 requires preservation of notices when you redistribute, which for a server deployment usually means keeping NOTICE.txt alongside the binary. This is a note about obligations in the licence text, not legal advice; teams with a formal review process should run their own check over the vendored BoringSSL and XKCP notices.

Issues with CryptoKit itself are not handled here. The README routes CryptoKit bug reports to Apple's Feedback Assistant, and reserves GitHub for swift-crypto bugs, with regression tests expected alongside any fix.

## Conclusion

Adopt swift-crypto if your Swift service runs on Linux and you want CryptoKit-shaped calls instead of a C library binding, and pin the version range you tested rather than the whole 1.0.0 to 6.0.0 span the README suggests. Do not adopt it for legacy primitives such as 3DES, which the project says it will likely never support, and do not reach for CryptoExtras unless you accept bundling the BoringSSL and XKCP build into your binary on Apple platforms too. Before integrating, check that every primitive your code calls is in the main namespace rather than Staging or Server.

## FAQ

### How do I add swift-crypto to a Swift project?

Add the SwiftPM dependency to Package.swift with `.package(url: "https://github.com/apple/swift-crypto.git", "1.0.0" ..< "6.0.0")`, add `Crypto` to your target dependencies, and then `import Crypto`. The README states that most clients should allow any of the 1.x to 5.x versions because they are almost API compatible.

### Does swift-crypto work on Linux and Windows?

Yes. It is described as an open-source implementation of a substantial portion of the CryptoKit API suitable for Linux and ARM64 Windows platforms. On Apple platforms it compiles down to a re-export of CryptoKit.

### What is the difference between Swift Crypto and CryptoExtras?

CryptoExtras provides additional functionality that CryptoKit does not offer, with APIs aimed at server use cases. Depending on it means bundling the BoringSSL and XKCP implementation into your application regardless of platform.

### Will swift-crypto ever support 3DES?

The README says 3DES is highly unlikely to ever be supported, because of the difficulty of deploying it safely and its legacy status. More generally, the project focuses on modern primitives that are hard to misuse and may refuse new primitive proposals.

### What are the Staging and Server namespaces in swift-crypto?

Staging is a temporary namespace for APIs expected to arrive in CryptoKit, and members are deprecated there once they become generally available in the main namespace. Server holds APIs considered useful for server use but not eligible for CryptoKit, and the README says APIs are not expected to leave that namespace.

### What license is swift-crypto under?

Apache-2.0, with LICENSE.txt and NOTICE.txt in the repository root alongside a .licenseignore file. The current release line is 5.x, with 5.0.1 tagged on 2026-10-12.

## Sources

- [apple/swift-crypto on GitHub](https://github.com/apple/swift-crypto)
- [License: Apache-2.0](https://github.com/apple/swift-crypto/blob/main/LICENSE)
- [Project website](https://swiftpackageindex.com/apple/swift-crypto/documentation/crypto)
- [README](https://github.com/apple/swift-crypto/blob/main/README.md)
- [Releases](https://github.com/apple/swift-crypto/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/apple-swift-crypto
