clj-pgp
clj-pgp copied to clipboard
Support signatures on data packets
Add support for signing data packets. When unpacking a signed data packet, use a source of public keys (keyring?) to verify the signature values.
http://stackoverflow.com/questions/18772283/how-to-use-bouncycastle-pgpcontentsigner-to-clear-sign-a-byte-array
Here's what I came up with. Hopefully it's useful to you!
(require '[clojure.java.io :as io]
'[clj-pgp.keyring :as keyring]
'[byte-streams :refer [to-byte-array]])
(import '[org.bouncycastle.openpgp PGPSignatureGenerator PGPSignatureSubpacketGenerator PGPUtil PGPSignature]
'[org.bouncycastle.openpgp.operator.jcajce JcaPGPContentSignerBuilder]
'[org.bouncycastle.bcpg ArmoredOutputStream BCPGOutputStream])
(defn clear-sign [content secret-keyring-path passphrase]
"Produce a clear-signed version of `content'.
The text will be signed with the secret keyright found at `secret-keyring-path', unlocked with `passphrase'"
(let [bytea-out (java.io.ByteArrayOutputStream.)
armor-out (ArmoredOutputStream. bytea-out)
bcpg-out (BCPGOutputStream. armor-out)
keyring (keyring/load-secret-keyring (io/file secret-keyring-path))
pubkey (last (keyring/list-public-keys keyring))
seckey (keyring/get-secret-key keyring (pgp/hex-id pubkey))
privkey (pgp/unlock-key seckey passphrase)
builder (JcaPGPContentSignerBuilder. (.getAlgorithm pubkey) PGPUtil/SHA256)
sig-gen (PGPSignatureGenerator. (.setProvider builder "BC"))]
(.init sig-gen PGPSignature/CANONICAL_TEXT_DOCUMENT privkey)
(.beginClearText armor-out PGPUtil/SHA256)
(.update sig-gen (to-byte-array content))
;; Without an additional newline (\n) the final pgp message will be invalid.
;; It's only to satisfy the asc format, however, so it should *not* be
;; considered as part of signature computation
(.write armor-out (to-byte-array (str content "\n")))
(.endClearText armor-out)
(.encode (.generate sig-gen) bcpg-out)
(.flush armor-out)
(.close armor-out)
(.toString bytea-out)))
Cool, I'll see if I can integrate something along these lines!