Last active
September 30, 2023 00:56
-
-
Save xfthhxk/0026bee89251cbf5183fc41d3ae25262 to your computer and use it in GitHub Desktop.
Digital Signatures using Clojure without dependencies
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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