We are developing an open-source peer-to-peer app, Mapeo, designed for users with low technical experience (and no email or phone) to collect data in offline environments. We are generating their identity on the device for each project as a public-private keypair using libsodium crypto_sign_keypair.

To support identity recovery in the case of device loss or switching to a new device, we want to use a single master key that is used as a seed for all other key pairs. Users will write down this key and manually enter it to recover their identity (similar to how Bitcoin uses BEP-39 wordlists to backup a 256-bit key).

Ideally we would use a 256-bit seed, which is what is supported by libsodium's crypto_sign_seed_keypair and provides plenty of entropy. However, there are some design limitations:

  1. BEP-39 wordlists are a good solution to facilitate writing down a key and it might be manageable to write down 24 words for a 256-bit key, however only 10 languages are supported, and we are already supporting multiple languages that do not have word lists (e.g. Thai, Khmer, Vietnamese).
  2. Most of our users do not have access to a printer, and are on mobile devices, so their is no easy way for them to print out their key backup as a QR code for example.
  3. The best encoding we have come up with is base-32, since it avoids ambiguous characters. However a 256-bit key with a 32-bit CRC would need 57 characters in base-32. In our design mockups this is an overwhelming random string (even displayed in groups of 5 characters) and we are concerned it will lead to transcription errors.
  4. Since many users use non-latin alphabets, we may need to display the key as numbers (e.g. arabic numerals) since they are more widely understood. However a 256-bit number is 77 digits, which is hard to write down or enter without an error.

To work around these limitations, my question is whether a 128-bit seed / master key would provide enough entropy for "good enough" security. It is more manageable to write down (30 base-32 characters with a CRC-16, or 44 numerals).

I propose deriving a 256-bit seed (for seeding keypair generation and deriving subkeys) by hashing the 128-bit seed with Argon2 (see libsodium pwhash).

I realize that this gives us only 128-bits of entropy, but since it's hashed to 256-bits with Argon2 it would be costly to brute force.

I am no security expert (you may have gathered that by now!) but my question is whether this idea of a 128-bit seed / master key is enough entropy to make brute-force attacks hard / impossible. We are not looking for NSA level encryption, but enough to prevent a determined attacker (possibly state-sponsored) from being able to brute-force.

It is a compromise between usability and security, we want to keep the app easy enough to use securely, and keep the security good enough, and I'm not sure where the right balance is in terms of key length / entropy.

  • $\begingroup$ 144 bits would be not much worse for the UI and 65,000 times harder to crack. $\endgroup$
    – gnasher729
    Nov 26 at 17:01
  • $\begingroup$ It doesn't help to use more than 128 bits of entropy when generating the EC private key, since 256-bit EC curves only have a security level of 128 bits. See crypto.stackexchange.com/questions/39991/… $\endgroup$
    – knaccc
    Nov 28 at 14:31
  • $\begingroup$ Thank you @knaccc that is a really helpful link and very helpful information. $\endgroup$
    – Gregor
    Nov 29 at 15:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.