A pure1 Swift library for parsing and creating PGP RFC 4880 public keys, user ids, and signatures. This library is designed to be public-key-cryptography-implementation-agnostic. That is, you can use swift-pgp with any public-key crypto implementation you choose, provided it is either an RSA or Ed25519 cryptosystem.
1. Except for SHA hash functions from CommonCrypto.
This library was created for Krypton. For more information, check out krypt.co.
Currently, swift-pgp only signatures for certifications and binary documents, but it's abstracted to support the full RFC 4880 spec, see the next section for whats in the pipeline.
-
Public Keys: parse and create PGP public keys
- RSA
- Ed25519 (via ext. eddsa draft)
-
Signatures: parse and create PGP Signatures
- Certify Public Key <> User ID binding (aka Certification Signatures)
- Binary Documents
-
ASCII Armor: parse and create ASCII armored PGP messages
The next phase of swift-pgp is to support formatting PGP encrypted messages. This will add support for parsing and creating structures like:
- Symmetric-Key Encrypted Session Keys
- Symmetrically Encrypted Data
- `git submodule init; git submodule add [email protected]:kryptco/swift-pgp
- Drag PGPFormat.xcodeproj/ to your project (don't check copy files, they're already there)
- Add
CommonCrypto
to your project:
Go to Build Phases and add this run script
phase:
modulesDirectory=$DERIVED_FILES_DIR/modules
modulesMap=$modulesDirectory/module.modulemap
modulesMapTemp=$modulesDirectory/module.modulemap.tmp
mkdir -p "$modulesDirectory"
cat > "$modulesMapTemp" << MAP
module CommonCrypto [system] {
header "$SDKROOT/usr/include/CommonCrypto/CommonCrypto.h"
export *
}
MAP
diff "$modulesMapTemp" "$modulesMap" >/dev/null 2>/dev/null
if [[ $? != 0 ]] ; then
mv "$modulesMapTemp" "$modulesMap"
else
rm "$modulesMapTemp"
fi
Create signatures with swift-pgp by utilizing the Signable
interface. The Signable
interface is what makes the swift-pgp library public-key-cryptography-implementation-agnostic.
/**
Represents a structure that can be signed
*/
public protocol Signable {
var signature:Signature { get set }
func signableData() throws -> Data
}
The Signable
interface is extended to provide two useful functions
func dataToHash() throws -> Data
mutating func set(hash:Data, signedHash:Data) throws
This lets you initialize a signable, extract the data that needs to be hashed via dataToHash()
, hash it, sign it, and then set the hash and signature via set(hash:Data, signedHash:Data)
. The dataToHash()
function can also be used to extract the data that needs to be hashed to verify signatures.
Currently, there are only two types of Signables: SignedPublicKeyIdentity
and SignedBinaryDocument
.
Below are a few examples for creating certification and binary document signatures.
A Public Key <> User ID binding certification.
// initialize a public key
let publicKeyData = RSAPublicKey(modulus: ..., exponent: ...)
let publicKey = try PublicKey(create: .rsaSignOnly, publicKeyData: publicKeyData, date: Date())
// initialize a user id
let userID = UserID(name: "Alex Grinman", email: "[email protected]")
// initialize the signed public key
var signedPublicKey = try SignedPublicKeyIdentity(publicKey: publicKey, userID: userID, hashAlgorithm: .sha512)
// extract the data to hash and sign, sign it, and set it on the signedPublicKey
let dataToHash = try signedPublicKey.dataToHash()
let hash = H(dataToHash) // where H is your chosen (i.e. sha512) hash implementation
let signatureData = X(dataToHash) // where X is your chosen RSA sign implementation
try signedPublicKey.set(hash: hash, signedHash: signatureData)
// get the ASCII armored message
let asciiMessage = try signedPublicKey.armoredMessage(blockType: .publicKey, comment: "created with swift-pgp")
Multiple UserIDs often certifications need to say that several User IDs are binded to a public key. swift-pgp provides a helper struct for this called
SignedPublicKeyIdentities
that is initialized with an list ofSignedPublicKeyIdentity
s.
A signature for a binary document.
// the bytes of the document being signed, i.e. 0xDEADBEEF
let binaryData = Data(bytes: [0xDE, 0xAD, 0xBE, 0xEF])
var signedBinary = SignedBinaryDocument(binary: binaryData, publicKeyAlgorithm: .rsaSignOnly, hashAlgorithm: .sha512)
// extract the data to hash and sign, sign it, and set it on the signedPublicKey
let dataToHash = try signedBinary.dataToHash()
let hash = H(dataToHash) // where H is your chosen (i.e. sha512) hash implementation
let signatureData = X(dataToHash) // where X is your chosen RSA sign implementation
// compile the signed public key packets
try signedBinary.set(hash: hash, signedHash: signatureData)
// return ascii armored signature
let asciiMessage = try signedBinary.set(blockType: .signature, comment: "created with swift-pgp")
We are currently deciding on a license for swift-pgp. For now, the code is released under All Rights Reserved.