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, this source MUST be provided before any of the following operations are performed:
Curve25519.Signing.PrivateKey()
Curve25519.KeyAgreement.PrivateKey()
SymmetricKey(size:)
AES.GCM.Nonce()
AES.GCM.seal(_:key:nonce:authenticating)
You can provide random numbers by setting Randomness.source
:
Randomness.source = { count in
return ... // Return `count` random bytes, or nil, if no randomness is available.
}
Signing is part of public-key cryptography. Private keys can create signatures of data, while the corresponding public keys can verify the signatures.
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 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)
To verify a signature with a public key:
let result: Bool = publicKey.isValidSignature(signature, for: data)
Users can exchange public keys in order to establish a shared secret.
The creation of private keys is analogous to the signature case above.
let privateKey = Curve25519.KeyAgreement.PrivateKey()
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
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).
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)
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.