TweetNaCl secretbox on Workers

Hi, I’m trying to use Tweetnacl in a webpack worker app. My app basically pull the latest encrypted file and key from offsite URLs using fetch, pipes it to the writable part of a TransformStream. The readable part of the TransformStream is returned in a new Response. The code is like this:

function getKey(url){
	return new Promise((resolve, reject) => {
		fetch(url).then(function(response){
			return response.json().then(function(jsonData){
				resolve(jsonData);
			});
		});
	});
}

async function handleRequest(event, request) {
	let {readable,writable} = new TransformStream();
	let key = await getKey("...");
	event.waitUntil(streamAndDecryptFile("...", Uint8Array.from(key.dataKey), writable));
	return new Response(readable, response);
}

async function streamAndDecryptFile(url, key, writable) {
	let writer = writable.getWriter();
	let response = await fetch(url);
	return processChunkedResponse(response, writer, key).then(function(){
		return writer.close();
	});
}


function processChunkedResponse(response, writer, key) {
	var reader = response.body.getReader(); 
	let chunkSize = 65552;
	var databuffer = new Buffer(0);
	return readChunk();

	function readChunk() {
		return reader.read().then(appendChunks);
	}

	function appendChunks(result){
		var data = result.value || new Uint8Array;
		var allData = Buffer.concat([databuffer, Buffer.from(data)]);
		var totalLength = allData.length;
		var remainder = totalLength % chunkSize;
		var cutoff = totalLength - remainder;
		for (var i=0 ; i<cutoff ; i+=chunkSize) {
			var chunk = allData.slice(i, i+chunkSize);
			decryptChunk(chunk);
		}
		databuffer = allData.slice(cutoff, totalLength);
		if(result.done)
		{
			if (databuffer.length > 0) {
				var originalLength = databuffer.length;
				var remaining = new Buffer(chunkSize - databuffer.length);
				remaining.fill(0);
				databuffer = Buffer.concat([ databuffer, remaining ], chunkSize);
				decryptChunk(databuffer, originalLength);
			}
			return Promise.resolve();
		}
		else {
			return readChunk();
		}
	}

	function decryptChunk(result, read = chunkSize) {
		var dataBuff = result || new Buffer(0);
		var data;
		if (read < blockSize)
			data = dataBuff.slice(0, read);
		else
			data = dataBuff;
		var nonce = initialNonce.slice();
		const decryptedSize = calculateDecryptedSize(read) + fileHeaderSize;

		let encryptedOffset = 0;
		let decryptedOffset = 0;
		do {
			const end = encryptedOffset + blockSize;
			const part = data.subarray(encryptedOffset, end);
			let decrypted = secretbox.open(part, nonce, key);
			if (decrypted == null) {
				throw new Error('Could not decrypt data');
			}
			incrementNonce(nonce);
			data.set(decrypted, decryptedOffset);

			decryptedOffset += blockDataSize;
			encryptedOffset = end;

		} while (decryptedOffset < decryptedSize);
		writer.write(data.subarray(0, decryptedSize));
	}
}

I’m using buffer library to use the Buffer class in my code.

The issue that I’m seeing is this:

script exceeded time limit

Uncaught (in response) Error: internal error

Uncaught (async) Error: Promise will never complete.

The last two error show the recursive stacktrace of readChunk and appendChunks.

Are this kind of operations permitted on Cloudflare Workers platform? Is decryption using too much CPU time?

I wanted to add that for files less than 1MB decrypts fine when accessed directly in the browser, but gives the same errors in the Worker devtools window when tried through the “Quick Edit”

Workers can barely load 1MB of parsed JSON into a variable within it’s CPU-limit, I’d be surprised if it can decrypt even 0.5MB of data.