Swiftpack.co - Package - christophhagen/CryptoKit25519


A Swift module for Curve25519 functions and AES-GCM encryption compatible with Apple's CryptoKit.


This module provides signatures and key agreement based on Curve25519 in Swift. This library is meant to be compatible and syntactically similar to Apple's CryptoKit framework, which is only available for their recent operating systems. This library provides similar capabilities as CryptoKit.Curve25519, and has a very similar structure.


When using the Swift Package Manager, specify in Package.swift:

.package(url: "https://github.com/christophhagen/CryptoKit25519", from: "0.6.0")

Then, in your source files, simply:

import CryptoKit25519


This library is built to be very similar to Apple's CryptoKit framework, so much of the documentation there also applies to this framework. Notable differences are:

  • Operations are NOT constant-time.
  • Sensitive keys are NOT immediately zeroized after use.

Currently supported operations:

  • Signatures with Curve25519 (No support for P521, P384, or P256)
  • Key Agreement with Curve25519 (No support for P521, P384, or P256)
  • Encryption with AES-GCM (No support for ChaChaPoly)

If you need additional operations, have a look at OpenCrypto.


CryptoKit25519 requires a source of cryptographically secure random numbers to generate keys. On supported platforms (iOS 2.0+, macOS 10.7+, tvOS 9.0+, watchOS 2.0+, macCatalyst 13.0+) SecCopyRandomBytes is used as the default. On other platforms, the random bytes are calculated based on UInt8.random(in:using:).

You can provide a custom source for random numbers by setting Randomness.source:

Randomness.source = { count in
    return ... // Return a [UInt8] with `count` random bytes, or nil, if no randomness is available.

The custom source is then use for calls to the following functions:



Signing is part of public-key cryptography. Private keys can create signatures of data, while the corresponding public keys can verify the signatures.

Private Keys

When creating a signature, a private key is needed:

let privateKey = Curve25519.Signing.PrivateKey()

When the key is already available:

let privateKey = try Ed25519.PrivateKey(rawRepresentation: data)

Private keys can be converted to data:

let data = privateKey.rawRepresentation

Public Keys

Public keys are used to verify signatures. Public keys can be created from a private key:

let publicKey = privateKey.publicKey

Or, when the public key is available as data:

let publicKey = try Curve25519.Signing.PublicKey(rawRepresentation: data)

Public keys can be converted to data:

let data = publicKey.rawRepresentation


To create a signature with a private key:

let signature = privateKey.signature(for: data)

Verifying Signatures

To verify a signature with a public key:

let result: Bool = publicKey.isValidSignature(signature, for: data)

Key Agreement

Users can exchange public keys in order to establish a shared secret.

Private & Public keys

The creation of private keys is analogous to the signature case above.

let privateKey = Curve25519.KeyAgreement.PrivateKey()

Calculating shared secrets

Shared secrets can be calculated by both parties, using their private key together with the received public key.

let secret = try privateKey.sharedSecretFromKeyAgreement(with: otherPublicKey)

// Access the raw data
let data: Data = secret.rawData

Deriving key material

Shared secrets should not be used directly. Instead, feed them into a Key Derivation Function (KDF), to increase the strength of the keys.

let salt = "My application".data(using: .utf8)!
let sharedInfo = ...

let key = try secret.hkdfDerivedSymmetricKey(
            using: .sha256, 
            salt: salt, 
            sharedInfo: Data, 
            outputByteCount: 32)
// Access the raw data
let data: Data = key.rawData


CryptoKit25519 supports AES in GCM(Galois Counter Mode).

Encrypting data

let sealedBox = try AES.GCM.seal(message, using: key)

It's also possible to provide a custom nonce, and additional data to be authenticated.

let sealedBox = try AES.GCM.seal(message, using: key, nonce: AES.GCM.Nonce(), authenticating: authenticatedData)

Decrypting data

let plaintext = try AES.GCM.open(sealedBox, using: key)


This framework uses the Swift Wrapper CEd25519, as well as the CryptoSwift library for the HKDF and Encryption.

The implementation of the signature generation was partly inspired by Ed25519 for Swift 3.x.


Stars: 3


Used By

Total: 0


Optional randomness - 2020-06-04 10:05:12

Provide default implementation for random bytes, so that setting a custom randomness source becomes optional.

Random linux - 2020-06-04 09:19:22

Fix issues with random number generation on linux

These unsafe pointers - 2020-04-17 12:24:33

Fixed an issue with a memory leak when initializing a Curve25519.Signing.PrivateKey.

Compatibility ensured - 2020-02-02 15:48:22

Fix compatibility issues with Apple CryptoKit

  • Signing.PrivateKeys are now computed correctly
  • Normalization for KeyAgreement.PrivateKey
  • AES.GCM encryption compatibility ensured
  • Test cases added to compare with Apple CryptoKit

Default randomness - 2020-02-01 18:01:09

  • On supported platforms SecRandomCopyBytes is used to provide random numbers.
  • All private keys are now normalized, to mimic the behavior of Apple CryptoKit.

No comparison - 2020-01-14 22:38:28

Keys and nonces now conform to Hashable and Equatable.

Exterminate - 2020-01-13 19:03:49

Repairs the key agreement API by fixing some bugs.

Encryption Support - 2020-01-13 15:02:36

Minor turbulence - 2020-01-13 13:05:54

Reaching cruising altitude - 2020-01-13 12:49:02

First public flight - 2020-01-08 14:50:39

All functions and variables are now public.

First flight - 2020-01-06 23:51:42

Provide an API similar to Apple's CryptoKit Framework.

Test Release V2 - 2020-01-06 21:56:28

Test release - 2020-01-06 20:25:07