<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Mar 8, 2017 at 8:01 PM, Ray Dillinger <span dir="ltr"><<a href="mailto:bear@sonic.net" target="_blank">bear@sonic.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Okay, to make sure I understand:<br>
<br>
You have four-decimal pins hashed with sixteen-bit salt, and you're<br>
worried about someone stealing the database.<br>
<br>
We can start by talking about the size of the salt.  I mention this<br>
because, since most businesses have more than 65536 customers (or at<br>
least aspire to) it is likely that increasing the size of the salt so<br>
that you can ensure each customer has _unique_ salt, will improve security.<br>
<br></blockquote><div><br></div><div>For a decent chance at unique salts, a good rule of thumb is the square of the expected number of hashes. So if they have a million customers, use a 40-bit salt or longer. This won't protect against someone trying 1234 against all salts in the whole DB and knowing 10% will match, but it maximises the work required to do that.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
The other reason to talk about the size of the salt is because, instead<br>
of using a traditional symmetric encryption algorithm on a database of<br>
hashes, it is better to simply extend the entities being hashed.<br>
<br>
IOW, instead of encrypt(hash(PIN:salt),key), it is simpler to use<br>
hash(PIN:salt:key).<br>
<br>
This extends the work factor for the attacker as effectively as<br>
encryption; finding a hash preimage for 256 bits of PIN+salt+key<br>
requires the same number of attempts as finding a 256-bit key.  And it<br>
has the advantage of not bringing more or different crypto code into<br>
your application.  Every line of dedicated crypto code in an application<br>
is an opportunity to make a security-critical mistake, so it's best to<br>
minimize.<br>
<br></blockquote><div><br></div><div>As a tedious side note, if you're using a key/pepper, you can avoid worrying about the length of the salt by adding in the sanitised user ID for guaranteed uniqueness. Might be an option if 16 bits is hard to change for some reason.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">But, the dirty dirty truth is that with public implementations of good<br>
crypto algorithms available, key management is by far the hardest part<br>
to get right.  Avoiding the need for key management is why hashing<br>
instead of encryption is preferred for PINs and passwords in the first<br>
place.   If it's out of scope for this project, get someone to sign a<br>
document that says so, because that key has to be present on everything<br>
that can check PINs. Key theft is therefore the most likely way for the<br>
whole thing to fail.<br>
<br></blockquote><div><br></div><div><div>If you haven't already, I'd also check whether the security team didn't mean just encrypting the DB at rest - the stolen backup scenario is a quick win and easy to reason about. An attacker who can execute DB queries can likely replace a hash with their own, and someone who gets hold of the pepper will likely also have any key used for encrypting rows.</div><div><br></div><div>If you do recommend changing the hash, you need to consider the migration path, which either involves cracking everyone's PIN, or wrapping the current hash with another hashing step that introduces the pepper/longer salt. As long as you use a pepper, I'd say it's safe to set the number of rounds relatively low, although you might instead want to match the inner one to avoid making it easy for someone who has the pepper. (I assume your 10s to do a bcrypt was just an example because there's no point burning cycles on a 4-digit PIN - they're not valuable like passwords once cracked.)</div></div><div><br></div><div>This is straying a little from your original question, but my priority for any system like this would be to make sure rate limiting is enforced. If possible, it should be moved to an isolated server which just validates PINs (and resets them with stronger authentication). This server can then do account lockout after a very small number of tries, which would provide a far better payoff than touching the hash. If the system's exposed to the web, add a captcha, rate-limit authentication attempts by IP, and block known IP anonymisation services. If you can, e.g. if the PIN reset process is email-based, just rely on that and stop using PINs altogether.</div><div><br></div><div><br></div><div>Cheers,</div><div>Mark</div></div></div></div>