5

In Unix crypt using SHA-256 and SHA-512 the author, Ulrich Drepper, introduces the SALT string as the following (highlight by me):

For the SHA-based methods the SALT string can be a simple string of which up to 16 characters are used.

What is the rationale calling this string a simple string? What does it mean? What are the consequences? I'm especially interested in the edge-cases of providing a string of 16 NUL bytes for example.

hakre
  • 189
  • 1
  • 5
  • There should be no problem with null chars in the salt; however say `\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0` is a perfectly fine salt; however to be an effective salt it should only be used once (or else its not really salting the password and all hashes can be attacked in parallel). – dr jimbob Jul 23 '13 at 19:57
  • @drjimbob: When I test with such a string, for example with PHP's `crypt()` for SHA-256/512, it's cutted-off before the first NUL byte. AFAIK PHP devs have ported Dreppers code, so the perfectly fine salt you have does effectively not work. I'm trying to find out if it *should* work or not by the specs given. – hakre Jul 23 '13 at 20:15

2 Answers2

3

The text means "simple" by opposition to what was used in the older traditional DES-based crypt() where the salt was a 12-bit value, represented as exactly two characters in a restricted set. Ulrich Drepper wants to say that his creation is less picky and can take as salt any sequence of up to 16 bytes.

Though the hashing function itself can work with any bytes (including zeros, which are not special in any way for a hash function), the C code shown in the text you link to uses a string-based API:

char *
sha256_crypt (const char *key, const char *salt)

i.e. the salt will stop just before the first byte of value zero, or just after the 16th byte, whichever comes first. Moreover, the value of the salt will be part of the produced output string, so the salt had better consist in printable ASCII characters and not include the '$' sign, since that's what is used as separator within that string.

A simple way to generate a "proper salt string" for this function is to generate a sequence of exactly 12 random bytes (taken from a good PRNG, i.e. /dev/urandom), and encode them with Base64. This will yield 16 random characters, in an alphabet containing letters (uppercase and lowercase), digits, '+' and '/' -- and none other, in particular no '$' and no troublesome control character. The salt will still have 96 bits of entropy, making salt reuse considerably improbable (so things will be fine).

Tom Leek
  • 168,808
  • 28
  • 337
  • 475
  • So effectively when a salt is generated, the NUL byte can not be part of it and `$` makes no sense, too, because otherwise it wouldn't be properly recognized later on. So this does not require to encode as base64 (which is done on others AFAIK), but to just encode "base254" and exclude `\NUL` and `$` from the alphabet, right? – hakre Jul 23 '13 at 20:12
  • Apparently... but the produced string will probably be used in other contexts, e.g. stored in an `/etc/passwd` or `/etc/shadow` file which can have its own additional constraints (e.g. no `':'`). There are three levels: the abstract function (which accepts any byte value), the sample implementation (which does not tolerate zeros and `'$'`), and "other users" who can be more picky. Sticking to Base64 should be safe for all three levels. The whole thing is not as well specified as it should. – Tom Leek Jul 23 '13 at 20:26
1

In this context a simple string is any character array in C for example: char[]. The code is performing a strlen() so it is null terminated. A salt should be a cryptographic nonce.

rook
  • 46,916
  • 10
  • 92
  • 181
  • Dreppers code is using `strlen` which - when I look that up for C - is documented to terminate strings at NUL byte. So isn't that conflicting to your answer? Am I missing something? – hakre Jul 23 '13 at 20:18
  • @hakre Cool, you answered your own question. – rook Jul 23 '13 at 20:26
  • Which implication in context of the question has *"A salt should be a cryptographic nonce."*? Everything *should* be something (for some use), however is it here? E.g. is base64 okay? (and most often in the end we always answer our own questions, that's why we ask them, aren't we?) – hakre Jul 23 '13 at 20:42
  • @hakre well hopefully you are generating a cryptographic nonce as a salt, i have no idea how you are calling this function so I couldn't tell you if it is or is not. base64 would be a waste of space as you are not using a full byte. – rook Jul 23 '13 at 20:50
  • Yes base64 reduces the space. I think I'll stick with "base254" for the moment. The source of random should by cryptographically secure (have not reviewed the code fully but I *know* the author is aware of that). As the random source is returning 256 bits I need to reduce that down to 254 bits *whithout* loosing randomness here. I think I pick the method from solar designer as outlined in phpass and adopt it to 254 bits - if possible. Will chew on this a bit. Thanks for your feedback. – hakre Jul 23 '13 at 21:09