Peter Gutman wrote on 12/08/2006 01:36:31 AM:
Over the years there have been various papers published on messing with
CBC-
encrypted data to perturb the plaintext in a predictable way. The
OpenPGP
folks addressed this issue fairly quickly by adding an MDC to their
encrypted
content, but S/MIME doesn't address it at all. What makes this issue a
lot
more troublesome is that the public perceives encryption as providing
data
integrity protection, a service it in fact doesn't provide (they also
perceive
signing as providing no data integrity protection, see Garfinkel 2006).
Short
of educating the entire world's email-using population about
cryptographic
security issues, the other possible alternative is to make the
encryption act
in the way they think it acts.
(There are other useful applications of the added MDC as well, e.g. when
wrapping private keys for storage the MDC protects against the
Klima-Rosa
attack, which OpenPGP keys are protected against but S/MIME ones
aren't).
A simple fix for the problem is to add an MDC to EnvelopedData. There
are
alternatives, but none are practical: wrapping the EnvelopedData in
AuthenticatedData collapses under the weight of key management and
implementation issues, using a combined encrypt+authenticate mode is
either
impractical due to patent concerns or has severe implementation problems
because these new modes will take an arbitrarily long amount of timeto
become
widely supported, etc etc.
The MDC approach is a relatively straightforward change that simply runs
a
hash over the ciphertext and attaches the encrypted form of the hash
(using
the content-encryption key used to encrypt the rest of the content) to
the
EnvelopedData as UnprotectedAttributes. So the process becomes:
ciphertext = encrypt( plaintext );
MDC = encrypt( hash( ciphertext ) );
Hmm ... I vaguely recall some problems with using a unkeyed hash, e.g.
SHA-1, to protect integrity. Here's what I can remember at the moment,
sorry if I'm making a mistake.
Presumably encrypt does not protect integrity, so, the attacker may be
able to change ciphertext to ciphertext', and further know that the
corresponding decryption plaintext' has some meaningful relationship to
plaintext. Now the attacker can compute hash(ciphertext') and if the
encrypt function has sufficiently poor integrity, the attacker can use
this knowledge of MDC to compute MDC' = encrypt(hash(ciphertext')).
An example of an encrypt function that is vulnerable to this any stream
cipher, such as RC4. Specifically, let ciphertext' = ciphertext xor delta
= (rc4-stream xor plaintext) xor delta, giving plaintext' = plaintext xor
delta. Now MDC' = MDC xor hash(ciphertext) xor hash(ciphertext').
Even if S/MIME does not allow stream ciphers, they demonstrate that the
construction above presumes that the encrypt function must have some kind
of integrity properties. I'm not sure if AES-CBC, for example, has the
requisite integrity-protection property for the construction above.
An alternative construction may work, though:
MDC = MAC (ciphertext);
where MAC could be HMAC and the key would be the CEK, or a derivative
thereof. Using a MAC in this way has precedent in a scheme like
DHAES/ECIES. The scheme DHAES has a published security proof, so it has,
to a significant extent, precedent in the academic crypto community.
Admittedly, the alternative construction, however, might require more
implementation work than hash based construction, since some S/MIME
implementations may not have code for computing a MAC (unless they
implemented AuthenticatedData). Even so, it doesn't really take too much
work to implement HMAC given a hash function implementation.
Dan Brown
(905) 501-3857
http://www.certicom.com
Hashing the ciphertext protects against other attacks relating to
manipulating
of PKCS #5 padding content. The use of the content-encryption
key/cipher for
the MDC tag avoids key management issues. The OpenPGP folks have been
doing
this for some years now, and it has the approval of the crypto
community.
The only problematic issue is how to indicate the use of the MDC
algorithm.
Some options are:
Use a version number of 5 to indicate (implicitly) the use of a SHA-1
MDC.
Add something to the RecipientInfos as an OtherRecipientInfo that
simply
contains the hash algorithm details.
(As above, but with OriginatorInfos).
The second option is a bit of a kludge, but seems to be the cleanestway
to do
it. The overall changes are very minimal, a new UnprotectedAttribute
type
with the MDC, a new OtherRecipientInfo type, and a bit of code to run a
hash
alongside the en/decrypt. In my trial implementation (excluding the
attribute-handling) there were only about a dozen lines of code required
because the hashing is already performed for SignedData so all it
required was
turning on the hash flag if an MDC was specified in the RecipientInfo.
Is there any support for adding this? I should be able to get a draft
out
fairly quickly, and from a check with two other implementors producing
interoperable implementations should be fairly easy.