Skip to content

Instantly share code, notes, and snippets.

@xfthhxk
Last active September 30, 2023 00:56
Show Gist options
  • Save xfthhxk/0026bee89251cbf5183fc41d3ae25262 to your computer and use it in GitHub Desktop.
Save xfthhxk/0026bee89251cbf5183fc41d3ae25262 to your computer and use it in GitHub Desktop.
Digital Signatures using Clojure without dependencies
(ns digital-signature
(:require [clojure.string :as str])
(:import (java.security.spec PKCS8EncodedKeySpec X509EncodedKeySpec)
(java.security PublicKey PrivateKey Signature KeyFactory KeyPairGenerator)
(java.util Base64)))
(defn gen-key
[pem algo]
(let [priv-header "-----BEGIN PRIVATE KEY-----"
priv-footer "-----END PRIVATE KEY-----"
pub-header "-----BEGIN PUBLIC KEY-----"
pub-footer "-----END PUBLIC KEY-----"
public? (cond
(str/starts-with? pem pub-header) true
(str/starts-with? pem priv-header) false
:else (throw (ex-info "Invalid PEM string" {})))
[header footer] (if public?
[pub-header pub-footer]
[priv-header priv-footer])
k (-> pem
(str/replace header "")
(str/replace (System/lineSeparator) "")
(str/replace footer ""))
bs (.decode (Base64/getDecoder) k)
key-factory (KeyFactory/getInstance algo)]
(if public?
(.generatePublic key-factory (X509EncodedKeySpec. bs))
(.generatePrivate key-factory (PKCS8EncodedKeySpec. bs)))))
(defn gen-key-pair
[algo]
(let [kp (-> algo
KeyPairGenerator/getInstance
.generateKeyPair)]
{:public-key (.getPublic kp)
:private-key (.getPrivate kp)}))
(defn b64-decode
[^String s]
(.decode (Base64/getDecoder) (.getBytes s)))
(defn b64-encode
[^bytes bs]
(String. (.encode (Base64/getEncoder) bs)))
(defn sign
[^PrivateKey pk ^bytes data ^String algo]
(b64-encode (.sign (doto (Signature/getInstance algo)
(.initSign pk)
(.update data)))))
(defn verify
[^PublicKey pk ^bytes data ^String algo ^String signature]
(.verify (doto (Signature/getInstance algo)
(.initVerify pk)
(.update data))
(b64-decode signature)))
(comment
;; Generate keys on cli
;; openssl genpkey -algorithm ED25519 -out ed25519-private.pem
;; openssl pkey -in ed25519-private.pem -pubout > ed25519-public.pem
(let [algo "EDDSA"
private-key (gen-key (slurp "ed25519-private.pem") algo)
public-key (gen-key (slurp "ed25519-public.pem") algo)
data (.getBytes "hello")]
(verify public-key data algo
(sign private-key data algo)))
(let [algo "EDDSA"
{:keys [public-key private-key]} (gen-key-pair algo)
data (.getBytes "hello")]
(verify public-key data algo
(sign private-key data algo)))
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment