This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-05-04
Channels
- # announcements (1)
- # architecture (7)
- # beginners (44)
- # biff (11)
- # calva (15)
- # cider (5)
- # clerk (9)
- # clj-kondo (20)
- # clj-on-windows (19)
- # clj-yaml (2)
- # cljs-dev (39)
- # clojure (52)
- # clojure-czech (2)
- # clojure-dev (11)
- # clojure-europe (28)
- # clojure-hamburg (10)
- # clojure-hungary (3)
- # clojure-nl (1)
- # clojure-norway (59)
- # clojure-uk (5)
- # clojured (2)
- # clojurescript (33)
- # conjure (2)
- # datahike (1)
- # datomic (5)
- # defnpodcast (5)
- # emacs (18)
- # figwheel (2)
- # funcool (6)
- # graphql (1)
- # hyperfiddle (11)
- # jobs (3)
- # joyride (13)
- # malli (6)
- # music (4)
- # off-topic (45)
- # polylith (11)
- # practicalli (3)
- # rdf (3)
- # releases (1)
- # scittle (8)
- # shadow-cljs (13)
- # specter (2)
- # squint (8)
- # testing (6)
- # tools-deps (21)
- # xtdb (2)
Cross-posting because it touches on a broader discussion about getting cryptographically random data in the Clojure ecosystem. Together with @mfikes and @dnolen we recently improved the random-uuid implementation in ClojureScript making it considerably faster (https://clojure.atlassian.net/browse/CLJS-3369). However, it is not ideal, since it didn't fix the ultimate problem that it relies on Math/random in the form of rand-int instead of proper crypto functions. For that I thought about something like this:
(defn get-array
[]
(js/Array.from (.getRandomValues js/crypto (js/Uint16Array. 2048))))
(defn get-uint16
[]
(let [uint16 (when crypto-array
(.shift crypto-array))]
(if-not uint16
(do (def ^:dynamic crypto-array (get-array))
(get-uint16))
uint16)))
(defn crypt3-random-uuid
"Improved UUIDv4 generation."
[]
(letfn [(quad-hex []
(let [unpadded-hex ^string (.toString (get-uint16) 16)]
(case (count unpadded-hex)
1 (str "000" unpadded-hex)
2 (str "00" unpadded-hex)
3 (str "0" unpadded-hex)
unpadded-hex)))]
(let [ver-tripple-hex ^string (.toString (bit-or 0x4000 (bit-and 0x0fff (get-uint16))) 16)
res-tripple-hex ^string (.toString (bit-or 0x8000 (bit-and 0x3fff (get-uint16))) 16)]
(uuid (str (quad-hex) (quad-hex) "-" (quad-hex) "-"
ver-tripple-hex "-" res-tripple-hex "-"
(quad-hex) (quad-hex) (quad-hex))))))
It just shows getting a bigger chunk of random data and then basically taking smaller chunks from this small buffer is quite efficient. However, this is too concrete, hacky and very likely thread UNsafe in my view. I would much rather open a discussion in the Clojure and ClojureScript community about how we would like to treat getting cryptographically random data and whether everybody is fine with the current state of things.
I envision basically a /dev/urandom but with configurable output to get e.g. a byte stream, or an endless well of characters possibly even constrained to some alphabet/ strings possibly from some alphabet/doubles possibly from some range/ longs possibly from some range or whatever the literals and possibly even platform specific types are. This would make it much simpler to implement random-uuid in ClojureScript properly, however it could probably make it much simpler to implement portable libraries for cryptographic key generation/ generating truly random data e.g. for testing. The idea is to focus on practical usability and good performance (it shouldn't be much slower than tapping directly into /dev/urandom). My naive JavaScript implementation was able to reach about 1/8th of the /dev/urandom bandwidth based on the measurement of how many UUIDv4s I am able to generate per second in Chrome. The biggest bottleneck seems to be the browser/ the browser API.
What do you think?Are there any cryptographically safe default random number generators in other languages? In the languages I know and have used, the built-in random functions are unsafe.
This is the kind of thing where my first question is, what does Java (and JS) provide and can we just use the host
I have shown the most widely supported thing for JavaScript. (js/crypto.getRandomValues js/somearray) This is quite inconvenient/ inefficient as is - therefore the question. @UEENNMX0T Certainly the Clojure version of random-uuid is based on cryptographical APIs of Java as that is precisely the place to use proper crypto. The ClojureScript version should use proper crypto for random-uuid by default too. If for some reason it needs to fall back it should be possible for the developer to know that is/ was the case. This difference should be explicitly noted in the docs as it might have quite far-reaching consequences (e.g. higher chance of collision).
This is not the first time the suggestion has come up. I think it is fine to use JS Crypto if it is available, I don’t think we need to signal anything beyond updating the docstring. Patches welcome.
@dnolen what do you think about using this opportunity to introduce this "well of randomness in manageable form" as I propose? I want to prevent doing a specific implementation just for random-uuid, when this could have much broader use.
that doesn’t mean only fixing random-uuid
- wherever Clojure uses secure random, ClojureScript should too
If I see a question on http://ask.clojure.org that has an open jira ticket with (imo) a solid problem statement and proposed solution, is a patch implementing the proposed solution welcome? what is a concrete step I can take to move the ticket forward, if any?
Yes, you can provide a patch on jira if you follow the contributor steps (sign the ca, request a jira acct to attach a patch)