1    Introduction

1.1    Overview

std.lib.security is part of the standard foundation library set. This page collects the public API reference for the namespace.

2    Walkthrough

2.1    Hashing

sha1 and md5 produce hex-encoded message digests of a string. They are thin wrappers over verify/digest.

hash strings to hex

(sha1 "123")
=> "40bd001563085fc35165329ea1ff5c5ecbdbbeef"

(md5 "123")
=> "202cb962ac59075b964b07152d234b70"

2.2    Digests and HMAC

digest returns raw bytes; call encode/to-hex to display them. hmac computes a keyed hash. list-providers and list-services show what algorithms are available on the current JVM.

list security providers and services

(list-providers)
=> coll?

(list-services "MessageDigest")
=> coll?

compute a raw digest

(-> (digest (.getBytes "hello world") "SHA")
    (std.lib.encode/to-hex))
=> "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"

compute a keyed HMAC

(-> (hmac (.getBytes "hello world")
          {:type "HmacSHA1"
           :mode :secret
           :format "RAW"
           :encoded "wQ0lyydDSEFRKviwv/2BoWVQDpj8hbUiUXytuWj7Yv8="})
    (std.lib.encode/to-hex))
=> "a6f9e08fad62f63a35c6fd320f4249c9ad3079dc"

2.3    Keys

Generate secret or asymmetric keys, convert them to and from maps, and inspect their algorithm and mode.

generate and inspect a secret key

(let [k (generate-key "AES" {:length 128})]
  (key-type k)
  => "AES"

  (key->map k)
  => (contains {:type "AES"
                :mode :secret
                :format "RAW"
                :encoded string?}))

generate a key pair

(->> (generate-key-pair "RSA" {:length 512})
     (map key-mode))
=> [:public :private]

round-trip a key through its map representation

(let [k  (generate-key "AES" {:length 128})
      km (key->map k)]
  (-> km ->key key->map)
  => (contains km))

2.4    Encryption and decryption

encrypt and decrypt operate on byte arrays. The examples use a fixed AES key so the ciphertext is deterministic.

encrypt and decrypt with AES

(let [key   {:type "AES"
             :mode :secret
             :format "RAW"
             :encoded "euHlt5sHWhRpbKZHjrwrrQ=="}
      bytes (.getBytes "hello world")]
  (-> (decrypt (encrypt bytes key) key)
      (String.))
  => "hello world")

2.5    End-to-end: generate a key, encrypt data, and verify it

A complete workflow: list available ciphers, generate an AES key, encrypt a message, and decrypt it back to the original string.

generate a fresh key and round-trip a message

(let [key   (generate-key "AES" {:length 128})
      text  "round-trip secret message"
      bytes (.getBytes text)]
  (-> (encrypt bytes key)
      (decrypt key)
      (String.))
  => text)

3    API



->key ^

[k]
Added 3.0

idempotent function converting input into a key

v 3.0
(defn ^Key ->key
  ([k]
   (cond (map? k)
         (map->key k)

         :else k)))
link
(-> {:type "AES", :mode :secret, :format "RAW", :encoded "euHlt5sHWhRpbKZHjrwrrQ=="} (->key) (->key)) => java.security.Key

cipher ^

[] [name] [name provider]
Added 3.0

lists or returns available `Cipher` implementations

v 3.0
(defn ^Cipher cipher
  ([]
   (list-services "Cipher"))
  ([name]
   (cipher name nil))
  ([^String name ^String provider]
   (if (nil? provider)
     (Cipher/getInstance name)
     (Cipher/getInstance name provider))))
link
(cipher) => ("AES" "AESWrap" "AESWrap_128" ...) (cipher "AES") => javax.crypto.Cipher

decrypt ^

[bytes key] [bytes key {:keys [algorithm params random iv], :as opts}]
Added 3.0

decrypts a byte array using a key

v 3.0
(defn ^"[B" decrypt
  ([bytes key]
   (decrypt bytes key {}))
  ([bytes key {:keys [algorithm params random iv] :as opts}]
   (operate Cipher/DECRYPT_MODE bytes key opts)))
link
(-> (decrypt (encode/from-hex "30491ab4427e45909f3d2f5d600b0f93") {:type "AES", :mode :secret, :format "RAW", :encoded "euHlt5sHWhRpbKZHjrwrrQ=="}) (String.)) => "hello world"

digest ^

[] [bytes algo] [bytes algo {:keys [provider], :as opts}]
Added 3.0

creates a digest out of a byte array

v 3.0
(defn digest
  ([]
   (provider/message-digest))
  ([bytes algo]
   (digest bytes algo {}))
  ([bytes algo {:keys [provider] :as opts}]
   (-> ^java.security.MessageDigest
    (provider/message-digest algo provider)
       (doto (.update ^bytes bytes))
       (.digest))))
link
(digest) => (contains ["MD2" "MD5" "SHA-224" "SHA-256" "SHA-384" "SHA-512"] :in-any-order :gaps-ok) (-> (digest (.getBytes "hello world") "SHA") (encode/to-hex)) => "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"

encrypt ^

[bytes key] [bytes key {:keys [algorithm params random iv], :as opts}]
Added 3.0

encrypts a byte array using a key

v 3.0
(defn encrypt
  ([bytes key]
   (encrypt bytes key {}))
  ([bytes key {:keys [algorithm params random iv] :as opts}]
   (operate Cipher/ENCRYPT_MODE bytes key opts)))
link
(-> (encrypt (.getBytes "hello world") {:type "AES", :mode :secret, :format "RAW", :encoded "euHlt5sHWhRpbKZHjrwrrQ=="}) (encode/to-hex)) => "30491ab4427e45909f3d2f5d600b0f93"

generate-key ^

[] [algo {:keys [provider], :as opts}]
Added 3.0

generates a key according to algorithm

v 3.0
(defn generate-key
  ([] (provider/key-generator))
  ([algo {:keys [provider] :as opts}]
   {:pre [(:length opts)]}
   (-> ^KeyGenerator (provider/key-generator algo provider)
       (doto (init-key-generator opts))
       (.generateKey))))
link
(generate-key) => ("AES" "ARCFOUR" "Blowfish" "DES" "DESede" "HmacMD5" "HmacSHA1" "HmacSHA224" "HmacSHA256" "HmacSHA384" "HmacSHA512" ...) (generate-key "AES" {:length 128}) ;;=> #key {:type "AES", ;; :mode :secret, ;; :format "RAW", ;; :encoded "AQgv8l+vJNfnEWuhHs55wg=="} (generate-key "HmacSHA224" {:length 40}) ;;=> #key {:type "HmacSHA224", ;; :mode :secret, ;; :format "RAW", ;; :encoded "0qQkmic="}

generate-key-pair ^

[] [type {:keys [provider], :as opts}]
Added 3.0

creates a public and private key pair

v 3.0
(defn generate-key-pair
  ([]
   (provider/key-pair-generator))
  ([type {:keys [provider] :as opts}]
   {:pre [(:length opts)]}
   (-> ^KeyPairGenerator (provider/key-pair-generator type provider)
       (doto (init-key-pair-generator opts))
       (.generateKeyPair)
       ((juxt #(.getPublic ^KeyPair %)
              #(.getPrivate ^KeyPair %))))))
link
(generate-key-pair) => ("DSA" "DiffieHellman" "EC" "RSA") (generate-key-pair "RSA" {:length 512}) ;;=> [#key {:type "RSA", ;; :mode :public, ;; :format "X.509", ;; :encoded "...." } ;; #key {:type "RSA", ;; :mode :private, ;; :format "PKCS#8", ;; :encoded "..."}]

hmac ^

[] [bytes key] [bytes key {:keys [algorithm provider], :as opts}]
Added 3.0

creates a key encrypted digest

v 3.0
(defn hmac
  ([]
   (provider/mac))
  ([bytes key]
   (hmac bytes key {}))
  ([bytes key {:keys [algorithm provider] :as opts}]
   (-> (provider/mac (or algorithm
                         (key/key-type key))
                     provider)
       (doto (init-hmac (key/->key key) opts))
       (.doFinal bytes))))
link
(-> (hmac (.getBytes "hello world") {:type "HmacSHA1", :mode :secret, :format "RAW", :encoded "wQ0lyydDSEFRKviwv/2BoWVQDpj8hbUiUXytuWj7Yv8="}) (encode/to-hex)) => "a6f9e08fad62f63a35c6fd320f4249c9ad3079dc"

key->map ^

[k]
Added 3.0

returns a map representation of a key

v 3.0
(defn key->map
  ([^Key k]
   (cond (map? k) k

         :else
         {:type    (.getAlgorithm k)
          :mode    (key-mode k)
          :format  (.getFormat k)
          :encoded (encode/to-base64 (.getEncoded k))})))
link
(key->map (generate-key "AES" {:length 128})) => (contains {:type "AES", :mode :secret, :format "RAW", :encoded string?})

key-generator ^

[] [name] [name provider]
Added 3.0

lists or returns available `KeyGenerator` implementations

v 3.0
(defn ^KeyGenerator key-generator
  ([]
   (list-services "KeyGenerator"))
  ([name]
   (key-generator name nil))
  ([^String name ^String provider]
   (if (nil? provider)
     (KeyGenerator/getInstance name)
     (KeyGenerator/getInstance name provider))))
link
(key-generator) => ("AES" "ARCFOUR" "Blowfish" ...) (key-generator "Blowfish") => javax.crypto.KeyGenerator

key-pair-generator ^

[] [name] [name provider]
Added 3.0

lists or returns available `KeyPairGenerator` implementations

v 3.0
(defn ^KeyPairGenerator key-pair-generator
  ([]
   (list-services "KeyPairGenerator"))
  ([name]
   (key-pair-generator name nil))
  ([^String name ^String provider]
   (if (nil? provider)
     (KeyPairGenerator/getInstance name)
     (KeyPairGenerator/getInstance name provider))))
link
(key-pair-generator) => ("DSA" "DiffieHellman" "EC" "RSA") (key-pair-generator "RSA") => java.security.KeyPairGenerator

key-store ^

[] [name] [name provider]
Added 3.0

lists or returns available `KeyStore` implementations

v 3.0
(defn ^KeyStore key-store
  ([]
   (list-services "KeyStore"))
  ([name]
   (key-store name nil))
  ([^String name ^String provider]
   (if (nil? provider)
     (KeyStore/getInstance name)
     (KeyStore/getInstance name provider))))
link
(key-store) => ("CaseExactJKS" "DKS" "JCEKS" "JKS" "KeychainStore" "PKCS12") (key-store "JKS") => java.security.KeyStore

list-providers ^

[]
Added 3.0

list all security providers

v 3.0
(defn list-providers
  ([]
   (->> (Security/getProviders)
        (seq)
        (map #(.getName ^Provider %))
        (sort))))
link
(list-providers) => ["Apple" "SUN" "SunEC" "SunJCE" "SunJGSS" "SunJSSE" "SunPCSC" "SunRsaSign" "SunSASL" "XMLDSig"]

list-services ^

[] [type] [type provider]
Added 3.0

lists all services that are available

v 3.0
(defn list-services
  ([]
   (->> (Security/getProviders)
        (mapcat #(.getServices ^Provider %))
        (map #(.getType ^Provider$Service %))
        (set)
        (sort)))
  ([type]
   (list-services type nil))
  ([type provider]
   (->> (if (nil? provider)
          (Security/getProviders)
          [(Security/getProvider provider)])
        (mapcat #(.getServices ^Provider %))
        (sort-services type))))
link
(list-services) => ("AlgorithmParameterGenerator" "AlgorithmParameters" ...) (list-services "Cipher") => ("AES" "AESWrap" "AESWrap_128" ...) (list-services "KeyGenerator" "SunJCE") => ("AES" "ARCFOUR" "Blowfish" "DES" "DESede" ...)

mac ^

[] [name] [name provider]
Added 3.0

lists or returns available `Mac` implementations

v 3.0
(defn ^Mac mac
  ([]
   (list-services "Mac"))
  ([name]
   (mac name nil))
  ([^String name ^String provider]
   (if (nil? provider)
     (Mac/getInstance name)
     (Mac/getInstance name provider))))
link
(mac) => ("HmacMD5" "HmacPBESHA1" "HmacSHA1" ...) (mac "HmacMD5") => javax.crypto.Mac

md5 ^

[body]
Added 4.0

function for md5 hash

v 4.0
(defn md5
  ([^String body]
   (-> (.getBytes body)
       (verify/digest "MD5")
       (encode/to-hex))))
link
(md5 "123") => "202cb962ac59075b964b07152d234b70"

message-digest ^

[] [name] [name provider]
Added 3.0

lists or returns available `MessageDigest` implementations

v 3.0
(defn ^MessageDigest message-digest
  ([]
   (list-services "MessageDigest"))
  ([name]
   (message-digest name nil))
  ([^String name ^String provider]
   (if (nil? provider)
     (MessageDigest/getInstance name)
     (MessageDigest/getInstance name provider))))
link
(message-digest) => ("MD2" "MD5" "SHA" "SHA-224" "SHA-256" "SHA-384" "SHA-512") (message-digest "MD2") => java.security.MessageDigest$Delegate

sha1 ^

[body]
Added 3.0

function for sha1 hash

v 3.0
(defn sha1
  ([^String body]
   (-> (.getBytes body)
       (verify/digest "SHA1")
       (encode/to-hex))))
link
(sha1 "123") => "40bd001563085fc35165329ea1ff5c5ecbdbbeef"

sign ^

[] [bytes key {:keys [algorithm provider], :as opts}]
Added 3.0

creates a signature using a private key

v 3.0
(defn sign
  ([]
   (provider/signature))
  ([bytes key {:keys [algorithm provider] :as opts}]
   (-> (provider/signature algorithm provider)
       (doto (.initSign (key/->key key)) (.update ^bytes bytes))
       (.sign))))
link
(sign) ;; => (contains ["MD2withRSA" "MD5andSHA1withRSA" "MD5withRSA" ;; "NONEwithDSA" "NONEwithECDSA" "SHA1withDSA" ;; "SHA1withECDSA" "SHA1withRSA" "SHA224withDSA" ;; "SHA224withECDSA" "SHA224withRSA" "SHA256withDSA" ;; "SHA256withECDSA" "SHA256withRSA" "SHA384withECDSA" ;; "SHA384withRSA" "SHA512withECDSA" "SHA512withRSA"] ;; :in-any-order) (-> (sign (.getBytes "hello world") {:type "RSA", :mode :private, :format "PKCS#8", :encoded (apply str ["MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAmrOdqA5ZGMJ6" "55meZCnj44B65ZUXnAscXu7GJcNQO91Z7B9NmWX/P59BBUC/yJ6s/ugEffhP" "wCYJt013GkV6tQIDAQABAkBJxzV+C3G0XDOvNlUSoeO8AO8bhJIg6i+amrdH" "FTGzimwp/eyOGZlXpHcaK57kSBK4npXgfWCFFLNuvAtCrQ91AiEA0McEFHMS" "MTVU/78kDYSsJ+lty6izxkONp/XZ4+T6BDsCIQC9sWmBYAFDfiHvLnv2NT7O" "08LR+UnNuDalduukc649zwIhAKXHEadHRA/M4GR/Gxqc2bKLeUJ4/98TrvzK" "jCyYmioXAiAiOg2wY1M3C14yGvARB6ByjzD61AEmFlP93Qw9mwXYbwIhALR/" "Uv4DvJJbR7mpRXcRCo9Me1wawdCndM5ZyF7Hvpu4"])} {:algorithm "MD5withRSA"}) (encode/to-hex)) => (apply str ["5ba863c3e24c73f09d50749698ae82406490c" "edc4566810461480e37da661754b7bf33cc6b" "bf0f48646304c8994202d2fd7094e7420049f" "eaa512c8cd72d7000"])

signature ^

[] [name] [name provider]
Added 3.0

lists or returns available `Signature` implementations

v 3.0
(defn ^Signature signature
  ([]
   (list-services "Signature"))
  ([name]
   (signature name nil))
  ([^String name ^String provider]
   (if (nil? provider)
     (Signature/getInstance name)
     (Signature/getInstance name provider))))
link
(signature) => ("MD2withRSA" "MD5andSHA1withRSA" "MD5withRSA" ...) (signature "MD2withRSA") => java.security.Signature$Delegate

verify ^

[] [bytes signature key {:keys [algorithm provider], :as opts}]
Added 3.0

verifies a signature using a public key

v 3.0
(defn verify
  ([]
   (provider/signature))
  ([bytes signature key {:keys [algorithm provider] :as opts}]
   (-> (provider/signature algorithm provider)
       (doto (.initVerify ^PublicKey (key/->key key)) (.update ^bytes bytes))
       (.verify signature))))
link
(verify (.getBytes "hello world") (->> ["5ba863c3e24c73f09d50749698ae82406490c" "edc4566810461480e37da661754b7bf33cc6b" "bf0f48646304c8994202d2fd7094e7420049f" "eaa512c8cd72d7000"] (apply str) (encode/from-hex)) {:type "RSA", :mode :public, :format "X.509", :encoded (apply str ["MFwwDQYJKoZIhvcNAQEBBQADSwAwSA" "JBAJqznagOWRjCeueZnmQp4+OAeuWV" "F5wLHF7uxiXDUDvdWewfTZll/z+fQQ" "VAv8ierP7oBH34T8AmCbdNdxpFerUC" "AwEAAQ=="])} {:algorithm "MD5withRSA"}) => true

4    std.lib.security: A Comprehensive Summary

The std.lib.security module provides a comprehensive set of utilities for cryptographic operations, key management, and security provider introspection in Clojure. It wraps Java's Cryptography Architecture (JCA) and Java Cryptography Extension (JCE) to offer functionalities for encryption/decryption, key generation, digital signing, message digesting, and HMAC (Hash-based Message Authentication Code) generation. This module is crucial for applications requiring secure data handling, authentication, and integrity verification within the foundation-base project.

The module is organized into several sub-namespaces:

4.1    std.lib.security.provider

This namespace focuses on introspecting and accessing available cryptographic service providers (CSPs) and their services.

  • list-providers []: Lists the names of all installed security providers.n sort-services [type services]: Helper function to filter and sort services by type.n list-services [& [type provider]]: Lists all available cryptographic services, optionally filtered by type (e.g., "Cipher", "KeyGenerator") and provider.n cipher [& [name provider]]: Lists available Cipher implementations or returns a javax.crypto.Cipher instance for a given name and optional provider.n key-factory [& [name provider]]: Lists available KeyFactory implementations or returns a java.security.KeyFactory instance.n key-generator [& [name provider]]: Lists available KeyGenerator implementations or returns a javax.crypto.KeyGenerator instance.n key-pair-generator [& [name provider]]: Lists available KeyPairGenerator implementations or returns a java.security.KeyPairGenerator instance.n key-store [& [name provider]]: Lists available KeyStore implementations or returns a java.security.KeyStore instance.n mac [& [name provider]]: Lists available Mac (Message Authentication Code) implementations or returns a javax.crypto.Mac instance.n message-digest [& [name provider]]: Lists available MessageDigest implementations or returns a java.security.MessageDigest instance.n signature [& [name provider]]: Lists available Signature implementations or returns a java.security.Signature instance.

4.2    std.lib.security.key

This namespace provides utilities for generating, managing, and converting cryptographic keys.

  • init-key-generator [gen opts]: Initializes a KeyGenerator with options like length, params, and random.n generate-key [& [algo opts]]: Generates a symmetric javax.crypto.SecretKey for a given algo and opts.n init-key-pair-generator [gen opts]: Initializes a KeyPairGenerator with options.n generate-key-pair [& [type opts]]: Generates an asymmetric java.security.KeyPair (public and private keys) for a given type and opts.n key-mode [k]: Returns the mode of a key (:public, :private, or :secret).n key-type [k]: Returns the algorithm type of a key (e.g., "AES", "RSA").n key->map [k]: Converts a java.security.Key object into a map representation, including its type, mode, format, and encoded bytes (Base64).n to-bytes [input]: Converts input (Base64 string or byte array) to a byte array.n map->key [m]: A multimethod that converts a map representation of a key back into a java.security.Key object (e.g., SecretKeySpec, PublicKey, PrivateKey), dispatching on the :mode of the key.n ->key [k]: An idempotent function that ensures its input k is a java.security.Key object, converting from a map if necessary.n print-method Key/PublicKey/PrivateKey: Extends print-method for Key types to display them as #key followed by their map representation.

4.3    std.lib.security.cipher

This namespace provides functions for symmetric encryption and decryption using various cipher algorithms.

  • init-cipher [cipher mode key opts]: Initializes a javax.crypto.Cipher object with a given mode (encrypt/decrypt), key, and options (e.g., params, random, iv).n operate [mode bytes key opts]: The base function for both encryption and decryption, performing the actual cipher operation.n encrypt [bytes key & [opts]]: Encrypts a byte array using a given key and optional opts.n* decrypt [bytes key & [opts]]: Decrypts a byte array using a given key and optional opts.

4.4    std.lib.security.verify

This namespace offers functionalities for generating and verifying cryptographic hashes, HMACs, and digital signatures.

  • digest [& [bytes algo opts]]: Generates a cryptographic hash (message digest) of a byte array using a specified algo (e.g., "SHA1", "MD5").n init-hmac [mac key opts]: Initializes a javax.crypto.Mac object with a key and optional params.n hmac [& [bytes key opts]]: Generates an HMAC (keyed-hash message authentication code) of a byte array using a key and optional opts.n sign [& [bytes key opts]]: Generates a digital signature of a byte array using a private key and optional opts.n verify [& [bytes signature key opts]]: Verifies a digital signature of a byte array using a public key, the signature, and optional opts.

4.5    std.lib.security (Facade Namespace)

This namespace acts as a facade, re-exporting key functions from its sub-namespaces and providing convenient wrappers for common hashing algorithms.

  • h/intern-in: Interns encrypt, decrypt, generate-key, generate-key-pair, ->key, key->map, list-providers, list-services, cipher, key-generator, key-pair-generator, key-store, mac, message-digest, signature, digest, hmac, sign, and verify into this namespace.n sha1 [body]: Computes the SHA1 hash of a string and returns it as a hexadecimal string.n md5 [body]: Computes the MD5 hash of a string and returns it as a hexadecimal string.

Overall Importance:

The std.lib.security module is essential for building secure and trustworthy applications within the foundation-base project. Its key contributions include:

  • Comprehensive Cryptographic Support: Provides a wide range of cryptographic primitives for data confidentiality, integrity, and authentication.n Key Management: Simplifies the generation, representation, and handling of various types of cryptographic keys.n Provider Introspection: Allows for dynamic discovery and selection of available security providers and algorithms.n Data Integrity and Authentication: Offers tools for hashing, HMACs, and digital signatures to ensure data has not been tampered with and originates from a trusted source.n Extensibility: Built upon Java's flexible JCA/JCE, allowing for easy integration of new algorithms and providers.

By offering these robust security capabilities, std.lib.security significantly enhances the foundation-base project's ability to handle sensitive data and operations securely, which is vital for its multi-language development ecosystem.