Skip to content

Instantly share code, notes, and snippets.

@postspectacular
Last active August 28, 2017 15:16
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save postspectacular/a5497ed6b03268dac273 to your computer and use it in GitHub Desktop.
Save postspectacular/a5497ed6b03268dac273 to your computer and use it in GitHub Desktop.
;; add lein dep:
;; [org.bouncycastle/bcpg-jdk15on "1.51"]
;; export gpg public & private keys to armored files:
;; gpg -ao pub.asc --export XXXXXXXX
;; gpg -ao pk.asc --export-secret-keys XXXXXXXX
;; usage:
;; (encrypt "foo.txt" "foo.gpg" (pub-key "pub.asc"))
;; (decrypt "foo.gpg" (io/output-stream "foo.txt") (secret-key "ks-pk.asc") "passphrase")
(import
'[org.bouncycastle.openpgp
PGPObjectFactory
PGPPublicKeyRingCollection PGPSecretKeyRingCollection
PGPPublicKey PGPSecretKey
PGPPublicKeyRing PGPSecretKeyRing
PGPUtil
PGPCompressedData
PGPEncryptedData
PGPLiteralData
PGPEncryptedDataList
PGPCompressedDataGenerator
PGPEncryptedDataGenerator]
'[org.bouncycastle.jce.provider BouncyCastleProvider]
'[org.bouncycastle.openpgp.operator.bc
BcPGPDataEncryptorBuilder
BcPGPDigestCalculatorProvider
BcPBESecretKeyDecryptorBuilder
BcPublicKeyDataDecryptorFactory
BcPublicKeyKeyEncryptionMethodGenerator]
'[java.io InputStream OutputStream ByteArrayOutputStream]
'[java.security SecureRandom Security])
(require '[clojure.java.io :as io])
(Security/addProvider (BouncyCastleProvider.))
(defn pub-key [path]
(with-open [ks (io/input-stream path)]
(let [rcoll (-> ks (PGPUtil/getDecoderStream) (PGPPublicKeyRingCollection.))]
(->> (for [ring (-> rcoll (.getKeyRings) (iterator-seq))
key (-> ring (.getPublicKeys) (iterator-seq))]
key)
(some #(if (.isEncryptionKey ^PGPPublicKey %) %))))))
(defn secret-key [path]
(with-open [ks (io/input-stream path)]
(let [rcoll (-> ks (PGPUtil/getDecoderStream) (PGPSecretKeyRingCollection.))]
(->> (for [ring (-> rcoll (.getKeyRings) (iterator-seq))
key (-> ring (.getSecretKeys) (iterator-seq))]
key)
(some
#(if (and (.isSigningKey %) (not (.. % (getPublicKey) (isRevoked)))) %))))))
(defn file->zipped-bytes [src]
(with-open [bytes (ByteArrayOutputStream.)
com (PGPCompressedDataGenerator. PGPCompressedData/ZIP)]
(PGPUtil/writeFileToLiteralData (.open com bytes) PGPLiteralData/BINARY (io/file src))
(.close com)
(.toByteArray bytes)))
(defn encrypt
[src dest ^PGPPublicKey pub-key]
(let [bytes (file->zipped-bytes src)
enc (doto (BcPGPDataEncryptorBuilder. PGPEncryptedData/AES_256)
(.setWithIntegrityPacket true)
(.setSecureRandom (SecureRandom.)))
gen (doto (PGPEncryptedDataGenerator. enc)
(.addMethod (BcPublicKeyKeyEncryptionMethodGenerator. pub-key)))]
(with-open [out (.open gen (io/output-stream dest) (long (alength bytes)))]
(.write out bytes))))
(defn extract-private-key
[^PGPSecretKey key ^chars pass]
(.extractPrivateKey
key (-> (BcPGPDigestCalculatorProvider.)
(BcPBESecretKeyDecryptorBuilder.)
(.build pass))))
(defn decrypt
[src ^OutputStream out sec-key pass]
(with-open [in (io/input-stream src)
out out]
(let [pk (extract-private-key sec-key (char-array pass))
in (-> in (PGPUtil/getDecoderStream) (PGPObjectFactory.))
enc (.nextObject in)
enc (if (instance? PGPEncryptedDataList enc) enc (.nextObject in))
pbe (-> enc (.getEncryptedDataObjects) (.next))
msg (-> (.getDataStream pbe (BcPublicKeyDataDecryptorFactory. pk))
(PGPObjectFactory.)
(.nextObject))
msg (if (instance? PGPCompressedData msg)
(-> msg (.getDataStream) (PGPObjectFactory.) (.nextObject))
msg)]
(if (instance? PGPLiteralData msg)
(with-open [ld (.getInputStream ^PGPLiteralData msg)]
(loop []
(let [c (.read ^InputStream ld)]
(when (>= c 0)
(.write out c)
(recur)))))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment