lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Message-ID: <55F6F037.2040106@devever.net> Date: Mon, 14 Sep 2015 17:05:11 +0100 From: Hugo Landau <hlandau@...ever.net> To: discussions@...sword-hashing.net Subject: Re: [PHC] Specification of a modular crypt format > -- A similar format should exist, that contains everything except the > hash output. This is for compatibility with the Unix crypt() API. Let's > call "salt string" the string without the hash output, and "hash string" > the string with the hash output. This is good, but I'd repeat this for configuration. It should be possible to create a string free of both salt and hash. This could be used for passing around configuration parameters in some circumstances. Basically the idea, which seems to be quite universally adopted, is that the fields are in the order of ident-config-salt-hash, i.e. from most general to most specific. > $<id>$[<param>=<value>(,<param>=<value>)*$]<salt>[$<hash>] I gather this is coming from sha256/512-crypt's $rounds=...$ syntax, but I'm not convinced it's warranted. The need for key-value extensibility for password hashing functions is, presumably, nil, especially given that no fields are now optional. This brings in unnecessary complexity (and thus the increased chances that people will mess up implementations). $<id>$<arg>$<arg2>$...$<argN>$<salt>$<hash> is simpler to deal with, though I suppose $<id>$<arg>,<arg2>,...,<argN>$<salt>$<hash> would also suffice if it's desirable to limit the parameters to one field for some reason. I also think parameter values can be limited to non-negative integers at this time, unless you are aware of any password hashing schemes which would be incompatible with this. This has the advantage that the grammar of integers can be integrated into the definition, thus making the determinism of the encoding formal. Here's my proposed grammar in ABNF: hash-string = salt-string '$' hash salt-string = config-string '$' salt config-string = '$' scheme-identifier '$' scheme-specific-options scheme-identifier = 1*(ALPHA / DIGIT / '-') hash = base64-string salt = base64-string ; N is determined by scheme scheme-specific-options = N*N(scheme-option '$') scheme-option = integer integer = '0' / (NZDIGIT *DIGIT) base64-string = *(ALPHA / DIGIT / '.' / '/') NZDIGIT = %x31-39 >I am not using standard Base64 (RFC 4648) for encoding of binary strings, but the "traditional" variant which is already used in some existing hash strings, for the following reasons: I'm not convinced by this rationale. Firstly, I'm not aware of any base64 functionality provided by programming language standard libraries which does line wrapping, etc. The world seems to agree that 'base64' has come to mean a certain thing, distinct from 'PEM base64' etc. While it's true that RFC 4648 base64 generates padding, this can easily be stripped. So this doesn't seem like a justification for using a different 'alphabet' (and IIRC endianness of encoding). In other words, this would be a gratuitous difference almost for the sake of incompatibility. It seems like an overreaction to use something very different because the more common choice is slightly off (but easily rectified). While it's true that existing crypt() implementations and their base64 implementation is widespread, RFC 4648 base64 is more prevalent still. And consider that the most pressing case for modern password hashing is probably not in /etc/shadow, but in the user databases of large, popular websites. Developers in this circumstance (or, preferably, people developing password hashing libraries) will have RFC 4648 base64 libraries available to them, but if they have to use crypt() base64 they may have to implement it themselves, which creates the risk that they will implement it in a subtly buggy or broken fashion. I say this from experience; I implemented sha512-crypt in Go, and had to implement crypt() base64. Whereas if it had used RFC 4648 base64 existing base64 libraries could have been reused. Not really a problem, but it feels like an unnecessary liability.
Powered by blists - more mailing lists