Clojure wrapper for the Bouncy Castle OpenPGP library

License: Unlicense

Language: Clojure


CircleCI codecov API codox marginalia docs

This is a Clojure library which wraps the Bouncy Castle OpenPGP implementation.


Library releases are published on Clojars. To use the latest version with Leiningen, add the following dependency to your project definition:

Clojars Project

The main interface to the library is the clj-pgp.core namespace, which provides many general functions for working with PGP keys and data.

PGP Keys

PGP stores keys in keyrings, which are collections of related asymmetric keys. Public keyrings store just the public key from each keypair, and may store keys for other people as well as keys controlled by the user. Secret keyrings store both the public and private parts of a keypair, encrypted with a secret passphrase.

=> (require
     '[ :as io]
        [core :as pgp]
        [keyring :as keyring]))

; Load a keyring from a file:
=> (def keyring (keyring/load-secret-keyring (io/file "~/.gpg/secring.gpg")))

; List the keys in the public ring:
=> (keyring/list-public-keys keyring)
(#<PGPPublicKey ...> #<PGPPublicKey ...>)

=> (def pubkey (first *1))

=> (pgp/key-id pubkey)

=> (pgp/hex-id pubkey)

; Load the matching secret key by the hex identifier:
=> (def seckey (keyring/get-secret-key keyring *1))

=> (pgp/key-algorithm seckey)

; Get a full map of info about a key:
=> (pgp/key-info pubkey)
{:master-key? true,
 :key-id "923b1c1c4392318a",
 :strength 1024,
 :algorithm :rsa-general,
 :fingerprint "4C0F256D432975418FAB3D7B923B1C1C4392318A",
 :encryption-key? true,
 :user-ids ["Test User <>"]}

Keypairs and keyrings can be created using the clj-pgp.generate namespace. RSA and EC keys can be generated directly or as part of a keyring, which binds a master key together with signing and encryption subkeys. The generate-keys macro provides a handy syntax for creating new keyrings:

=> (require '[clj-pgp.generate :as pgp-gen])

; Set up some RSA and elliptic curve generators:
=> (def rsa (pgp-gen/rsa-keypair-generator 2048))
=> (def ec (pgp-gen/ec-keypair-generator "secp160r2"))

; Generate a new EC keypair:
=> (pgp-gen/generate-keypair ec :ecdsa)
#<PGPKeyPair ...>

; Generate a full keyring with master and subkeys using a DSL:
=> (pgp-gen/generate-keys
     "test user" "test passphrase"
       (keypair rsa :rsa-general)
       (prefer-symmetric :aes-256 :aes-128)
       (prefer-hash :sha512 :sha256 :sha1)
       (prefer-compression :zlib :bzip2))
       (keypair rsa :rsa-general)
       (expires 36000))
       (keypair ec :ecdh)))
{:public #<PGPPublicKeyRing ...>
 :secret #<PGPSecretKeyRing ...>}

Message Handling

Data encryption is supported using PGP message packets. The content is encrypted using a symmetric key algorithm, then the key is encrypted using the given public key(s) or passphrase. Any matching private key or passphrase can then decipher and read the message.

Data may also be compressed before encrypting it, and converted to an ASCII representation after. The ASCII format is sometimes referred to as an "armored" encoding because it is intended to be transmissible through email.

=> (require '[clj-pgp.message :as pgp-msg])

=> (def content "my sensitive data")

; Wrap the message with various encodings:
=> (def message
       content pubkey
       :format :utf8
       :cipher :aes-256
       :compress :zip
       :armor true))

=> (println message)
; Version: BCPG v1.49
; hIwDkjscHEOSMYoBBADGcRtjKmBSAh6L2fVe/1BCZtEbME4zp6GqilETzOYyi5HL
; Vee++PI03KluhW32i359ycvOre92yHaApcDBRXGwdYBT/hx8ryXov3I1wvZMS/iK
; Iex91VxkquJnvZvi6/qy3f6WFgLBHT2GCKy+Um4YU2OstykHZP7Gsbr5MZ04K8ks
; 71TaictIOx2qukbpwnIVNzOl5GeaPy5FiVbntl0Wc3lESD2A9l2pDENyicg=
; =cvks
; -----END PGP MESSAGE-----

; Secret keys can be 'unlocked' to get the private key:
=> (def privkey (pgp/unlock-key seckey "test password"))

=> (println (pgp-msg/decrypt message privkey))
; my sensitive data

; Or, for more detail:
=> (pgp-msg/read-messages message :decryptor privkey)
({:data "my sensitive data"
  :cipher :aes-256
  :encrypted-for -7909697412827827830
  :integrity-protected? true
  :compress :zip
  :format :utf8
  :filename "_CONSOLE"
  :mtime #inst "2014-12-06T22:44:59.000-00:00"})


PGP keys can be used to sign data by hashing it and encrypting the hash with the private key. Later, the signature can be verified by decrypting it with the public key and comparing it with the hash of the data.

=> (require '[clj-pgp.signature :as pgp-sig])

=> (def sig (pgp-sig/sign content privkey))

; Signatures can be identified by key id:
=> (= (pgp/key-id sig) (pgp/key-id privkey))

; Verify that a signature on some content is correct for a key:
=> (pgp-sig/verify content sig pubkey)


The library provides functions for encoding some PGP objects in both binary and ASCII formats.

=> (pgp/encode sig)
#<byte[] [B@51e4232>

=> (print (pgp/encode-ascii pubkey))
; Version: BCPG v1.49
; mI0EUr3KFwEEANAfzcKxWqBYhkUGo4xi6d2zZy2RAewFRKVp/BA2bEHLAquDnpn7
; abgrpsCFbBW/LEwiMX6cfYLMxvGzbg5oTfQHMs27OsnKCqFas9UkT6DYS1PM9u4C
; 3qlJytK9AFQnSYOrSs8pe6VRdeHZb7FM+PawqH0cuoYfcMZiGAylddXhABEBAAE=
; =Hnjf

; Encoded keys can be round-tripped:
=> (let [ascii (pgp/encode-ascii pubkey)]
     (= ascii (pgp/encode-ascii (pgp/decode-public-key ascii))))


This is free and unencumbered software released into the public domain. See the UNLICENSE file for more information.

Project Statistics

Sourcerank 5
Repository Size 434 KB
Stars 50
Forks 3
Watchers 6
Open issues 8
Dependencies 4
Contributors 2
Tags 9
Last updated
Last pushed

Top Contributors See all

Greg Look Michael Reinhardt

Packages Referencing this Repo

Wrapper for the Bouncy Castle OpenPGP library
Latest release 0.9.0 - Updated - 50 stars

Recent Tags See all

0.8.3 December 30, 2015
0.8.2 June 06, 2015
0.8.1 March 12, 2015
0.8.0 December 10, 2014
0.5.4 September 24, 2014
0.5.3 July 05, 2014
0.5.2 May 24, 2014
0.5.1 May 21, 2014
0.4.0 April 27, 2014

Something wrong with this page? Make a suggestion

Last synced: 2018-06-24 05:27:14 UTC

Login to resync this repository