Subject: Re: Phil Zimmermann's suggestion - Implementation?

From: [email-masked]
Date: Tue, 20 Apr 1999 22:48:34 -0700

I have experimentally implemented the integrated message integrity
check within the encryption/decryption layer.  It is not difficult to
handle the 20-byte trailing hash during decryption.  I use a circular
buffer in which I put the trailing part of each chunk of decrypted data.
It always has the last 20 decrypted bytes in it.  The data is passed
through the hash as we output it from this decryption layer; once we
hit EOF we take the 20 bytes in the buffer and we know those should be
matched against the calculated hash.

I can't speak for other implementations, but I found doing it this way to
be fairly straightforward.  I don't see implementation difficulty as being
a barrier to this approach, or a reason to put the integrity checking
in a pseudo-signature packet.

The problem with doing it in a signature packet is that it is a
fundamentally different function than signatures.  The hash only provides
integrity in the context of an encryption envelope.  Logically the
integrity protection is a property of the encryption layer.  Doing the
hash without encryption provides no integrity protection.  The signature
packet is functionally the wrong place to put it.

Hal Finney
NAI, Inc.

---

From: [email-masked]
Date: Wed, 21 Apr 1999 19:38:20 -0400

> in a pseudo-signature packet.

Implementation difficulty of one thing is not a reason, but I could
probably come up with hundreds of tiny little things to make it better
which would add some value but bloat the code greatly after all were
implemented.  And we should also fix existing implementation/functional
problems such as the lack of a checksum on the new sym-encrypted-sym-key
packets so you have to try each key on the ciphertext. 

You could also create a new packet type, so the EOF would simply signal
that you should look for a(n encrypted) new packet type X with 20 bytes of
contents which is the hash result.

Otherwise, why bother with all this packet nonsense and the CTBs and
whatever in the first place?  You could theoretically not have any of this
and simply search backwards (or include a 2 byte tag) to the beginning of
the first signature packet.

There is a packet infrastructure.  This should be used in one capacity or
another.  I make an exception for header bytes because these are either of
fixed or well defined short lengths.  Tacking things on the end can be
made to work, but it is not a clean way to do things.

We have packets with undefined types which we can add one for this
function.  We also have a predefined packet which is (symmetrically) 
encrypted as part of the existing infrastructure which in normal usage
contains the same data, except in signed form so we call it a signature
packet, but only because it has to this point only contained signatures. 

To repeat: The reason to put integrity checking in a pseudo-signature
packet is because all the necessary code is ALREADY THERE, so instead of
adding a 20 byte delay line you only need a new algorithm ID to identify
this and an IF() test to bypass the signature validation routine.  If
something is already there and easily adapted it is silly to create a new
layer.

Sort of like an old comedy sketch when satellites were first being used
to transmit TV where Mr. Smith was in the kitchen, but they flew him
across the country so he could appear in Mrs. Smith's living room "live
via satellite.  You want to duplicate 70% of the existing signature packet
infrastructure and add a delay line layer because the MDC function is not
a "signature"?  I want to make a 2% change to the existing signature
routines that would accomplish the same function.

How many lines of code did it take for your change?  How much slower?
Remember to add in the hash computation.  And the second hash computation
if there is one if the same packet is going to be signed anyway.

Care to take a stab at adding that function to my opgp and count the lines
as a percentage?

And try my technique and count the impact on the code.  Or find some
reason the function fails to be accomplished by my method.  If you could
argue that it wouldn't work (or work well, or have security problems) I
would say do it your way (except in a unique packet).

> packet is functionally the wrong place to put it.

As I pointed out, the "signature packet" can be called something
different, e.g. "verification packet" or "validation packet".  Had I known
that a MDC feature might be added I would have raised a big stink about
using the word "validation" or "verification" instead of "signature" for
the packet type in the RFC "just in case we want to do something other
than full signatures with it".  What is being asked for is merely a proper
subset of what happens to create the existing packets.

It may be a fundamentally different function, but it happens at exactly
the same point in the implmementation and merely omits one step - the
actual crypto function to validate the signature.  And if you are
encrypting, these packets are encrypted along with the message.

Normal messages are just the encrypted literal packet.  Or encryption
applied to a 1-pass validation (was signature) header, the literal packet,
and the validation packet.  You just have your hash over the V4 hashed
material value in addition to the literal packet. 

Your point about requiring encryption is correct, but you can more easily
have implementations reject unencrypted non-signature validation packets
as providing no information, i.e. only worry about the validation if the
whole came from the encryption.

And are you sure that no one is going to want to add the validation or
other information provided by the subpackets?  (e.g. Date info - you could
also add file permissions, length, etc. to the validation packet
infrastructure, but not to a fixed 20 byte MAC).

---

From: Jon Callas <[email-masked]>
Date: Wed, 21 Apr 1999 17:34:58 -0700

Tom, again -- unless the data is of indefinite-length, you *know* how long
the thing is, and you just subtract 20 from the length you hash. Won't that
work?

And if indefinite length is a problem, we can always say you can't use
indefinite length with a MICed packet. I have no especial love for
indefinite length, and to my mind, it's there to provide TLS-like function,
which is probably better done with TLS. :-)

	Jon

---

From: [email-masked]
Date: Thu, 22 Apr 1999 12:59:45 -0400

> the thing is, and you just subtract 20 from the length you hash. Won't that

Yes, but the specification says that either packet format is valid and
most current implementations use the indefinite length format for any
potentially unknown length stream (e.g. encrypt stdin).

Ask Hal or someone else how easy it would be to make PGP 6.x do definite
length formats by default.

I simply asked if the 20 bytes of hash could be put at the front instead
of the end (a similar problem since if you have to rewind to put the
length in the fields, you could just move a few bytes forward and put the
hash data at the beginning).

In short, if you have definite length packets, there is probably no
penalty for putting the hash at the beginning. 

> which is probably better done with TLS. :-)

I don't like them either, but they are there, and are perfectly valid to
use for any packet and add this given functionality.

If we start to get rid of these, we may as well depricate their use in
future releases.

And why wouldn't a MIC packet work, i.e. why do the 20 bytes have to be
tacked onto the end of the encryption stream without the virtual EOF and
one more packet?

---

From: Werner Koch <[email-masked]>
Date: Thu, 22 Apr 1999 21:38:40 +0200

> I don't like them either, but they are there, and are perfectly valid to

And there are really applications for it:  What about creating a tar
from a large filesystem , encrypt it, put it on tape or CD - Do you
really want to use a temporary file of such a size - only to put the
hash on the front?  I started with GnuPG before I actually knew about
OpenPGP and invented an extension to the v3 format to allow encrypting
and signing of streams.  There are indeed folks who encrypt large
amounts of data and they don't want to waste space for temporary files.
Conclusion: Partial length headers are absolutely needed.

> tacked onto the end of the encryption stream without the virtual EOF and

And why not define that we put n bytes on the end of the encryption
stream and by some lucky coincident these bytes actually look like a
signature/MDC packet ;-)

-- 
Werner Koch at guug.de           www.gnupg.org           keyid 621CC013