Key Steganography

I have a question about the format of a secret key. Here’s a hypothetical that motivates the question:

I have 100 ZEC and a private key:


I use a password to encrypt part of the private key via characterwise addition mod 32

+ 'password'
= 'secret-extended-key-main1qdkdcwnsqqqabcde..lmnopqr4s9aekc2'

So now I have a second private key. (?)

I put 5 ZEC in the account that goes with the first key and 95 ZEC in the account that goes with the second key. I store copies of the first key in a safe, and I remember the password. So as long as I don’t lose the first key, I can re-derive the second key.

Later, bad guys come to my house and threaten to hurt me if I don’t give them my ZEC. So I give them the first key, and they get away with 5 ZEC. Since I have backups, and I remember the password, I can still re-derive the second key, and I get to keep 95 of my ZEC.

I’ve noticed that all of my keys start with ‘secret-extended-key-main1q’, so I imagine that the first part of the key indicates metadata. But at some point things start looking random.

I want to know if there is any internal structure beyond whatever appears in the key header. And if so, where can I learn about it? If there is a checksum in there, for instance, then I won’t be deriving a second key by adding the password–instead I’ll just be creating an invalid one.

Please don’t do that! The key is an encoding of several fields, so what you’re doing here only changes the last field (the “chain code”), resulting in two keys with essentially the same key material. It probably won’t work anyway because the (Bech32) encoding has a checksum, but if it did it wouldn’t be secure. Always use independently generated keys.

The structure of this kind of key (a Sapling extended spending key) is documented in ZIP 32.


Most hardware wallets support password-based steganography as part of BIP 39, and this would be the easiest way to do this safely.

The recommended way to use BIP 39 for Zcash shielded addresses is to use BIP 39 to generate the 64-byte seed from a mnemonic (the 24-word secret), and then use that seed as the master seed S in ZIP 32. Setting a password during the BIP 39 derivation process will cause a different seed to be generated, and therefore different shielded addresses.

1 Like

Thanks for the information Daira, that’s the kind of thing I was after. I appreciate your warnings about how silly my idea is. I’m not quite yet ready to drop it though, so I’ll go check out ZIP 32.

The problem with independently generated keys is that you have to store them in ways that are resistant to:

  • Misplacement
  • Surveillance
  • Fire, Flood, EMPs, etc

Which is a solvable problem, but I think it becomes much a much more difficult problem if you also want to be able to deny, under duress, that whatever artifact the bad guys found actually contains a key at all. Like, if somebody with a gun shows me three key backups that they found in my house, I had better be able to cough up three valid keys. But if I can secretly use them as starting entropy to come up with a fourth, then I can still hide things from those bad guys.

I figure if you take one key that was generated securely, and you offset it with the equivalent of a one-time-pad, then you haven’t lost any entropy–so the new key is vulnerable to attack only by people who:

  • have the original key
  • know that an offset key exists
  • can find your one time pad.

Do you think this is true?

What we’ve gained here is that it’s easy to use things as one time pads that don’t look cryptographically relevant at all, which is more than can be said for a direct key backup or a BIP 39 mnemonic. You can use the last sentence of your favorite novel, for instance, so that you can go buy another copy if your house burns down and still have access to it, and nobody needs to know it that it’s serving as a secret.

(I realize I’m abusing the term “one time pad”, they’re supposed to be random, but it’s the closest term I know).

Having skimmed ZIP 32, it is indeed the master seed that I ought to be manipulating, not the derived key. Thanks for pointing that out.

I wasn’t sure if the key was the seed, or if it had underlying structure, which it looks like it does.

Also, I’ll have to look closer at the BIP 39 process, it sounds like what I need.

1 Like

Hi Matrixman and Daira and str4d:

I skimmed ZIP 32 and noticed that it has a list of “Reference Implementations” at the end. I looked at one of these, and it seemed to refer to the wallet.cpp code. And another one seemed to be a pretty complex .rs (rust?) program.

Is Matrixman’s idea something that could be implemented using zcash-cli called from a shell script? I understand this is really naive and I haven’t put the time in to study this in depth, but it would be nifty if this could be implemented easily (or maybe it already is!).

-All the best