Jeffrey Goldberg <
jeffre...@goldmark.org> wrote:
>On 12-06-08 10:21 AM, kg wrote:
>> Jeffrey Goldberg <
jeffre...@goldmark.org> wrote:
>>> I am talking about
>>> implementation errors, but they can be my own (for example, expecting a
>>> different padding scheme then the one used to encrypt the data). I'm
>>> just talking about cautious programming and not something that is more
>>> directly part of the security of the scheme.
>>
>> Such mistakes could give the adversary unexpected oracles.
>
>Yep. That's why I said "directly". I do want to avoid such mistakes.
>>
>
>> Sometimes, you can design defensively by including information about the
>> cryptosystem in use when doing key derivation (this is fairly cheap). If
>> you mess up and encrypt with one system (say CBC + HMAC) and decrypt
>> with something else (CTR + HMAC), the keys you use won't match and the
>> ciphertext will be rejected.
>
>That's interesting. But I'd like to keep things nice and modular. I'm
>not sure that I want to build something like that into key derivation.
>
>It the moment I'm trying to work out a format that is roughly
>
> header || ciphertext || authenticated-plaintext || tag
Ah. Encrypt-then-MAC is straight-forward. Adding authenticated-only data
is often tricky, as you have found out.
Basically, to encrypt authenticated-only data adata and confidential
data cdata with encryption key k1 and MAC key k2, it should be safe to
do something like:
c0 = Enc(k1, cdata)
tag = MAC(k2, length(adata) || adata || cdata)
c = length(adata) || adata || c0 || tag
The MAC tag ensures that the decryptor knows the string
length(adata) || adata | c0
and it is exactly as constructed. A sane encoding of length(adata) allows
the decryptor to correctly split the string into adata and c0 pieces,
after which c0 can safely be decrypted.
>The header will contain
>
> fixed-label || version || length-of-cdata || length-of-adata ||
>length-of-tag
I'd put version information etc. into adata. If you cannot guarantee that
your keys are only used properly, I'd adapt key generation. I've tried a
few tricks such as putting version information into the tag generation,
but I can always find ways to screw up.
E.g.: One could replace MAC by
MAC'(k2, txt) = MAC(k2, version || txt) ,
but if one version is a prefix of another version, it is possible to
mess up.
Using
MAC'(k2, txt) = MAC(KDF(k2, version), txt)
seems more difficult to break for most reasonable KDF functions.
>The reason that I'm regretting the 256 bit AES keys is that we have a
>unique random key for each item which is encrypted with a master key.
This is an engineering question (which I am not good at, presumably you
are): You have a database of ciphertexts ci = Enc(master-key, ki). Would
it work if you had a database of salts si and defined ki = KDF(master-key,
salt || other-data)? (If your ciphertexts are integrity-protected,
so should the salts be.)
From a security point of view, these two solutions seem more or less
equivalent.
--
kg