Cryptography for the Swift ecosystem

I know I'm taking on a big topic here, especially considering the amount of influence a project like this has and the opinions that are going to be raised. Every single piece of public and internal APIs will be questioned, although there are hard specs that will remain.

The initial topic I'm creating will contain my open questions. I'll be adding my own separate reply to this topic with my own opinions and ideas.

Cryptography

Cryptography is a very broadly applied set of technologies and consists of many aspects. To name a few:

  • Cryptographic Hash Functions
  • Symmetric Key Cryptography
  • Public-Key cryptography

And many derived techniques and technologies such as:

  • Key Derivation Functions
  • Message Authenticators
  • Diffie-Hellman Key exchange
  • SSL
  • Blockchain

The Scope

As you read above, there is a wide variety of technologies that are related to cryptography in a broad sense.

I think it's important for those that are interested in a project like this to define and share your opinion of a scope and API. For this reason I compiled a list of questions that you can fill out.

Feel free to bring up opinions and feedback related to this idea forward, irregardless of the questions below.

Some Questions

Should cryptography be solely or partially reliant on CommonCrypto/libcrypto/the platform's preferred library? And if so, how are algorithms outside of the platform's support treated?

Does cryptography need to be implemented in Swift or C, or is this decided on a case-by-case basis?

The world is still full of old technology. Do "ancient" algorithms such as MD4 be implemented in this project either now or later down the line?

Should the API work with pointers, (Contiguous)Arrays, Collections, Strings or a combination of these?

Would the API support common representations of information such as hexadecimal and Base64?

Does an algorithm such as a hash function be a struct or a class?

What kind of features should be implemented and which should not. Why do you think so?
Think of the following non-exhaustive list in no particular order:

  • AES
  • BCrypt
  • Blockchain
  • Blowfish
  • DES
  • Diffie-Hellman
  • ECC
  • ECDSA
  • HMAC
  • MD4
  • MD5
  • PBKDF1
  • PBKDF2
  • PEM
  • PGP
  • ROT13
  • RSA
  • SHA0
  • SHA1
  • SHA2 (and its variations such as SHA256 and SHA512)
  • SHA3
  • TLS
2 Likes

Swift does not support yet all the features required to implements efficient cryptography functions, as some algorithms require access to low level CPU intrinsic (AES-NI, …).

So at least for some algorithms, it should drop down to lower level languages.

For this topic, I would definitely want to rope in the CryptoSwift project.

CC @krzyzanowskim

2 Likes

Should cryptography be solely or partially reliant on CommonCrypto/libcrypto/the platform's preferred library? And if so, how are algorithms outside of the platform's support treated?

Does cryptography need to be implemented in Swift or C, or is this decided on a case-by-case basis?

I think that some algorithms should rely on hardware accelerated chips such as AES-NI. Therefore, the implementation should be either written using the platform's preferred library.

I believe that other tools, such as MD5 and the SHA series of hashes should be written in Swift so that we can provide a good set of APIs without many any performance sacrifice that the C interop or wrapper may have.

The world is still full of old technology. Do "ancient" algorithms such as MD4 be implemented in this project either now or later down the line?

I think that these algorithms should be supported, although we may consider adding them to an "DeprecatedCrypto" namespace to prevent people from using these without understanding that they're old and unsafe.

Should the API work with pointers, (Contiguous)Arrays, Collections, Strings or a combination of these?

I think that, unlike CryptoSwift, the raw APIs should be written using pointers. This is a huge game changer when it comes to performance as I have proven with a few of my PRs and own cryptographic implementations as found in the older Vapor Crypto project.

This does not mean that I believe the other types should be excluded. CryptoSwift provides a really nice and useful API for common cryptographic use cases. Therefore the implementation should, in my opinion, be closer to a C library. But the public APIs that CryptoSwift exposes are really good.

Would the API support common representations of information such as hexadecimal and Base64?

Seeing that Base64 is very common when using encryption, I think so. Although I don't have a strong opinion on this.

Does an algorithm such as a hash function be a struct or a class ?

Definitely a struct. First of all there's an obvious performance difference. And aside from that, classes could be shared between multiple threads and cause trouble when trying to reuse the same class for a hash. This could be problematic to the unaware programmer.

What kind of features should be implemented and which should not. Why do you think so?

I think for the current scope, the goal should be to implement cryptographic primitives. This way there are fewer subjective decisions to be made and the scope is well defined.

Overall, I agree with much of what you said.

As a minor bikeshed moment - I would probably use the phrase "Legacy" or even "Unsafe" rather than "Deprecated", as this library wouldn't be a governing authority on the algorithm, and algorithms are free-floating mathematical constructs that their use is just superseded in usage simply due to advances in software development.

"Unsafe" to denote that they're weaker than they used to be, but I would prefer "Legacy" because they're still used when interacting with older libraries and interfaces, but perhaps not recommended for use in new areas.

3 Likes

I agree with that. LegacyCrypto sounds more accurate for sure.

@krzyzanowskim what is your take on this?

I am not saying that we should or should not do this, but swift has access to all of these low level intrinsics as builtins if we need since we have access to all llvm intrinsics. It would just take work in the stdlib to expose it (since the stdlib can access this sort of thing directly).

3 Likes

I have an impression (though didn't do research) that it was discussed like... ~2 years ago or so, and it was decided to rely on platform (C based) libraries that evolved from openssl (boringssl etc).

However.

Is Swift a good language to implement crypto primitives?

No, it's not good. It neither provide good API nor low-level capabilities.

At this point it is worth to mention that Swift standard library already uses implementation of MD5, SHA1 https://github.com/apple/swift/blob/b630380c0a401af7961a54693897bca2c4c9fb60/benchmark/single-source/Hash.swift, some Swift projects even expose SHA256 as a public https://github.com/apple/swift-package-manager/blob/26d456594d3572f3822a794cacebd8e0b653ad70/Sources/Basic/SHA256.swift#L13 API, that were introduced without much of consideration AFAIK.

Should the API work with pointers, (Contiguous)Arrays, Collections, Strings or a combination of these?

Over the course of improving CryptoSwift performance I did move to pointers. It did help of course. It didn't solve all problems though. The main performance problem of Swift is allocation and copying. This can be addressed using raw memory buffers. The other is dynamic dispatching and non-specialized generics. All the small pieces make Swift hard to implement highly efficient code. It need eg. manual force of inlining or copy code here and there to improve optimization - that may change with any Swift release. I outlined some of it in one of my presentation (if you find it interesting): https://speakerdeck.com/krzyzanowskim/slow-swift

Does an algorithm such as a hash function be a struct or a class?

It doesn't really matter. This is an implementation detail. What matter is API. It's not that struct is better or faster than class or anything like that.

Would low-level access help?

definitely! If we could inject asm directly from swift, that'd make a lot of sense. I don't think it's a Swift priority though (I remember PR with the feature, but never merged).

Legal

Another consideration is a law. Some countries require certification, or registry entries, etc etc. Who'd manage it? CommonCrypto is managed by Apple, and I guess one of the reasons why it provides archaic API is certification it already have. (FIPS takes years to get and cost dozens of thousands of dollars).

2 Likes

Thanks @Joannis_Orlandos for raising this issue. I think it is of critical importance but also, as you say, a very big topic.

As others have mentioned, pure Swift is not a great choice for implementing crypto today. This is why IBM decided to solve our crypto needs by implementing a set of Swift APIs which delegate the actual crypto to underlying platform frameworks.

We have created the following packages:

  1. BlueCryptor - digests/hashing inc. MD5, SHA256 etc., PBKDF key derivation, HMAC, AES, DES, Blowfish, etc.
  2. BlueRSA - RSA encryption/decryption/signing inc. RSA-PSS.
  3. BlueECC - ECDSA and ECIES
  4. BlueSSLService - TLS (this is rather tied to the Kitura ecosystem)

For each of these, the underlying crypto is delegated to OpenSSL on Linux, and CommonCrypto/SecureTransport on Darwin. This has proven to be a successful approach for us, although supporting both OpenSSL 1.0 and 1.1 has been painful (shout out to @lukasa for finding the solution here!)

Another approach is the path the NIO team has taken with GitHub - apple/swift-nio-ssl: TLS Support for SwiftNIO, based on BoringSSL. where they vendor BoringSSL and use that instead of a platform framework (they also have GitHub - apple/swift-nio-transport-services: Extensions for SwiftNIO to support Apple platforms as first-class citizens. which uses Network.framework).

So I think there are two viable approaches:

  1. The NIO approach, build Swift APIs on a vendored impl. like BoringSSL
  2. The IBM approach, build Swift APIs on platform frameworks

There are pros and cons of each, but they are both proven to work.

In terms of what the Swift APIs should look like, I think the approach taken by GitHub - google/tink: Tink is a multi-language, cross-platform, open source library that provides cryptographic APIs that are secure, easy to use correctly, and hard(er) to misuse. is very interesting and has already been used across a variety of languages.

The size, complexity and risks of a project like this should not be underestimated... but it has to happen eventually for Swift to succeed. We are already seeing proposals for things like APNS which require JWT, which obviously require crypto. Ideally we would be building a stack from the bottom up and tackling the crypto primitives first.

1 Like

While I understand the arguments against using Swift for crypto today, is there a point in the future (foreseeable or not) where Swift would be a viable candidate for implementing cryptographic algorithms?

If so, when and what are we waiting for?
If not, when and what are we waiting on?

1 Like

Waiting for Apple blessing, otherwise it's blasphemy.

Who's waiting? CryptoSwift is 5yo and extremely popular in the community, yet not much contributing. Wanna build the future today? there's a codebase that wait for you.

2 Likes

Apple / the core team also need to decide what the official non-standard library distribution model will be going forward. Maybe we’ll learn something today.

I agree with you. Swift crypto is in many areas viable. But some features like AES-NI cannot be leveraged. If that's all we're waiting for, then let's do AES in C, and the rest in Swift.

I don't think that's a blocker for the server-side ecosystem. We have a distribution story through SPM and it's working so far for NIO and the frameworks on top of it.

(there are plenty of ways SPM needs to improve but it is viable)

Sorry, I was talking more about what prevents there being an official Swift crypto package, not crypto packages in general. Without a way to just say import Crypto and go, we’re not there yet.

1 Like

OK. This is moot for SSWG which is chartered to produce and recommend libraries and tools outside the Swift language project itself. But I actually don't think this is a problem - there is nothing stopping import Crypto from being delivered via SPM and the Server-side Swift ecosystem is already 100% SPM today.

Sorry, forgot this was a server side thread.

Given that fairly good wrappers around the various crypto libraries exist, I’d rather see a the effort put towards enhancing Swift for crypto usage and a native library rather than making a wrapper official. But if we do want an official package in the short term, I think it would be beneficial to make it clear that it is a wrapper while focusing efforts on the native package.

1 Like

I wish I was in San Jose: Cryptography and Your Apps - WWDC19 - Videos - Apple Developer

2 Likes

Until then, documentation and sample code is available. PSOTU is gonna be wild.

https://developer.apple.com/documentation/cryptokit

They had the unique chance to make it non-apple platform only, and they didn't

6 Likes