DEV Community

Cover image for Generating secrets in Clojure
Líkið Geimfari
Líkið Geimfari

Posted on • Originally published at isaak.dev

Generating secrets in Clojure

Generating secrets is a very important part of any security-sensitive application. In this article, I'm going to tell you about a low-level library that helps to generate secrets in Clojure.

If you're familiar with Python, you might have heard of secrets module from Python's standard library.

Well, the secrets.clj is just like Python's secrets, but for Clojure — it's a library designed to generate cryptographically strong random numbers suitable for managing data such as passwords, account authentication, security tokens, and related secrets.

Installation

Add secrets.clj to your project.clj file:

[likid_geimfari/secrets "1.1.1"]
Enter fullscreen mode Exit fullscreen mode

then run lein deps to install it.

That's it, you're ready to go:

(ns example.core
  (:require [secrets.core]
            [secrets.tools]
            [secrets.constants]))
Enter fullscreen mode Exit fullscreen mode

Usage

Typical use cases are:

  • Generating random numbers
  • Creating passwords, SMS-codes and OTP
  • Generating random tokens
  • Generating password recovery URLs and session keys
secrets.core/randbelow(n)

This function generates a secure random integer in the range [0, n), where n is the exclusive upper bound.

Example:

user=> (secrets.core/randbelow 9999)
7612
Enter fullscreen mode Exit fullscreen mode
secrets.core/choice(seq)

This function returns a random element from a non-empty sequence or throws an exception if the sequence is empty.

user=> (secrets.core/choice ["bob" "alice" "eve"])
"eve"
Enter fullscreen mode Exit fullscreen mode
secrets.core/choices(seq)

Just like secrets.core/choice, but this function returns a list of random elements picked from the sequence:

(secrets.core/choices ["bob" "alice" "eve"] 2)
("eve" "alice")
Enter fullscreen mode Exit fullscreen mode
secrets.core/token-hex(nbytes)

Generates a secure random string in hexadecimal format. The string has nbytes random bytes, and each byte is converted to two hex digits.
If n-bytes are not supplied, a reasonable default gets used, which is 32.

user=> (secrets.core/token-hex(64))
"3a3e8e6636000dd3b7d39aa4316935f27c2f013d768f0c00f309efb453f34dbc673060db2cd8af288494892848"
Enter fullscreen mode Exit fullscreen mode
secrets.core/token-urlsafe(nbytes)

Generates a secure random string in URL-safe format.

(defn generate-password-recovery-url [n]
  (str "https://mydomain.com/reset=" (secrets.core/token-urlsafe n)))
(generate-password-recovery-url 64)
"TItm04q8by00MRMcNBt7I3Yx-wSxyUa79isRLNyQJCd8K75RnqUahwcWA_rURBt1clknJiRGrubapGaUrEUnSw"
Enter fullscreen mode Exit fullscreen mode
secrets.core/token-bytes(nbytes)

Generates a secure random string in bytes format.

(secrets.core/token-urlsafe(16))
#object["[B" 0x3b2454e9 "[B@3b2454e9"]
Enter fullscreen mode Exit fullscreen mode

How many bytes should tokens use?

To be secure against brute-force attacks, tokens need to have sufficient randomness.
The number of random bits needed for a token depends on the application, but 256 bits
is considered to be cryptographically strong.

Personally, I would recommend using 64 bytes (512 bits).

Links

Original post: https://isaak.dev/2022/10/generating-secrets-in-clojure
Telegram Channel: https://t.me/software_dev_channel

Top comments (0)