0
$\begingroup$

I'm building an application for securely backing up cryptocurrency private keys or 12-word backup phrases that crypto wallets use as a seed to generate private keys. For the purpose of this question, if you're unfamiliar with cryptocurrency, you just need to know that whoever knows your private key can spend your money.

This is the backup process:

  • The user encrypts his plaintext with a password (I'm using scrypt and AES256)
  • The ciphertext is base64-encoded, and both the ciphertext and some header data are encoded as a single QR code -- this is the user's backup
  • The user prints several copies of the QR for storage
  • If the user's computer crashes and he needs to restore his backup, he can scan the QR code and provide the password to decrypt the message and retrieve his private key(s)

The QR code contains the scrypt parameters, salt, initialization vector, and the ciphertext.

My question is: Do I need to add an HMAC signature to the contents of the backup? If possible, I'd like to leave it out, since it significantly increases the complexity of the resulting QR code, and complex/large QR codes are more difficult for devices to scan.

I'm thinking I don't need an HMAC signature because, if the ciphertext is altered in any way by a malicious party, the resulting altered plaintext will be useless to the user - he won't be able to recover his cryptocurrency. Altering the ciphertext would produce the same results as simply destroying the user's backups (a signature can't protect against that). A length extension attack would also be pointless in this context.

The fact that an altered backup is useless seems like a built-in integrity check, making a signature redundant. Is this conclusion correct, or do I need to add a signature?

$\endgroup$
0
$\begingroup$

No, I don't think that a HMAC is necessary here. However, you may want to consider what happens if the QR code is indeed wrong. For instance, it was found that a system that used passive RFID tags was vulnerable against buffer overrun attacks: all the attacker had to do was to increase the size of the ID represented by the tag.

Ultimately you want simply to keep the private key value secret. The validation of the private key can be handled by performing an action on the wallet. If such an action is not possible on its own or if the verification of the private key solely rests on the decryption of that key then you may be in trouble: you need some way of verification that the decryption result is OK. Padding in that case cannot be trusted enough to be worth the cost (and if you can pad then you can also not pad and store a authentication tag (MAC value).

Having a MAC over the ciphertext makes it much easier to prove security. Note that you can derive the IV from the salt and the pass phrase using scrypt or scrypt and a KDF/PRF (such as, funny enough, HMAC), so you could replace that with an authentication tag. Using SIV mode is also possible, then the IV would double as authentication tag.

The scrypt parameters could be represented by a single protocol version byte representing hard coded parameters.

$\endgroup$
  • $\begingroup$ This is a good reminder to always sanitize user input, whether or not you're implementing cryptography. On the subject of deriving the IV from the salt... if I'm comfortable with a salt that's the same size as my cipher block (16 bytes), then I can just simply use the same value for both IV and salt, right? A new random salt/IV is generated every time the user runs the encryption. $\endgroup$ – Ransauce Jan 24 '18 at 5:52
  • $\begingroup$ Using the same IV/salt is possible, although some crypto purists would balk at it. Usually the IV is simply derived from the KDF used (scrypt or a followup KBKDF such as HKDF) in a similar fashion as the key. $\endgroup$ – Maarten Bodewes Jan 25 '18 at 17:23

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.