Skip to content
This repository has been archived by the owner on Feb 7, 2023. It is now read-only.

AES_GCM_Decrypt_process #170

Open
Khivar opened this issue Feb 22, 2019 · 1 comment
Open

AES_GCM_Decrypt_process #170

Khivar opened this issue Feb 22, 2019 · 1 comment

Comments

@Khivar
Copy link

Khivar commented Feb 22, 2019

There is an issue while decrypting multiple chunks :

const decryptor = new asmCrypto.AES_GCM(new Uint8Array(aesKey), new Uint8Array(iv), new Uint8Array(tag), tagLength/8);

const buffer1 = decryptor.AES_GCM_Decrypt_process(new Uint8Array(encrypted.buffer, 0, 512));
const buffer2 = decryptor.AES_GCM_Decrypt_process(new Uint8Array(encrypted.buffer, buffer1.byteLength, 512));

const buffer3 = new ArrayBuffer(buffer1.byteLength + buffer2.byteLength);
const result = new Uint8Array(buffer3);
result.set(new Uint8Array(buffer1))
result.set(new Uint8Array(buffer2), buffer1.byteLength);
const buffer = result.buffer;

First of all, the buffer1 contains 496 bytes and buffer2 contains 512 bytes. So the resulting buffer contains 1008 bytes. When I check against the original decrypted data, the first 512 bytes are correct but after that everything differs.

So it seems to stash the 16 last bytes on the first call in order to use it as the tag on the upcoming AES_GCM_Decrypt_finish call but since i don't call it right away and instead call AES_GCM_Decrypt_process again, it correctly destash those bytes and process them (hence the first 512 correct bytes in the resulting buffer and not just 496 correct bytes) and again the last 16 bytes must be stashed so only 1008 bytes total instead of 1024, which seems perfectly normal.

Since it works when calling AES_GCM_Decrypt_process with all the data at once followed by AES_GCM_Decrypt_finish, I guess the issue lies in the code that is executed after the processing of a destashed potential tag, which is the case from the second and all subsequent calls to AES_GCM_Decrypt_process.

@Khivar
Copy link
Author

Khivar commented Feb 22, 2019

Trying to make it work, I added a parameter to AES_GCM_Decrypt_process : containsTag.

ES5 code :

AES_GCM.prototype.AES_GCM_Decrypt_process = function (data) {
    var containsTag = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
    var dpos = 0;
    var dlen = data.length || 0;
    var asm = this.aes.asm;
    var heap = this.aes.heap;
    var counter = this.counter;
    var tagSize = this.tagSize;
    var pos = this.aes.pos;
    var len = this.aes.len;
    var rpos = 0;
    if (containsTag) {
      var rlen = len + dlen > tagSize ? (len + dlen - tagSize) & -16 : 0;
    }
    else {
      var rlen = len + dlen > tagSize ? dlen : 0;
    }
    var tlen = len + dlen - rlen;
    var wlen = 0;
    if (((counter - 1) << 4) + len + dlen > _AES_GCM_data_maxLength)
        throw new RangeError('counter overflow');
    var result = new Uint8Array(rlen);
    while (dlen > tlen) {
        wlen = _heap_write(heap, pos + len, data, dpos, dlen - tlen);
        len += wlen;
        dpos += wlen;
        dlen -= wlen;
        wlen = asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA + pos, wlen);
        wlen = asm.cipher(AES_asm.DEC.CTR, AES_asm.HEAP_DATA + pos, wlen);
        if (wlen)
            result.set(heap.subarray(pos, pos + wlen), rpos);
        counter += wlen >>> 4;
        rpos += wlen;
        pos = 0;
        len = 0;
    }
    if (dlen > 0) {
        len += _heap_write(heap, 0, data, dpos, dlen);
    }
    this.counter = counter;
    this.aes.pos = pos;
    this.aes.len = len;
    return result;
};

I call it by passing false to containsTag and switching it to true when i call it on the last chunk which contains the tag. With that change It now decrypts my files correctly.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant