AES-GCM: obtain intermediate tag/MAC or continue after doFinal() without counter reset

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

AES-GCM: obtain intermediate tag/MAC or continue after doFinal() without counter reset

Andrey Gursky
Hi,

I'm considering AES-GCM decryption on the fly "lite" (without new keys
and reinitialization). The goal is to be able to decrypt and verify not
the whole big message after complete reception (over e.g. TCP), but
instead smaller pieces (e.g. 64 KBytes) one at time with the same key
(and iv which is implicitly not the same due to the counter
auto-increment).

It seems to me the following simplified usage case consists of avoidable
operations (since counter could be kept incremented and tag could be
computed for completed blocks)

new key;
tcp.send(encryptedKey);
while (bufLen > 0) {
    init(key, new iv);
    processBytes(64K of bufLeft);
    encryptedWithTag = doFinal();
    tcp.send(iv);
    tcp.send(encryptedWithTag);
    bufLeft -= 64K;
}

and could be replaced by:

init(new key, new iv);
tcp.send(encryptedKey);
tcp.send(iv);
while (bufLen > 0) {
    processBytes(64K of bufLen);
    encryptedWithTag = doFinal(); // or doIntermediate() ?
    tcp.send(encryptedWithTag);
    bufLen -= 64K;
}

This doesn't work for me now. I believe it is due to the counter reset
to the initial IV value, what I'm trying to avoid (in secure way):

core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java

    init() {
        nonce = IV;
        J0 = f(nonce);
    }
    doFinal() {
        reset(false);
    }
    reset() {
        counter = Arrays.clone(J0);
    }

Similar approach seems to work with libcrypto++ [1].

Maybe it can be done with some other Java API, I haven't noticed yet?
Or if not, could this be improved? What is a cipher object useful for
after doFinal() now (since key and initial iv are preserved, starting
another encryption with this object is not secure, isn't it)? Wouldn't
it be more useful without resetting the counter?

Thanks,
Andrey

[1] Multiple messages with AES-GCM and nonce resynchronize
    https://www.mail-archive.com/cryptopp-users@.../msg08293.html

Reply | Threaded
Open this post in threaded view
|

Re: [BUG] AES-GCM: obtain intermediate tag/MAC or continue after doFinal() without counter reset

Andrey Gursky
On Tue, 3 Jan 2017 03:02:02 +0100 Andrey Gursky wrote:

> Hi,
>
> I'm considering AES-GCM decryption on the fly "lite" (without new keys
> and reinitialization). The goal is to be able to decrypt and verify not
> the whole big message after complete reception (over e.g. TCP), but
> instead smaller pieces (e.g. 64 KBytes) one at time with the same key
> (and iv which is implicitly not the same due to the counter
> auto-increment).
>
> It seems to me the following simplified usage case consists of avoidable
> operations (since counter could be kept incremented and tag could be
> computed for completed blocks)
>
> new key;
> tcp.send(encryptedKey);
> while (bufLeft > 0) {
>     init(key, new iv);
>     processBytes(64K of bufLeft);
>     encryptedWithTag = doFinal();
>     tcp.send(iv);
>     tcp.send(encryptedWithTag);
>     bufLeft -= 64K;
> }
>
> and could be replaced by:
>
> init(new key, new iv);
> tcp.send(encryptedKey);
> tcp.send(iv);
> while (bufLeft > 0) {
>     processBytes(64K of bufLeft);
>     encryptedWithTag = doFinal(); // or doIntermediate() ?
>     tcp.send(encryptedWithTag);
>     bufLeft -= 64K;
> }
>
> This doesn't work for me now. I believe it is due to the counter reset
> to the initial IV value, what I'm trying to avoid (in secure way):
>
> core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
>
>     init() {
>         nonce = IV;
>         J0 = f(nonce);
>     }
>     doFinal() {
>         reset(false);
>     }
>     reset() {
>         counter = Arrays.clone(J0);
>     }
>
> Similar approach seems to work with libcrypto++ [1].
>
> Maybe it can be done with some other Java API, I haven't noticed yet?
> Or if not, could this be improved? What is a cipher object useful for
> after doFinal() now (since key and initial iv are preserved, starting
> another encryption with this object is not secure, isn't it)? Wouldn't
> it be more useful without resetting the counter?
>
> Thanks,
> Andrey
>
> [1] Multiple messages with AES-GCM and nonce resynchronize
>     https://www.mail-archive.com/cryptopp-users@.../msg08293.html

Ping. Any suggestions?

jce/src/main/java/javax/crypto/Cipher.java:
>     * A call to this method resets this cipher object to the state
>     * it was in when previously initialized via a call to <code>init</code>.
>     * That is, the object is reset and available to encrypt or decrypt
>     * (depending on the operation mode that was specified in the call to
>     * <code>init</code>) more data.
> ...
>    public final byte[] doFinal()

For me it looks like you make it very easy for a user to misuse the
cypher object after doFinal(), which would result in unsecure
encryption. Despite of "depending on..." there is no check, that the
particular KEY/IV pair have been just used for encryption and thus the
object MUST NOT be used as is without setting new IV.

BUG: Missing exception in this case.

By not resetting the counter, you give a chance for users to continue
using the cypher object in a secure way until very much data had been
transmitted (counter overflow). This seems to me a much better
solution. The currently one allows easy to introduce a security bug,
which makes the encryption useless. If I have missed something
important, please let me know.

I'm using libbcprov-java 1.55 from Debian Testing. Now after looking
into git, I've found "changed GCMBlockCipher to reject trivial attempts
to reuse nonce." (237981204608c61ef2298a06588a975d292232bd)
and a new comment:
core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
>        // note: we do not reset the nonce.

So now it seems the object couldn't be reused, and there is no bug
anymore. But then there is another bug: the object becomes useless
for encryption after doFinal(), doesn't it?

David, could you tell me please, why wouldn't you reset the nonce? And
have you considered to not reset the counter?

Regards,
Andrey

Reply | Threaded
Open this post in threaded view
|

Re: [BUG] AES-GCM: obtain intermediate tag/MAC or continue after doFinal() without counter reset

David Hook

BC allows for the reuse of the key - you can pass null in the
lightweight API or RepeatedKeySpec for the JCE. Using that will remove
the overhead of setting up the key schedule. You would still need to
update the nonce (use 16 bytes, increment it per message of 64K to
manage your message level of counter). I would not advise tampering with
the algorithm further.

Regards,

David

On 12/01/17 10:11, Andrey Gursky wrote:

> On Tue, 3 Jan 2017 03:02:02 +0100 Andrey Gursky wrote:
>
>> Hi,
>>
>> I'm considering AES-GCM decryption on the fly "lite" (without new keys
>> and reinitialization). The goal is to be able to decrypt and verify not
>> the whole big message after complete reception (over e.g. TCP), but
>> instead smaller pieces (e.g. 64 KBytes) one at time with the same key
>> (and iv which is implicitly not the same due to the counter
>> auto-increment).
>>
>> It seems to me the following simplified usage case consists of avoidable
>> operations (since counter could be kept incremented and tag could be
>> computed for completed blocks)
>>
>> new key;
>> tcp.send(encryptedKey);
>> while (bufLeft > 0) {
>>     init(key, new iv);
>>     processBytes(64K of bufLeft);
>>     encryptedWithTag = doFinal();
>>     tcp.send(iv);
>>     tcp.send(encryptedWithTag);
>>     bufLeft -= 64K;
>> }
>>
>> and could be replaced by:
>>
>> init(new key, new iv);
>> tcp.send(encryptedKey);
>> tcp.send(iv);
>> while (bufLeft > 0) {
>>     processBytes(64K of bufLeft);
>>     encryptedWithTag = doFinal(); // or doIntermediate() ?
>>     tcp.send(encryptedWithTag);
>>     bufLeft -= 64K;
>> }
>>
>> This doesn't work for me now. I believe it is due to the counter reset
>> to the initial IV value, what I'm trying to avoid (in secure way):
>>
>> core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
>>
>>     init() {
>>         nonce = IV;
>>         J0 = f(nonce);
>>     }
>>     doFinal() {
>>         reset(false);
>>     }
>>     reset() {
>>         counter = Arrays.clone(J0);
>>     }
>>
>> Similar approach seems to work with libcrypto++ [1].
>>
>> Maybe it can be done with some other Java API, I haven't noticed yet?
>> Or if not, could this be improved? What is a cipher object useful for
>> after doFinal() now (since key and initial iv are preserved, starting
>> another encryption with this object is not secure, isn't it)? Wouldn't
>> it be more useful without resetting the counter?
>>
>> Thanks,
>> Andrey
>>
>> [1] Multiple messages with AES-GCM and nonce resynchronize
>>     https://www.mail-archive.com/cryptopp-users@.../msg08293.html
> Ping. Any suggestions?
>
> jce/src/main/java/javax/crypto/Cipher.java:
>>     * A call to this method resets this cipher object to the state
>>     * it was in when previously initialized via a call to <code>init</code>.
>>     * That is, the object is reset and available to encrypt or decrypt
>>     * (depending on the operation mode that was specified in the call to
>>     * <code>init</code>) more data.
>> ...
>>    public final byte[] doFinal()
> For me it looks like you make it very easy for a user to misuse the
> cypher object after doFinal(), which would result in unsecure
> encryption. Despite of "depending on..." there is no check, that the
> particular KEY/IV pair have been just used for encryption and thus the
> object MUST NOT be used as is without setting new IV.
>
> BUG: Missing exception in this case.
>
> By not resetting the counter, you give a chance for users to continue
> using the cypher object in a secure way until very much data had been
> transmitted (counter overflow). This seems to me a much better
> solution. The currently one allows easy to introduce a security bug,
> which makes the encryption useless. If I have missed something
> important, please let me know.
>
> I'm using libbcprov-java 1.55 from Debian Testing. Now after looking
> into git, I've found "changed GCMBlockCipher to reject trivial attempts
> to reuse nonce." (237981204608c61ef2298a06588a975d292232bd)
> and a new comment:
> core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
>>        // note: we do not reset the nonce.
> So now it seems the object couldn't be reused, and there is no bug
> anymore. But then there is another bug: the object becomes useless
> for encryption after doFinal(), doesn't it?
>
> David, could you tell me please, why wouldn't you reset the nonce? And
> have you considered to not reset the counter?
>
> Regards,
> Andrey
>