Dmitry Eremin-Solenikov dbaryshkov@gmail.com writes:
2017-10-03 23:04 GMT+03:00 Niels Möller nisse@lysator.liu.se:
What about message sizes which aren't a multiple of the block size? As I understood your code, it would be possible to call cfb_encrypt with an input lenght of, e.g., 19 octets, which would be processed as one CFB128 segment and one CFB24 segment. Which is a mix of different segment lengths. That's why it seemed natural to me to generalize to any mix of segment lengths. Am I missing something?
No, it is still CFB128, but with last segment being of partial size. SP800-38A supports that kind of operation (segments + partial one).
I've had another read of SP800-38A, section 6.3. It says "The CFB mode also requires an integer parameter, denoted s, such that 1 <= s <= b. In the specification of the CFB mode below, each plaintext segment (P j) and ciphertext segment (C j) consists of s bits.". So no partial segments, and I see no support for that in the section on padding either.
Now, the ciphertext for a partial segment is no problem, I see only one reasonable way to define that. Question is, what the output iv should be? E.g, if you want to set an initial iv, encrypt two 19-octet messages, with the output iv after the first message be the input iv for the second. I haven't seen neither a spec or a testcase for that, do you know any?
I see three reasonable approaches:
1. Support only segments matching the block size (i.e., CFB128 for a 16-octet block size), no partial segments.
2. 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.
3. 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.
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. (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).
And one other unrelated question: Isn't encrypt and decrypt identical for CFB? We xor a keystream to the message to encrypt or decrypt. And the key stream is defined by the cipher, key and segment size (or sequence of segment sizes, in case we support mixing sizes), regardless if we're going to use it for encrypt or decrypt. Or is there something subtle I'm missing?
Regards, /Niels