clj-branca: lessons learned

Last week, I wrote about about creating a Clojure library for encoding and decoding Branca tokens. The library is finally ready. It’s called clj-branca and the version 0.1.1 is now out.

Quick pitch

Need to pass information from a service to another service, possibly going through an user’s browser? URL-safe authenticated encrypted tokens could be the solution you’re looking for. Check clj-branca out!

(Please do not use it for stateless sessions, it’s a bad idea. Also, this is a side project, it has not been audited, and I’m not a security engineer. These same caveats apply to a lot of security-related open-source libraries but it does not mean that you should ignore them.)

Lessons learned

When I started the project, I thought it would be a quick way to kick the tires of Branca and libsodium. Like I wrote last time, it wasn’t quick, but on the other hand, I learned more than I expected.

base62 encoding. Branca tokens are Base62-encoded. This means taking the raw token data as an array of bytes and encoding it into printable, URL-safe ASCII string with a 62 character set. It’s the same idea as Base64, but without the - and _ character used by the URL-safe variant of Base64.

Encoding and decoding Base64 is very efficient. Since log2(64) = 6, each Base64 character represents exactly six bits. It’s straightforward to create encoders and decoders that work in linear O(n) time. However, log2(62) ≈ 5.95. Arbitrary radix conversions cannot be done in linear time – based on some Internet searches, I think their complexity is O(n log(n)). This means Base62 encoding and decoding cannot work in linear time.

Base62 is probably fast enough for all Branca use, but aesthetically this bothers me. Base64 is practically as URL-safe (as long as you use the URL-safe variant and do not use padding) and there are performant implementations available for almost any platform imaginable.

sodium on JVM. Lazysodium is probably the easiest way to use libsodium on JVM, because it bundles the libsodium binaries in the jar. However, its “Lazy” interface does weird hex string conversions and I couldn’t figure out how to use it interoperably with libsodium on Node.js. I recommend using the “Native” interface, which looks very C-like, but which does what you expect from the type signature and libsodium documentation.

Even better option would be to use Google’s Tink, which contains pure-Java implementations of many of the same algorithms. It encourages you to buy into its key management scheme, which is probably a good idea.

deps.edn and releases. Clojure CLI does not come with any tools for building jars or deploying them to Clojars. Using this guide, I managed to cobble together Maven, pack, and a bunch of shell scripts. If you know what you’re doing, it is possible to create a release with correct SCM (git revision) information with this setup. The jar is not signed, but I’ve given up on that.

Anyway, I would not recommend this brittle setup. If you’re developing new libraries, save yourself time and energy by using Leiningen and lein release.

sourcehut. clj-branca is hosted on sourcehut, which is this new software development platform akin to GitHub. It’s structured as a bunch of separate services: there’s the project hub, git repo, issue tracker, and, uh, mailing list. If you want to contribute a patch, you’re welcome to send it to the mailing list. You can do this via sourcehut’s user interface if you register a user account.

To be honest, I’m not a big believer in mailing lists. This is going to be a barrier against contributions, but I was not expecting many contributions in the first place.

Sourcehut is pretty basic, but the features that are there seem to work well and quickly. I think I will use it for my private projects, but the biggest benefit of GitHub for open-source projects is that everybody else is already an user and that is going to hard to beat.

Comments or questions? Send me an e-mail.