Dmitry Eremin-Solenikov dbaryshkov@gmail.com writes:
I see three reasonable approaches:
Support only segments matching the block size (i.e., CFB128 for a 16-octet block size), no partial segments.
Allow a partial segment, and encrypt it in the same way as if it had been padded to a block boundary with arbitrary data. Then the output iv is the complete output block from the block cipher.
Apply the small-segment formula for iv update,
Ij = LSB_{b-s}(I{j-1]) | C_{j -1}
The way I think about that is that we construct a key-stream sequence to be xor:ed to the plain text. And the output iv is then always the last 16 bytes of that sequence.
I got this wrong, the output iv, by that rule, is the last 16 bytes of *ciphertext*, not of the key stream. Which, as you say, is why encrypt and decrypt differ.
And then for option (2), we'd have to pretend some particular padding of the partial segment, e.g., padding with zeros.
To me, (1) is easiest, I'm not sure if there are any clear use cases for partial segments. And it can easily be extended later.
GOST uses partial last segment when doing PBES2 encryption.
Does it depend on the output iv, or does it explicitly set a new iv for the next message?
I'm looking at Nettle docs for CTR, it doesn't say what happens to the iv/ctr if you encrypt one message with a partial block last, and then another message, without manually setting the counter in between. It just says that all but the last call must use a length that is a multiple of the block size.
The implementation simply increments the counter by one also after the partial block, and discards the left-over of the key stream. While I guess an application might expect it to work like a stream cipher and buffer the left-over key stream.
So we also have the option
4. Leave unspecified what happens to the iv after processing a partial segment. And require the application to explicitly set a new iv for each message if it needs to encrypt several messages with partial last segment.
(2) is analogous to how Nettle does CTR mode. But for CFB it seems a bit non-standard, I'd rather not do that unless there's some important protocol or application which uses CFB in this way, and includes some test vectors.
(3) is a bit more work. It's reasonably easy to document, and it has the advantage, that it gives us small-segment support for free, and it can be tested to some degree using CFB8 test vectors.
What do you think? If I understood your code correctly, it does neither (2) or (3).
I have no strong preference here. I updated last IV in a way that application can (manually, of course) resync to the stream in case it would like continue processing data after processing last (incomplete) segment.
I lean towards (3), which would mean always updating the iv so that it's the most recent block_size octets of the cipher text. As far as I understand, that would almost for free bring support for a sequences with arbitrary fixed segment size according to the specification, as well as non-standard mixing of segments of different sizes (not sure if that makes any cryptographic sense; but I see no obvious way why that would break).
But I'd like to hear opinions from additional people, what do others think?
Yes, the feedback of ciphertext. You were probably thinking about OFB, where encrypted IV is fed back, rather than whole ciphertext.
You're right, I misread the iv update rules.
BTW: do you want CFB8 mode implemented or I can drop it back from next version of patchset?
You can drop the separate CFB8 functions for now.
Regards, /Niels