Skip to main content

ยท 7 min read
Conrad Ludgate

End-to-end encryption is an essential component of Atuin. One of our core philosophies, when we created the sync service, was that we didn't want to worry about storing user data. The shell is a very sensitive system with API keys, AWS credentials, account passwords, etc. We didn't want to give the opportunity for that data to leak, either through an attack, or through a mistake on our part.

If there's one thing I have learnt as an engineer, it's that cryptography is hard. If you are an expert in cryptographic implementations or cryptoanalysis, please get in touch. This post will cover my research as - a non-crypto expert - into the long-term security of Atuin history data.

Disclaimer, where reasonable, I have considered the security of Side channel attacks. Right now, our biggest concern is attacks on the atuin server, where the encrypted data is stored at rest. All atuin data is stored unencrypted on your local device in order to perform search queries. Improvements to cryptographic implementations can come in later revisions if any realistic side-channel attacks are found.

TL;DRโ€‹

Our encryption system is changing from NaCl secretbox, and moving to PASETO v4 local encryption with PASERK local key wrapping.

Backstoryโ€‹

All the way back in April 2021, in our V0.5 release, Ellie decided to use the NaCl standard (aka salt/libsodium) for our encryption as a tried and trusted standard. Specifically, secretbox was the algorithm of choice.

If you're not familiar, secretbox is an implementation of authenticated symmetrical encryption. This means that only the owner of the encryption key can decrypt the data (this will be the user), and that any attempts to tamper with the data can be detected.

Honestly, this is a great system and offers everything we needed. However, our interface to libsodium is a now unmaintained crate called sodiumoxide and had issues being portable. Because of this, I started looking into what algorithms libsodium uses underneath and if we can use a native Rust implementation.

Secretbox is made up of two main components. A stream-cipher and a message authentication code. These are XSalsa20 and Poly1305 respectively, designed by NaCl's author Daniel J. Bernstein. In a brave effort, I decided to roll my own crypto and implement this XSalsa20 + Poly1305 system in Rust.

NOTE: I didn't actually implement the underlying algorithms. we are using:

From the RustCrypto project. These algorithms are not known to be vulnerable to software-based side-channel attacks.

Back to the drawing boardโ€‹

After peeling back the veil that is our cryptographic implementation, I started thinking a lot more about just how secure the system is.

The more I started looking, the more I noticed potential improvements. Salsa20/Poly1305 both date back to 2005. In another 20 years, is this system going to still be secure?

Let's take a look at some potential attacks

We don't guarantee a unique Initialisation Vector (IV) per messageโ€‹

We use a random 192-bit IV. There is a known attack on stream-ciphers if the Key + IV pair is ever re-used. For all practical purposes, this is enough, assuming the OS random source is any good. A birthday attack calculation suggests that it needs in the order of 10^23 messages for a one-in-a-trillion chance of collision.

This is not an issue as all of our users combined are never going to generate 10^23 entries, and we certainly aren't willing to store zettabytes of their data.

We use the same key for each messageโ€‹

Shell history is quite predictable. If you have a 2-byte history entry, it's quite likely that it's ls. Given the encrypted blob, you can start to brute force the associated key. A proof was published stating that no attack on Salsa20 with 128-bit key is possible with an average search time of less than 2^130 (about 10^39) random guesses.

To put that number into perspective. Performing 1 billion key operations per CPU core per second, and using a suite of 1 billion CPU cores, the attack will take roughly 10 trillion years.

Atuin uses a 256-bit key which is even more secure, and therefore not at risk of a practical brute-force attack. It follows that we are likely safe from a known plain-text attack.

However, there is still the issue of key leaking. We have no key-upgrade policy. If a key is leaked, maybe through a side-channel attack, a social attack, or malware, then the only solution is to create a new account with a new key.

This is partially an issue.

What we can changeโ€‹

While researching these systems, I learnt of many new cryptographic techniques that some modern systems use. While the analysis above indicates that we are protected, there might be attacks we are unaware of, so keeping up with modern research is important.

We're also in the middle of redesigning our sync service. While we're already planning a big change, we might as well consider updating the encryption too.

Key wrappingโ€‹

A common approach to encrypting lots of items is the use of wrapped keys. The idea here is that each payload has an associated random encryption key. This key is then itself encrypted (wrapped) using the master key and stored with the data.

Initially, this seemed less secure to me. However, my research seems to point out that the master key is less vulnerable to side-channel attacks since it is less used. It also offers no decrease in overall security since brute-forcing the master key from an random key is just as hard as it is for any message. In the end, it's like a password manager for your encrypted data.

This would unlock some potential future upgrades.

  1. Key rotation is easier since you need to re-encrypt the wrapped keys. This means much less data needs to be updated.
  2. Wrapped data keys can be decrypted in Hardware Security Modules (HSM) which are immune to side-channel attacks

Stronger ciphersโ€‹

XSalsa20 was later superseded by XChaCha20 by the same author. It has a very similar construction, but the stream cipher has better mixing characteristics, which makes any non-brute-force attacks harder to craft.

Conclusionโ€‹

I started to craft a new solution using these concepts. But eventually, I realised that I shouldn't be reinventing the wheel here. During more and more of my research sessions, I stumbled upon PASETO. While the intended use case is security tokens, their local encryption scheme is designed such that encrypted data is safe to be shared publically. Their V4 scheme also uses the XChaCha20 cipher which I was initially planning to use.

In the end, I bit the bullet and decided to use the standard. The nice thing with secretbox is that existing implementations in other languages are widely available. Making it easy to implement sync in third parties. If we implemented our own scheme, that would make it much easier for third parties to make mistakes if they wanted to use the sync data directly.

Using PASETO, there are existing implementations that we didn't have to write. This means that we don't build software doomed to die a lonely death. It also means that we benefit directly from future versions of the specification.

ยท 5 min read
Ellie Huxtable

Announcing a new release of Atuin! v15 is out now. This release is not particularly feature-heavy, instead we have focused on a number of bugfixes and improvements - with lots of new shiny things planned for v16.

I've also included the changes from v14.0.1 in these notes, as we never did a separate post for them

Communityโ€‹

Sync changesโ€‹

For the first time in a long while, we have made an adjustment to how sync functions. In the longer term, we intend on replacing our current sync algorithm with something that better handles consistency, but v15 should at least ship some performance improvements.

Older versions of Atuin used a fixed page size of 100. This meant that for each request, we could only upload or download 100 history items at a time. For larger histories, this meant a lot of HTTP requests + a fairly slow sync.

Atuin v15 ships a variable page size, defaulting to 1100. This is configurable on the server, via the page_size parameter. A smaller number of larger requests generally performs better in our testing.

For self hosted servers, please note that reverse proxies may require configuration changes to allow for larger requests.

What's Changedโ€‹

New Contributorsโ€‹

Full Changelog: https://github.com/ellie/atuin/compare/v14.0.0...v15.0.1

ยท 7 min read
Ellie Huxtable

We have since released v14.0.1 with some fixes, following a NuShell breaking change. A writeup of other included changes will be included in the next release notes!

Announcing a new release of Atuin! v14 is out now. Atuin allows you to easily search and sync your shell history across many machines. Get started here

You can update your installation via your system package manager, or by downloading the latest release from the release page.

This release introduces some breaking changes, so please ensure all Atuin clients and servers are updated or sync may not complete. If you have any issues, please try atuin sync --force

We had a lot of changes in this release - I'll call out a few, but this is not exhaustive. Read the changelog below for the full list!

Communityโ€‹

New Featuresโ€‹

Deletionsโ€‹

You can now delete history! This has been our longest-standing issue, and one we are frequently asked about. So it's great to get it out! It took us a while due to the nature of sync, and we wanted to try several different approaches. There is still no way to delete history from the UI, however you can now pass the --delete flag to any atuin search command to delete all history matching the query. I suggest you run the search without the delete flag first, just to check what you are removing

For example, to delete all commands that start with psql:

atuin search --delete --search-mode prefix psql

NuShellโ€‹

We now support NuShell! This was a huge effort by @stevenxxiu, and involved work on both Atuin and NuShell itself. The effort was greatly appreciated, thank you so much ๐Ÿ’–

Run in Nushell:

mkdir ~/.local/share/atuin/
atuin init nu | save ~/.local/share/atuin/init.nu

Add to config.nu:

source ~/.local/share/atuin/init.nu

PRs:

Inline history UIโ€‹

inline history

Another of our biggest asks - the UI can now be configured so that it does not take the entire screen. Thank you to @pdecat

Simply add

# Choose a height for the inline history search
inline_height = 40

to your Atuin config file, and you're good to go!

We didn't sort it in time for v14, but in v15 you will also be able to configure the UI more deeply - for instance, change the position of the search bar.

We have also added an alternative new search mode! This uses skim behind the scenes. Check it out with search_mode = "skim". Thank you @conradludgate

Windowsโ€‹

Atuin now provisionally supports Windows! We cannot provide full support + releases won't be tested to the same level on Windows, however a few contributors have now been building + running on the platform without issues. Thank you so much to @YummyOreo for this one!

Command previewโ€‹

preview

Previously, longer commands would be cut off in the UI. Thanks to @pdecat, we now have a preview window! Enable it with a show_preview = true

Improvementsโ€‹

  • Bash import improved
  • Prefer PWD env variable over cwd to better handle symlinks
  • Ignore common prefixes and subcommands in stats calculations
  • Add musl build
  • Add atuin status command to check sync status

Stickersโ€‹

Since the last release, we have printed some stickers!

If you'd like one, please fill out one of the following:

New contributorsโ€‹

A special thank you to everyone who contributed for the first time in this release!

Sync server statsโ€‹

I've ran a public sync server since the very beginning, and thought I'd share some stats from it! Bear in mind all data is encrypted, so the data we can see is only very high level.

In March, we saw:

  • 2,031,355 history lines synced up, with a total of 13,077,001
  • 137 new users, with a total of 1136 (we passed 1000!)

We also cleared 500 monthly active users for the first time! See the charts below for DAU/WAU/MAU

Full changelogโ€‹

Next releaseโ€‹

While this release was pretty big, we have a lot planned for the next one too! It should be out around the beginning of May.

GitHub: https://github.com/ellie/atuin/compare/v13.0.1...v14.0.0

ยท 6 min read
Ellie Huxtable

We have since released patch v13.0.1. v13 had a regression exposed when trying to register a new user. This would only affect people self-hosting Atuin Server. Please update!

Announcing a new release of Atuin! v13 is out now. Atuin allows you to easily search and sync your shell history across many machines.

You can update your installation via your system package manager, or by downloading the latest release from the release page.

We had a lot of changes in this release - I'll call out a few, but this is not exhaustive.

Crosstermโ€‹

Deserving of a special callout, we now use Crossterm as our TUI backend - this has been a huge effort, and has taken almost a year. Thank you to Conrad for pushing through it, and @pdecat for your contributions!

In the future this will allow for things like (possible) Windows support, and only using a small part of the screen for the search UI. It also handles async input better.

Please let us know if you experience any issues!

New featuresโ€‹

Pretty Statsโ€‹

stats image

While procrastinating writing his talk, Conrad added a new and improved stats display! Just run atuin stats to see your statistics. It'd be awesome to see what yours looks like, so please share it with us on Twitter or Discord!

Custom history list formatโ€‹

List history however you want! You can now specify the output format of atuin history list

Example

atuin history list --format "{time} - [{duration}] - {directory}$\t{command}"

See more on the docs page!

History filterโ€‹

The history filter allows you to exclude commands from history tracking - maybe you want to keep ALL of your curl commands totally out of your shell history, or maybe just some matching a pattern.

This supports regular expressions, so you can hide pretty much whatever you want! Thanks for the PR @jbaiter

Configure it in your client-side Atuin config, for example

## Note that these regular expressions are unanchored, i.e. if they don't start
## with ^ or end with $, they'll match anywhere in the command.
history_filter = [
"^secret-cmd",
"^innocuous-cmd .*--secret=.+"
]

Mnemonic key (BIP39)โ€‹

Previously, it was awkward to copy your Atuin key from machine to machine. Even more awkward to back it up!

We now use BIP39 to display your key in a nice + easily readable haiku-style format. Still - please don't share it!

Improvementsโ€‹

  • Better error messages
  • Nix install files + instructions
  • Exit when pushing the down arrow from the most recent entry
  • Refactor to support generic server-side databases
  • Make it easier to disable the ctrl-r and/or up arrow bindings
  • Update to axum6

Fixesโ€‹

  • Fish now handles multi-line commands properly
  • Listing history for the current session now works
  • Fix atuin init for Fish

Contributor Shoutout!โ€‹

@patricksjacksonโ€‹

@pdecatโ€‹

@Sciencentistguyโ€‹

@BapRxโ€‹

@yolo2hโ€‹

@s1ckโ€‹

@conradludgateโ€‹

@evanpurkhiserโ€‹

@eripaโ€‹

@trygveaaโ€‹

@fruktoโ€‹

@jbaiterโ€‹

@hungerโ€‹

@ekroonโ€‹

New Contributorsโ€‹

I very much appreciate the work from all contributors, but a special mention to everyone who made their first contribution in this release, no matter how large or small

Future plansโ€‹

I've been talking about it for ages and ages, but now that my life has finally settled down I'm going to be focusing on getting deletions out for the next release. We will be switching to an event-based sync, which should allow for many more features and cool things in the future!

Other changesโ€‹

Talkโ€‹

I spoke about Atuin at FOSDEM! If you want to know more about the project + video is your thing, you can watch it here

Websiteโ€‹

Well... this is new. Previously I never bothered writing much about new releases, and basically just used the autogenerated GitHub release. The docs should be much easier to find here too!

Mastodonโ€‹

We now have a Mastodon account over on Hachyderm! @atuin

Twitterโ€‹

I also opened a Twitter account for Atuin - @atuinsh

If you fancy chatting to us about anything here, or otherwise, please feel free to drop by the Discord!

Full Changelog: https://github.com/ellie/atuin/compare/v12.0.0...v13.0.0