W3C home > Mailing lists > Public > public-webcrypto@w3.org > February 2013

Re: Incomplete blocks

From: Richard Barnes <rbarnes@bbn.com>
Date: Thu, 14 Feb 2013 15:18:30 -0500
Cc: "public-webcrypto@w3.org Group" <public-webcrypto@w3.org>
Message-Id: <2DE26968-CB7B-4773-BFAB-626E7FC02BD3@bbn.com>
To: Ryan Sleevi <sleevi@google.com>
Ok, great.  Thanks, that does clarify things.  I had missed the padding spec in the CBC section. 

However, it seems rather outside the spirit of the low-level API to include padding in the algorithm.  It's necessary in some cases (e.g., RSA signature schemes), but for CBC, it could just as easily be done by the application.

--Richard



On Feb 14, 2013, at 3:07 PM, Ryan Sleevi <sleevi@google.com> wrote:

> On Thu, Feb 14, 2013 at 11:13 AM, Richard Barnes <rbarnes@bbn.com> wrote:
>> Suppose I make the following call:
>> 
>> /* my_iv and my_key pre-defined */
>> var my_pt = new Uint8Array(24);
>> var my_ct;
>> var op = window.crypto.encrypt(
>>    {name: "AES-CBC", params: {iv: my_iv}},
>>    my_key,
>>    my_pt
>> );
>> op.oncomplete = function(e) {
>>    my_ct = e.target.result;
>> }
>> 
>> That is, I've asked the API to encrypt 24 octets -- 1.5 blocks -- of data.  However, CBC only operates on whole blocks (unlike CTR, GCM).  What should then happen?  (Using enc() to represent encryption, and '+' for concatenation)
> 
> Your assumption (that CBC only operates on whole blocks) reflects a
> spec ambiguity - one that was raised in Sept and filed as
> https://www.w3.org/Bugs/Public/show_bug.cgi?id=18953
> 
> This was clarified in https://dvcs.w3.org/hg/webcrypto-api/rev/0c723a7d29b3
> 
>> 
>> 1) Complete, result = enc(my_pt[0:16])
>> 2) Complete, result = enc(my_pt[0:16]) + my_pt[16:]
>> 3) Complete, result = enc(my_pt + padding)
>> 4) Error
> 
> As reflected in https://dvcs.w3.org/hg/webcrypto-api/rev/0c723a7d29b3
> , it would be 3 - because the AES-CBC mode is defined to use
> PKCS#5/PKCS#7 padding.
> 
> I also note that this is related to you using the 'one-shot' form.
> 
> Consider the following:
> 
> var op = window.crypto.encrypt({name: 'AES-CBC', params: {iv: my_iv}}, my_key);
> op.process(new Uint8Array(5));
> op.process(new Uint8Array(19));
> op.process(new Uint8Array(7));
> op.finish();
> 
> For an implementation that supports incremental encryption, the
> expected result would be:
> 
> [op.process(5)]
> [op.process(19)]
> queue an onProgress, with op.result.byteLength == 16 (that is, it
> encrypted the 5 bytes from the first process call and 11 bytes from
> the second process call to yield 16 bytes CT)
> [op.process(7)]
> [op.finish()]
> queue an onProgress, with op.result.byteLength == 32 (that is, 8 bytes
> remaining from the second process call, the 7 bytes from the third
> process call, and 1 byte of padding)
> 
> For an implementation that doesn't support incremental encryption
> [op.process(5)]
> [op.process(19)]
> [op.process(7)]
> [op.finish()]
> onProgress, with op.result.byteLength == 32 (that is, the combined 31
> bytes, plus one byte of padding)
> 
>> 
>> Right now, PolyCrypt does (2), because that's what CryptoJS does if you tell it "no padding"; my development branch does (3).  I'm pretty sure both of these are wrong, and (1) or (4) should be the outcome.
>> 
>> In terms of the spec, I believe this ambiguity relates to 12.1 / Step 2 / Steps 3/6 (in the branches, respectively).
>> 
>> Thoughts?
Received on Thursday, 14 February 2013 20:19:04 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Thursday, 14 February 2013 20:19:04 GMT