20220112_clortho.rst (7241B)
1 Secrets in the shell 2 #################### 3 4 :date: 2024-06-25 20:46 5 :modified: 2024-06-25 21:58 6 :category: Code 7 :author: Louis Holbrook 8 :tags: crypto,hash,sha512,bash,cli,ccrypt 9 :slug: clortho 10 :summary: A key value store at your fingertips 11 :lang: en 12 :status: published 13 14 15 Ever since I started using the pass_ CLI as my password manager, I've found myself putting all sorts of stuff in there; usernames, email, urls, crypto addresses, api keys, you name it. 16 17 It makes total sense that some of these items are in there. For example, I store the url to a service together with the password, usually accompanied by the username and the email used [1]_. No password recoveries needed. 18 19 However, at some point I also started putting in things like crypto addresses, or even token smart contract addresses in there. 20 21 That seemed less of a good fit. 22 23 One thing is that it spams the password directory. 24 25 Another, perhaps more sinister, issue is that it's pretty clear for anyone reading the directory what items you are storing data for. 26 27 So what if I want to store key/value pairs, and at the same time I want to hide what I am storing? 28 29 30 Hiding in plain cipher text 31 =========================== 32 33 34 A simple solution is to hash the key together with some passphrase as "salt", along the lines of this: 35 36 .. code-block:: bash 37 38 key=$1 39 # read passphrase from stdin 40 stty -echo 41 echo -n "passphrase: " 42 read passphrase 43 stty echo 44 hash_key() { 45 # dump the passphrase (assuming mktemp stores in volatile memory) 46 ktt=$(mktemp) 47 kt=$(mktemp) 48 chmod 200 $kt 49 echo $passphrase > $kt 50 chmod 600 $kt 51 # the salted key; first add the hashed passphrase (sha512) 52 kc=$(sha512sum $kt | awk '{print $1;}' > $ktt) 53 # remove the stored passphrase 54 shred $kt 55 # then add the key to the mix, and hash again 56 echo $kp >> $ktt 57 kc=$(sha512sum $ktt | awk '{print $1;}') 58 } 59 60 The ``kc`` variable at the end of the script above now contains the *salted* hash of the key. 61 62 Specifically, in this implementation, given key ``"foo"`` and passphrase ``"bar"``, the resulting key will be: 63 64 ``a9454592edbed78c3abb739dd88567bc92cc4ea1feee8480c7204d48d7d0e9ce86f9c79d55e39751ceb3f2774913841056293a5e8e8f440a3f281dffabd6f540``. 65 66 67 Added value 68 =========== 69 70 Now we can encrypt the store the corresponding value, and store it in a file that has that literal hash as the key. 71 72 Using ccrypt_ as an example: 73 74 .. code-block:: bash 75 76 data_dir=$HOME/.obfuscated 77 key=$1 78 vp=$2 79 echo -n "$vp" > $t 80 # create a file for ccrypt to read, because supplying any other way in shell is not so safe. 81 passfile=$(mktemp) 82 chmod 600 $passfile 83 echo -n $passphrase > $passfile 84 chmod 400 $passfile 85 ccrypt -k $passfile $t 86 shred $passfile 87 if [ "$?" -gt "0" ]; then 88 >&2 echo set key fail 89 exit 1 90 fi 91 # run the code in the previous section 92 hash_key 93 mkdir -vp $data_dir 94 cp $t.cpt $data_dir/$kc 95 shred $t.cpt 96 97 At the end of this operation, the *encrypted* value is stored in a file whose name is the *salted* hash of the key. 98 99 100 101 Key Mastering 102 ------------- 103 104 Let's say you want to store some `Ethereum addresses`_ that are of interest to you, but should be of interest to noone else. 105 106 So, let's choose a prefix for "Ethereum addresses." Let it be ``etha`` 107 108 Next, let's pick an identifier that we will remember, that describes the *purpose* of the address. In this case it's for "governance of the organization 'Xy Zzy Co.'". The key then becomes ``ethagovxyzzyco``. 109 110 Last, for a bit of extra fun, let's add some random stuff at the end of the string, like `shilling!shilling?oh,shilling <https://www.quotes.net/mquote/42425>`_. Thus, we finally end up with `ethagovxyzshilling!shilling?oh,shilling``. 111 112 What we need to memorize here is: 113 114 * whenever referring to an *Ethereum address*. we use ``etha`` 115 * whenever referring to *governance*. we use ``gov`` 116 * whenever referring to an entity, we use the name of the organization *less whitespace and special characters*. 117 * the three above are added one after another 118 * add the extra fun 119 120 There will of course always be a pattern to how you create and add similar structures for other categories, actions and entities. 121 122 But the point here is to show that it doesn't take *that much* to have some advantage of *plausible deniability*: Even faced with the `5 Dollar Wrench Problem`_, if you are able to hold your ground, there is no feasible way to prove that you *don't own something*. Bite the bullet, absorb the pain, deny ownership, and you'll be fine. 123 124 125 Perils and pitfalls 126 =================== 127 128 None of this is in no way safe by itself. 129 130 Some concerns are named below. Surely there are others, too. 131 132 133 Out of sight, but still mined 134 ----------------------------- 135 136 You may find it a pain in the ass to type the passphrase for the key salt every time. 137 138 An obvious workaround for that is to store the passphrase in a file. 139 140 But keep in mind that, if you do that, the key obfuscation is going to be less safe than your regular passwords storage. 141 142 That is to say: If the attacker can read your passwords ciphertext, most likely the attacked can read you obfuscation passphrase, too. 143 144 145 Out of mind, out of luck 146 ------------------------ 147 148 Maybe the most important thing to realize in this solution is that there is no way to recall the original keys from the file names under which the values are stored. 149 150 Instead, the idea is that you decide on a naming scheme for certain crucial values you want to store, and *remember* how to reconstruct them. [2]_ 151 152 153 Shell shill 154 ----------- 155 156 The code above has been adapted from a ``bash`` tool I've already written for the purpose, given the name Clortho_. 157 158 Shell script is surely a very poor choice for this kind of thing, but at the time I simply wanted to write shell so that's how it ended up. 159 160 I probably will rewrite it for another environment at some point. 161 162 But for now it illustrates the point. 163 164 165 .. 166 167 .. [1] I use a different email for each service I sign up to, and for every other context I have to leave my email for something. I highly recommend this practice, aswell as running your own mail server. `It really isn't that hard <https://www.linuxbabe.com/mail-server/setup-basic-postfix-mail-sever-ubuntu>`_. 168 169 170 .. 171 172 .. [2] I'm not going to lie: That kind of thing takes practice. As in, you need to remind yourself from time to time what your scheme is. Perhaps that is an unthinkable proposition in the age of the Smartphone and the illusion of auxiliary instant truths. But I come from a time where I knew all numbers and addresses I needed to know by heart. The more you do it, the more you remember. The less you do it, the more you are dependent on others. What others do you depend on? And so on it goes... 173 174 .. _pass: https://www.passwordstore.org/ 175 176 .. _ccrypt: https://ccrypt.sourceforge.net/ 177 178 .. _Clortho: https://holbrook.no/src/clortho/file/clortho.sh.html#l10 179 180 .. _5 Dollar Wrench Problem: https://xkcd.com/538/ 181 182 .. _Ethereum addresses: https://kobl.one/blog/create-full-ethereum-keypair-and-address/