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
- cipher
- decrypt
- digest
- encrypt
- generate-key
- generate-key-pair
- hmac
- key->map
- key-generator
- key-pair-generator
- key-store
- list-providers
- list-services
- mac
- md5
- message-digest
- sha1
- sign
- signature
- verify
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]
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}]
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}]
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}]
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}]
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}]
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}]
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"
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]
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]
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]
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
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"]
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" ...)
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
v 4.0
(defn md5
([^String body]
(-> (.getBytes body)
(verify/digest "MD5")
(encode/to-hex))))
link
(md5 "123") => "202cb962ac59075b964b07152d234b70"
message-digest ^
[] [name] [name provider]
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
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}]
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]
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}]
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.nsort-services [type services]: Helper function to filter and sort services by type.nlist-services [& [type provider]]: Lists all available cryptographic services, optionally filtered bytype(e.g., "Cipher", "KeyGenerator") andprovider.ncipher [& [name provider]]: Lists availableCipherimplementations or returns ajavax.crypto.Cipherinstance for a givennameand optionalprovider.nkey-factory [& [name provider]]: Lists availableKeyFactoryimplementations or returns ajava.security.KeyFactoryinstance.nkey-generator [& [name provider]]: Lists availableKeyGeneratorimplementations or returns ajavax.crypto.KeyGeneratorinstance.nkey-pair-generator [& [name provider]]: Lists availableKeyPairGeneratorimplementations or returns ajava.security.KeyPairGeneratorinstance.nkey-store [& [name provider]]: Lists availableKeyStoreimplementations or returns ajava.security.KeyStoreinstance.nmac [& [name provider]]: Lists availableMac(Message Authentication Code) implementations or returns ajavax.crypto.Macinstance.nmessage-digest [& [name provider]]: Lists availableMessageDigestimplementations or returns ajava.security.MessageDigestinstance.nsignature [& [name provider]]: Lists availableSignatureimplementations or returns ajava.security.Signatureinstance.
4.2 std.lib.security.key
This namespace provides utilities for generating, managing, and converting cryptographic keys.
init-key-generator [gen opts]: Initializes aKeyGeneratorwith options likelength,params, andrandom.ngenerate-key [& [algo opts]]: Generates a symmetricjavax.crypto.SecretKeyfor a givenalgoandopts.ninit-key-pair-generator [gen opts]: Initializes aKeyPairGeneratorwith options.ngenerate-key-pair [& [type opts]]: Generates an asymmetricjava.security.KeyPair(public and private keys) for a giventypeandopts.nkey-mode [k]: Returns the mode of a key (:public,:private, or:secret).nkey-type [k]: Returns the algorithm type of a key (e.g., "AES", "RSA").nkey->map [k]: Converts ajava.security.Keyobject into a map representation, including its type, mode, format, and encoded bytes (Base64).nto-bytes [input]: Converts input (Base64 string or byte array) to a byte array.nmap->key [m]: A multimethod that converts a map representation of a key back into ajava.security.Keyobject (e.g.,SecretKeySpec,PublicKey,PrivateKey), dispatching on the:modeof the key.n->key [k]: An idempotent function that ensures its inputkis ajava.security.Keyobject, converting from a map if necessary.nprint-method Key/PublicKey/PrivateKey: Extendsprint-methodforKeytypes to display them as#keyfollowed 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 ajavax.crypto.Cipherobject with a givenmode(encrypt/decrypt),key, and options (e.g.,params,random,iv).noperate [mode bytes key opts]: The base function for both encryption and decryption, performing the actual cipher operation.nencrypt [bytes key & [opts]]: Encrypts a byte array using a givenkeyand optionalopts.n*decrypt [bytes key & [opts]]: Decrypts a byte array using a givenkeyand optionalopts.
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 specifiedalgo(e.g., "SHA1", "MD5").ninit-hmac [mac key opts]: Initializes ajavax.crypto.Macobject with akeyand optionalparams.nhmac [& [bytes key opts]]: Generates an HMAC (keyed-hash message authentication code) of a byte array using akeyand optionalopts.nsign [& [bytes key opts]]: Generates a digital signature of a byte array using a privatekeyand optionalopts.nverify [& [bytes signature key opts]]: Verifies a digital signature of a byte array using a publickey, thesignature, and optionalopts.
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: Internsencrypt,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, andverifyinto this namespace.nsha1 [body]: Computes the SHA1 hash of a string and returns it as a hexadecimal string.nmd5 [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.