[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20160323043844.GA4472@openwall.com>
Date: Wed, 23 Mar 2016 07:38:44 +0300
From: Solar Designer <solar@...nwall.com>
To: discussions@...sword-hashing.net
Subject: Re: [PHC] hash encryption
On Tue, Mar 22, 2016 at 09:08:41PM -0700, Andy Lutomirski wrote:
> My recollection of the different security properties of different numbers
> of Luby-Rackoff rounds is a bit vague, but they have nothing to do with
> bits of security or work factor. Can you justify them?
I found Thomas Pornin's answer here helpful:
http://crypto.stackexchange.com/questions/1352/are-there-any-specific-requirements-for-the-function-f-in-a-feistel-cipher
Regarding 7 rounds for 256-bit security:
https://www.iacr.org/archive/crypto2003/27290510/27290510.pdf
In other words, 128-bit security for a 256-bit block is what
Luby-Rackoff's usual 3 or 4 rounds provide (it's 4 for chosen ciphertext
attacks, which might or might not be relevant here).
Almost 256-bit security for a 256-bit block is achieved at 7 rounds, as
shown in that other paper above. I did not verify their results.
> IMO the error case should not result in the identity function. Abort or
> memset-to-zero would be better.
For an error case, sure. But this isn't meant to be an error case: it
is how we typically use password hashes now, without encryption.
I could encrypt with the empty key, but there's no security difference
here from not encrypting at all. Zero key length is not the same as a
key that just happens to be all-zero.
I could treat zero key length as an error, but then why not treat low
key length as an error as well? And what's "low"?
> Hashing the key length in before the key would avoid needing to think about
> related-key attacks that might lose you one round or so of security under
> some circumstances. Using a short-key variant as an oracle against a
> long-key variant would be nasty
That's an interesting thought. SHA-256 already hashes in the full
message length in bits, and with only the key being of variable length
here this feels sufficient. Do you think it might not be, and why?
Hashing in the full key length may be tricky to implement because it'd
require converting it to an endianness-independent layout first. I am
trying to avoid cluttering the code with unneeded(?) stuff like this.
Round number was much easier since those numbers are definitely small
enough to fit in 1 byte, and this is a requirement for the Luby-Rackoff
proof (independent functions for each round).
BTW, I am considering changing:
SHA256_Update(&ctx, &round, 1);
to:
{
uint8_t round_bytes[4] = {round};
SHA256_Update(&ctx, round_bytes, sizeof(round_bytes));
}
to ease optimized implementations (so that the key would start at an
aligned boundary, fitting SHA-256's 32-bit words directly). But this
clutters the SHA256_Update()-using code as above. Any thought on that?
Optimize for cleaner code here or for cleaner and shorter optimized code?
This cipher isn't exactly performance-critical here, since it'll
normally correspond to a negligible fraction of the password hashing
time. But it's also 100% overhead, because an offline attacker who has
the key will be able to decrypt the hashes prior to cracking them.
And maybe someone will reuse it elsewhere.
Thank you for the review!
Alexander
Powered by blists - more mailing lists