There are two big issues I didn't see addressed in the Swift Crypto docs made available so far.
Is it a goal, explicit non-goal, or undecided to implement crypto primitives and algorithms in native Swift, eventually removing the need for BoringSSL? Personally, I think it would be a benefit to the language and library to move in that direction, but I'd like to know if PRs in that direction would be accepted.
Is it a goal, explicit non-goal, or undecided to enable the use of SwiftCrypt to backwards deploy the CryptoKit APIs on Apple's platforms? It seems you can build the BoringSSL version for Apple platforms, but I wonder if work towards making it easier to backward deploy would be accepted. If not, the CryptoSwift library would likely continue to be my goto on Apple platforms, especially if it, too, adopts a CryptoKit compatible API layer.
Off-topic, but my fingers are that if import Crypto re-imports CryptoKit on darwin that we might eventually see something for Combine as already mentioned upthread and maybe import UI that re-imports SwiftUI on darwin.
As Swift Crypto’s core goal is to provide a cross-platform solution for using Apple CryptoKit’s APIs on a wider range of platforms, the API will naturally follow the evolution of Apple CryptoKit itself. However, as Swift Crypto is an open source project, there is some scope for proposing API directly to Swift Crypto. Depending on the scope of these APIs, ** they may also be considered for parallel implementation in Apple CryptoKit. **
It’s a “nice to have”. Where we can reasonably do so we will implement primitives in Swift: for example, HKDF is written entirely in Swift. However, Swift has some limitations for cryptographic implementations. Some of these are capable of being improved upon: for example, we can work on tools for the language to make writing constant time code easier.
Some limitations may never be passed. For example, it is very hard to get great performance from cryptography without assembly language acceleration. While this is definitely a “never say never” space, I wouldn’t hold my breath to see us adopt pure-Swift for all primitives. That performance just unlocks too many use-cases to give up.
At this time it’s a non-goal. We are open to discussing this with the community, but enabling a back-deployment story has a number of risks. It makes vulnerability mitigation stories very complex if some primitives silently come from CryptoKit and others from Swift Crypto’s OSS backend. The joy of the current model is that you can continue to assume the platform will supply security fixes on Apple platforms: with back-deployment, that’s less true.
While I think language support for assembly literals seems necessary for Swift to have a complete systems programming story, I agree there will be some performance difference in certain areas for quite some time. However, I guess my overall proposal would be to allow users to make that choice, effectively offering a third distribution. Then the choices would be: CryptoKit overlay on Apple platforms, maximum performance BoringSSL-based distribution for other platforms, and a Swift-native distribution for those who don't need maximum performance but value a simpler dependency graph.
Actually, I'd argue that enabling backward deployment provides greater mitigation, not less, as it allows developers to deploy fixes to platforms which are no longer getting security updates. Additionally, tooling like SPM can warn or even error out when integrating library versions with vulnerabilities, it's just a matter of investing the effort to do so.
Even if you don't accept that argument, this library will likely end up being used that way anyway, officially supported or not, especially if BoringSSL becomes an optional dependency, as mentioned above.
I'm not sure about everyone, but I don't understand "pure Swift" to mean "no inline assembly"; I read it to mean "not wrapping C code". Of course there will be hardware-specific things which can only be accessed via asm.
The only tangible benefits to having things be pure Swift rather than C are (IIUC): broader generics support (e.g. sequences/collections would not need to be contiguous), and potentially enabling high-level optimisations via SIL (that's why SIL exists, right?). I'm not sure, but they don't sound like major factors for cryptography.
I'd like to note that the assembly use-case is not just for hardware specific features. Often assembly is required to limit the scope of side channels, or to ensure high performance data access patterns. As it does not involve a compiler, it is not possible for the compiler to regress the performance of such an implementation, and does not require a "sufficiently smart" optimising compiler. These performance benefits are very real, and can unlock orders of magnitude of performance improvement in common algorithms such as AES.
In principle we could try to burn down the amount of C in the codebase, but I am not confident in how much value that unlocks. For vulnerability management reasons we need to continue to bring in the assembly language implementations of the base primitives. This means we don't gain much simplification in dependency management (we still have a BoringSSL dependency).
Additionally, as you note, I think the gains it brings us are fairly minor. Don't get me wrong, I'd like to see us burn down the amount of C in this project over time, but I don't consider it a high priority to do so. Interested contributors are welcome to take a swing at it though!
Actually this would be for those who don't need maximum performance nor maximal security. Having an implementation that doesn't support constant time algorithm or side channel attack protection is unsafe, not just slower.
Moreover, the cost of maintaining a third implementation would be too high for the benefit it bring IMHO.