[Cryptography] block size / block cipher versus stream cipher

Phillip Hallam-Baker phill at hallambaker.com
Fri Mar 26 11:41:44 EDT 2021


On Thu, Mar 25, 2021 at 5:51 PM Kristian Gjøsteen <kristian.gjosteen at ntnu.no>
wrote:

> 23. mar. 2021 kl. 05:22 skrev jrzx <jrzx at protonmail.ch>:
>
> On Sunday, March 21, 2021 3:49 PM, Kristian Gjøsteen <
> kristian.gjosteen at ntnu.no> wrote:
>
> The block cipher design paradigm has been a roaring success.
> We are in a position where an idiot like me can safely us
> block cipher to design cryptosystems and prove solid>
> theorems about their security.
>
>
> I don't think I am a complete idiot, and it is non trivial for me to
> implement the block cipher paradigm without screwing up.
>
> You wind up doing a lot of clever and complicated things with nonces and
> key scheduling.
>
> Allegedly, a great many people do screw up.
>
>
> Yes, we know. We all know. But you are missing the point.
>
> Block ciphers do not make your implementation job harder, they make it
> easier, because you do not (usually!) have to implement the block cipher.
>
> What makes your implementation job harder is idiots like me designing
> systems. And you know what: Without block ciphers, idiots like me would
> still design systems. And they would be harder to implement correctly. As a
> bonus, they would also be more likely to be insecure **as a design**,
> rendering secure implementation moot.
>
> Block ciphers are great. (Callas mentioned tweakable block ciphers in
> another e-mail; they are double-plus great.)
>

+1

But the real reason I prefer block ciphers over stream ciphers is that
stream ciphers have repeatedly turned out to be brittle. A spec with a
block cipher is usually pretty hard to screw up. A spec with a stream
cipher is difficult to write and difficult to implement.

The fundamental problem is that a stream cipher is implemented by XOR-ing
the plaintext with a cipherstream. And that is fragile because if you have
two ciphertexts enciphered against the same cipherstream, you can XOR them
to get the XOR of the two input ciphers. Ooops.

Another significant issue is in the design of the cipher, the
cipherstream of RC4 was not as unpredictable as people imagined.


Take the design problem I am working on today.

A host accepts UDP requests from multiple clients which MAY change their
Source IP address and port at any time because of NAT deployment. The
source IP is not reliable as a means of matching requests to requestors.
Since we are likely stuck with 64 bit machines for the foreseeable future,
a 64 bit connection identifier is a sufficient alternative. It is highly
unlikely we could ever support even 2^32 connections on a single host.

We are also going to require 16-32 bytes of sequence identifier, stream
identifier, acknowledgement, etc.

So in a plaintext world our packets look like this:

[Source-ID][T-HEAD][Plaintext]

If we want to use a stream cipher to encrypt, we need to do this:

[Source-ID][T-HEAD][Nonce][Ciphertext][Tag]

So what Mallet sees is

[Source-ID][T-HEAD][????][???????????][???]

Quite a bit of data.


With a block cipher, I can play rather more interesting games. If T-HEAD is
unique, I can recycle that to provide my nonce. I can do that with a block
cipher because the criteria is 'almost certain'. With a stream cipher, that
has to be 'absolutely guaranteed'. And that makes a huge difference in both
design and implementation. If Ethernet packets were a sensible 64KB, I
wouldn't mind about losing the 16 bytes. But when we are limited to 1260
bytes, I care. A LOT.

But wait, there is more, with a block cipher I can encrypt those initial
T-HEAD bytes. Why give anything away to the opposition? Let k0 be a key
that is established at session start and is constant for the lifetime of
the session and kn be a key that is formed using a KMAC on the sequence
info in T-HEAD and the key agreement data:

[Source-ID][E(T-HEAD, k0)][E(Plaintext,kn)][Tag]

So what Mallet sees using FRED transport and security is:

[Source-ID][??????????????????]

That Source-ID is irritating the heck outta me. It has to be the same every
time for the demultiplex to work. Or does it.

Lets make Source-id a full encryption block, for the sake of argument 128
bits. This will cost me 8 bytes.

Each time the Host sends out a response packet, it contains a series of
encrypted Source-ID tags. These consist of

[Source-ID][Sequence][State]

The entire tag is encrypted under a static key known only to the host.
These are in effect a form of cookie or Kerberos token. When the server
receives a request, it simply decrypts the first 16 bytes and it gets back
the Source-ID.

So now what Mallet sees is

[??????????????????]
[??????????????????]
[??????????????????]
[??????????????????]

All I am leaving Mallet at this point is packet timing data. Every packet
is padded out to the same number of bytes. Mallet can guess I am using
OCB-AES and thus identify the different packet components, but that is all.
I probably wouldn't use this approach everywhere, but it certainly makes a
lot of sense in TOR type situations.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.metzdowd.com/pipermail/cryptography/attachments/20210326/e755c4c0/attachment.htm>


More information about the cryptography mailing list