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:

<span>[</span><span>likid_geimfari/secrets</span><span> </span><span>"1.1.1"</span><span>]</span><span> </span>
<span>[</span><span>likid_geimfari/secrets</span><span> </span><span>"1.1.1"</span><span>]</span><span> </span>
[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:

<span>(</span><span>ns</span><span> </span><span>example.core</span><span> </span><span>(</span><span>:require</span><span> </span><span>[</span><span>secrets.core</span><span>]</span><span> </span><span>[</span><span>secrets.tools</span><span>]</span><span> </span><span>[</span><span>secrets.constants</span><span>]))</span><span> </span>
<span>(</span><span>ns</span><span> </span><span>example.core</span><span> </span><span>(</span><span>:require</span><span> </span><span>[</span><span>secrets.core</span><span>]</span><span> </span><span>[</span><span>secrets.tools</span><span>]</span><span> </span><span>[</span><span>secrets.constants</span><span>]))</span><span> </span>
(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:

<span>user=></span><span> </span><span>(</span><span>secrets.core/randbelow</span><span> </span><span>9999</span><span>)</span><span> </span><span>7612</span><span> </span>
<span>user=></span><span> </span><span>(</span><span>secrets.core/randbelow</span><span> </span><span>9999</span><span>)</span><span> </span><span>7612</span><span> </span>
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.

<span>user=></span><span> </span><span>(</span><span>secrets.core/choice</span><span> </span><span>[</span><span>"bob"</span><span> </span><span>"alice"</span><span> </span><span>"eve"</span><span>])</span><span> </span><span>"eve"</span><span> </span>
<span>user=></span><span> </span><span>(</span><span>secrets.core/choice</span><span> </span><span>[</span><span>"bob"</span><span> </span><span>"alice"</span><span> </span><span>"eve"</span><span>])</span><span> </span><span>"eve"</span><span> </span>
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:

<span>(</span><span>secrets.core/choices</span><span> </span><span>[</span><span>"bob"</span><span> </span><span>"alice"</span><span> </span><span>"eve"</span><span>]</span><span> </span><span>2</span><span>)</span><span> </span><span>(</span><span>"eve"</span><span> </span><span>"alice"</span><span>)</span><span> </span>
<span>(</span><span>secrets.core/choices</span><span> </span><span>[</span><span>"bob"</span><span> </span><span>"alice"</span><span> </span><span>"eve"</span><span>]</span><span> </span><span>2</span><span>)</span><span> </span><span>(</span><span>"eve"</span><span> </span><span>"alice"</span><span>)</span><span> </span>
(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.

<span>user=></span><span> </span><span>(</span><span>secrets.core/token-hex</span><span>(</span><span>64</span><span>))</span><span> </span><span>"3a3e8e6636000dd3b7d39aa4316935f27c2f013d768f0c00f309efb453f34dbc673060db2cd8af288494892848"</span><span> </span>
<span>user=></span><span> </span><span>(</span><span>secrets.core/token-hex</span><span>(</span><span>64</span><span>))</span><span> </span><span>"3a3e8e6636000dd3b7d39aa4316935f27c2f013d768f0c00f309efb453f34dbc673060db2cd8af288494892848"</span><span> </span>
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.

<span>(</span><span>defn</span><span> </span><span>generate-password-recovery-url</span><span> </span><span>[</span><span>n</span><span>]</span><span> </span><span>(</span><span>str</span><span> </span><span>"https://mydomain.com/reset="</span><span> </span><span>(</span><span>secrets.core/token-urlsafe</span><span> </span><span>n</span><span>)))</span><span> </span><span>(</span><span>generate-password-recovery-url</span><span> </span><span>64</span><span>)</span><span> </span><span>"TItm04q8by00MRMcNBt7I3Yx-wSxyUa79isRLNyQJCd8K75RnqUahwcWA_rURBt1clknJiRGrubapGaUrEUnSw"</span><span> </span>
<span>(</span><span>defn</span><span> </span><span>generate-password-recovery-url</span><span> </span><span>[</span><span>n</span><span>]</span><span> </span><span>(</span><span>str</span><span> </span><span>"https://mydomain.com/reset="</span><span> </span><span>(</span><span>secrets.core/token-urlsafe</span><span> </span><span>n</span><span>)))</span><span> </span><span>(</span><span>generate-password-recovery-url</span><span> </span><span>64</span><span>)</span><span> </span><span>"TItm04q8by00MRMcNBt7I3Yx-wSxyUa79isRLNyQJCd8K75RnqUahwcWA_rURBt1clknJiRGrubapGaUrEUnSw"</span><span> </span>
(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.

<span>(</span><span>secrets.core/token-urlsafe</span><span>(</span><span>16</span><span>))</span><span> </span><span>#</span><span>object</span><span>[</span><span>"[B"</span><span> </span><span>0</span><span>x3b2454e9</span><span> </span><span>"[B@3b2454e9"</span><span>]</span><span> </span>
<span>(</span><span>secrets.core/token-urlsafe</span><span>(</span><span>16</span><span>))</span><span> </span><span>#</span><span>object</span><span>[</span><span>"[B"</span><span> </span><span>0</span><span>x3b2454e9</span><span> </span><span>"[B@3b2454e9"</span><span>]</span><span> </span>
(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

原文链接:Generating secrets in Clojure

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
Time such as water, always silent. If you are well, it is sunny.
时光如水,总是无言。若你安好,便是晴天
评论 抢沙发

请登录后发表评论

    暂无评论内容