Have My Salt (And My Iterations Too!)
(Or why storing salt (and iterations) alongside hashed passwords is just fine)
Crypto is tricky, so getting your head around all the various bits of key material involved can be challenging. There are quite a number of good resources on this subject. Iâll be referencing various specifications and best practices here - but perhaps someone out there will benefit from my style of explanation.
Specifically, letâs talk about encrypting a Private Key file that weâll use in some sort of Public Key Infrastructure (PKI). Of which, weâll need the following components:
Passphrase
Youâre going to need a passphrase: NIST likes to call this a âMemorized Secretâ. You might know it as âpasswordâ. Whatever you want to call it, this is âSomething You Knowâ. This is the thing that youâre encouraged to create long versions of, perhaps generate randomly and put in a vault such as Bitwarden or LastPass (well, maybe donât use that one anymoreâŠ), so on.
A passphrase must be strong for you to have strong encryptionâŠ
Iâll say it again: A passphrase must be strong.
Good techniques for ensuring strong passphrases are actually quite limited though youâll find many anti-patterns all around you:
- Length: Youâll see recommendations for 8+ characters, perhaps 12 or 16⊠The longer isnât necessarily the better depending on your hashing algorithm, but Iâm not going to get into the details on that here. Itâs fine to think âthe longer the betterâ as a general rule of thumb.
- Checked against top well known passphrase/password lists. Basically youâre going to block out things like âpasswordâ (that yes, people really use this all the fucking time in 2023), âBryan1978â (âŠoof), etc. Resources are readily available on the web.
- Annnnd⊠Thatâs really mostly it. âMust include Xâ is an anti-pattern. âNo longer than Yâ. Anti-pattern. Truncating input? Anti-pattern. Youâve seen these everywhere, I know. We can cry together over beers.
đĄ You could generate a strong passphrase randomly and stuff it in a vault for extra layers of security. Remember to use a strong passphrase for your vault, too! In Linux you could do something like this:
strings /dev/urandom | grep -o '[[:print:]]' | head -n 32 | tr -d '\n'; echo
Salt đ§
A salt is a random value used in conjunction with the input passphrase when hashing. You might see this as ânonceâ in various applications. Their purpose? Prevent against repeat (or âreplayâ, âŠ) attacks (Get the name with ânonceâ?) What that means is if I have for example pre-generated a big list of passphrase:hash values, and didnât use the particular salt for a particular passphrase that you did, my list is of no use! It is absolutely best practice to generate a new salt for a given passphrase. And, when the salt is sufficient in itâs length and randomly generated, the chance that I have hashed passphrases with the same salt as you are, well up to the length (again!) and I suppose the RNG gods.
Hot damn, weâre on the topic a key reason for this post⊠salt storage! This is where it getâs a little more confusing. The salt is not considered a secret. Do you want to paste on the Internet? Probably no, but actually you could with little fear. But donât take my word for it.
As discussed above, the salt is to prevent repeat attacks. But the salt is also required to decrypt encrypted material or come up with a matching hash given a passphrase. It is true that given the salt, an attacker can attempt to brute force your passphrase. However, the power is not in the salt. Itâs the length of your passphrase covered above. Is life a little easier for an attacker if they know my salt? Actually yeah a little. The problem is however, itâs needed to decrypt. So anywhere validation/decryption occurs the salt needs to be known âin plain textâ (or in raw decimal, or whatever you use). In other words, if the attacker can get their paws on your hashes, they can get their paws on your salts. Itâs fine though. Donât care about that. What we donât want them to have is your strong passphrase.
Often, we donât even have a choice! Letâs look at a concrete example â Encrypting a Private Key file we plan on using for certificate signing. If youâre not up on it, itâs OK. Quick explanation: A Private Key is in a way, a super duper long version of a passphrase. Itâs what actually is used to encrypt data. What if a bad actor gets their hands on a Private Key? Ouch! They are now able to represent themselves (when certificate signing) as you! So letâs protect it a bit by encrypting the Private Key! Now if CptBaddiePants gets their hands on your MySigningPrivateKey.pem
, theyâre going to need âSomething You Knowâ to do decrypt and use it. Hey, itâs that passphrase thing!
But guess what else you need to know to decrypt your private key? The salt that was used with it (and, depending on the algorithm, the iterations⊠Iâll touch on them a bit later). Now, if we expect you to have to keep track of the salt, what does that smell like? If youâre following along, it will smell an awful lot like just another password. Thatâs certainly not very helpful. See where this is going? Weâre going to need to put it with the encrypted private key file so it can be of any use. But remember: This is OK!.
Cool, so a quick run through using OpenSSL for you to actually do the needful. In this case, weâll create a ECDSA P-256 (in which you may see referred to as names like âsecp256r1â or âprime256v1â) Private Key, then encrypt it with AES-256-CBC.
1 | # Generate the Private Key |
See the line there with the encryption info? Guess what?
DEK-Info: AES-256-CBC,A5DB8977466F0618E69828745C4A4B43
Whao now bro, youâre storing my salt⊠But Iâm not mad!
If I want to decrypt and use the PrivateKey.pem
file above, I need what matters: My passphrase. Hopefully I used a good one!
đĄOpenSSL will not require a strong passphrase! Thatâs left up to the user. Better not make it âpasswordâ though, because thatâs in my list âș
Letâs look at another example, a Linux /etc/shadow
file. The format is roughly this:
1 | sonic:$6$123:17736:0:99999:7::: |
Where we can break down the relevant portion above a little more. See that $6$.n.
labeled âEncrypted Passwordâ? It goes like this:$<TYPE>$<PARAMS>$<HASHED>
. In this particular case, type 6=SHA-512, of which uses only a salt (no iterations) = 123.
What happens if a bad actor manages to get my shadow file? While I wonât be happy, Iâll mostly not be super concerned. Of course Iâll update my passphrase.
If we were to create a PBKDF2 version of our passphrase and store it in a shadow file, it may look something like this:
1 | mario:$PK2$a2pqcE1TM1lMS3VrZ0c2bXNQb3ZjZWF4VVBOTFFiQVN2X1Z5MXl3Szh4T2V3NFJ6cXdxdGdOdjVXclo3S18zYmE1eWh0bFJGd3FFZFk1U21iZG0xdmUK.250000:...hash value and so on... |
Sweet! Thatâs 86 characters of base64 encoded salt, and 100k iterations! Iâm actually making this up, as /etc/shadow
doesnât support PBKDF2 generally, but grub does! Letâs look at itâs format. Itâs quite similar:
1 | grub.pbkdf2.sha512.<ITERATIONS>.<SALT>.<HASHED> |
Yep, Iâm seeing some patterns here!
Iterations đ
Weâve fumbled over iterations a few times in this already, so itâs probably sinking in now: Iterations are effectively a way to wast the attackers time. As CPU and GPU power just keeps getting better and better, cracking a passphrase by simply using a secure hash such as SHA-256 may not be enough. Letâs make the attacker do that a ton of times! This need not be any secret however; in fact, if weâre using this method, like the salt we must have it in hand to decrypt â and it falls within the âparametersâ group of material! What the attacker learns is a hint on how long the cracking may take. Thatâs really about it. You could read it something like this:
âAt the time this iteration was chosen, we have speculated that it would take N amount of time to crackâ.
We want that time to be a long time. A very long time. But of course cracking hardware keeps getting faster and faster creating a cat and mouse game⊠but thatâs another whole can of worms.
So have my salt, and have my iterations too! But Iâm keeping my my passphrases to myself!
I hope was helpful to some. Iâm sure Iâll get nasty responses; In which I will likely just update this article with more relevant links to specifications, NIST/OWASP et al. to back these claims. Or maybe Iâll just get âyou spelled $wordâ wrong like I usually do (âŠand I do usually spel gud.).
Until next timeâŠ