OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

pkcs11 message

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]


Subject: Re: [pkcs11] New Mechanisms subgroup Part 1 or 4 new in v2.3


On 5/1/2013 2:13 PM, Robert Relyea wrote:
On 04/30/2013 05:58 PM, Michael StJohns wrote:


In repeated calls. This removed the worry about what the meaning of the output for the second C_DecryptUpdate() was (no new AAD, use the same AAD?) and how the internal IV changes.
I don't quite understand this. The IV gets set when you do the init. You update the counter for each block and form a new counter block - but that's pretty straight forward. You encrypt that block to get the value you XOR with the cipher text - that's per block processing, and that state happens internal to the module.
The idea here is that each C_EncryptUpdate()/DecryptUpdate() call maps to a complete AEAD block. The issue is there is a single Init call, so you can't supply a new IV and AAD without tweaking things. The advantage of this is if you have a stream of AEAD blocks using the same key, certain key schedule and GCM key precalculations can be cached across Update calls. This could be a win in TLS.

On the balance, the new IV/AAD issue is probably a show stopper here.

Oh - now I understand. That's not how it works. You have to call C_EncryptInit/C_DecryptInit for each complete AEAD message - generally once per packet. This is not a stream cipher where you get to call the Init once and then update for each portion of the communication. It is confusing because the IV and the per-block counter descriptions get confused for each other.

On the other hand, I looked at this because of the per message IV uniqueness requirements and started wondering if perhaps we needed a C_EncryptSessionInit, etc - which wraps around the IV state stuff and manages that and under the covers does the C_EncryptInit/C_Encrypt or C_EncryptUpdate/Final stuff for each message and does the IV formation. The problem there is that while the Appendix A for CCM describes one method of forming the IV from a nonce and format block, it is possible to use other methods. I probably *wouldn't* build C_DecryptSessionInit since you have to process each packet with the IV it contains rather than a strict update of a previous IV.




Similiar argument for C_EncryptInit/C_Encrypt/C_EncryptUpdate. It probably makes sense to do the conservative thing in the spec as well.
I don't quite understand this either. There appears to be no bar in the standard to encrypting and outputting the cipher text prior to outputting the tag. You may have to buffer a partial block, but that's typical.




Oracle implemented the meaning that from C_EncryptInit() to C_EncryptFinal() is a single GCM operation with the MAC returned in final. On Decrypt, C_DecryptUpdate() returns no data and buffers it. C_DecryptFinal() returns the entire decryption.

If the PKCS #11 group wants to allow C_EncryptUpdate/C_DecryptUpdate, then we need to decide which semantic we want and make it explicit in the spec.

I think both are legitimate implementations. I sent a note off to Russ Housley (who designed CCM) and pointed out that both modes were designed for packet use. That suggests that the one-shot model may be most correct. But we may still want to spec this for both modes and allow non-FIPS to use the Update functions.

I'm assuming from your comments that you mean 'both' as in single shot versus multi-shot, not to varying interpretations on what to output in multi-shot (which is what I meant to convey). I'm OK with multi-shot. The 'buffer our decrypt data until you have all of it and return it on C_Finalize' doesn't seem all that useful, but the issue with IV and AAD in the 'each XXXUpdate represents a full GCM block with MAC' makes this one problematic. We implemented just single shot because both interpretations converge to the same thing in the single shot case.
You're using "block" in a confusing manner. Let's keep that term as the cryptographic division for the block cipher - e.g. 16 bytes for AES. Use message or packet to represent the aggregation of the plaintext and AAD that you're actually processing between init and final (or the implicit final).

If you're not in FIPS mode, you can output data (cipher text to plain or vice versa) after every complete block. And you may want to have this option if you don't support buffering of large amounts of data.

If you're in FIPS mode you have to buffer the output of cipher text to plain (but not vice versa) until you verify the tag for the message. You can do this with C_DecryptInit/C_Decrypt or with C_DecryptInit/C_DecryptUpdate*/C_DecryptFinal.

As I said above, this is a message cipher not a stream cipher so you have to re-initialize processing for each message. It's just the way it works.

I corresponded with Russ. He suggested that we should support a double jumbogram - and I assume he means ethernet jumbograms. So that's about 18-20K of required buffering.



----- CCM ---
We did not implement CCM. It would have the same issues. Longer term we may want a new function for IETF AEAD type functions ( see rfc 5166).
In general, this is more about how much data can be/needs to be buffered inside the PKCS11 module than almost anything else. I think the restriction imposed by NIST for this is extreme, especially since the same key can be used with AES-ECB and a set of fabricated counter blocks to do the decryption, even if the CBC-MAC fails.

------ CTR ---
There were no issues with CTR, the spec is pretty straighforward.

------ CTS ---
Just for my ref - this is CBC with Cipher Text Stealing. Your other message on XTS is XEX based cipher text stealing
This is CVS with Cipher Text Stealing.
A few things. First: though it wasn't clear, the only thing that makes sense for the spec is that each C_EncryptUpate call returns CTS data.
If you initially pass in less than or equal to a full block, then you get no output. If you pass in a single block at a time, you will always be one block behind. You have to be past (not at) a block boundary to get output.

No, because the spec specifically says that no data is returned on final. Each C_EncryptUpdate call is a complete CTS 'block'. That is each call has be be at least on block long and the encrypted output is the same as the encrypted input. The 'stealing' happens on each Update call.

That means that each C_EncryptUpdate/C_DecryptUpdate call must have a length > blocksize length. The spec does say that, but in a way that many interpret to mean only C_Encrypt/C_Decrypt (which conflicts with the explicit statement aht C_Finalize doesn't return anything).
You mean C_EncryptFinal? The statement that there is no final part is actually wrong. You can't calculate the last partial partial block unless you know that you're at the end of the data. If you were processing an exact multiple of the block size the output is going to be the last block.
Yes, The spec is correct for what it intended to specify. When I actually implemented this, I actually started implementing what you said, but then I read the input/output spec with the no data on final comment. It became clear CTS was supposed to happen on each update call. This is how CTS is actually used in real life (kerberos sends multiple CTS packets on the same stream with the same key).

Actually, it's worse than this. You end up buffering the last full block and the last partial block, because you return only a part of the encryption for the next to last block if the last block is less than full. You don't know whether you have complete blocks until you call the DecryptFinal. That's at least the case for CBC-CS1-Encrypt

Let's try this:

I'm going to encrypt 40 bytes of data a block at a time.

1) C_EncryptUpdate (16) - position is at 16, output is at 0 - I haven't yet processed enough data to have a valid execution for this mode. 2) C_EncryptUpdate (16) - position is at 32, output is at 0 - I've got valid execution, but I don't know if these are the last two blocks, and in fact the second block I've got buffered is actually the next to last block. 3) C_EncryptUpdate (8) - position is at 40, output is at 16, I've output the first block, buffered the second and the partial data for a total of 24 bytes 4) C_EncryptFinal - output is at 40. I've padded the last block to 16 bytes with zero, done two CBC operations to get the final blocks. I left truncate the next to last block to 8 bytes and output those 8 bytes and the cipher text from the last block for a total of 40 bytes.

It's actually also possible to do the CBC operation everytime you get a complete block and buffer the cipher text of that last block along with any partial plain text you have. In either event you need to buffer at least 32 bytes for this for AES.



You need to buffer up to a block at a time internally. There is no requirement that length>blocksize for each call to C_*Update.

Actually, there is. The spec universally uses 'C_Encrypt' to mean both 'C_Encrypt' and 'C_EncryptUpdate'. That's been a long term source of confusion we should probably fix.
Where do you get that from? I read this (table 44) to say that the input to the mechanism between Init and Final (or the implicit final of C_Encrypt) has to be >= blocksize, not that every call to C_EncryptUpdate needs to be. Regardless, let's assume I process 17 byte chunks - you still have to deal with buffering. It may be that we suggest this mechanism have a processing size constraint of full blocks, but its not there now.


The other issue is an issue with the definition of CTS. The spec simply references NIST SP 800-38A. Unfortunately this spec actually defines 3 different CTS formats:

Type 1, or NIST.
Type 2, or Schneier.
Type 3, or Kerberos.

Spec three modes. Or spec a single mode with a parameter structure which says which of these is in use.

Do you mean three mechanism?
Yes. Sorry.

I'm definitely OK with that.

bob

Mike







---------------------------------------------------------------------
To unsubscribe from this mail list, you must leave the OASIS TC that generates this mail. Follow this link to all your TCs in OASIS at:
https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php





[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]