🚀 Use streams instead of arraybuffers

This commit is contained in:
C-3PO 2018-07-05 01:58:01 +02:00
parent 27afb62d49
commit d79e7d289c
Signed by: c3po
GPG key ID: 62993C4BB4D86F24
3 changed files with 76 additions and 14 deletions

View file

@ -0,0 +1,25 @@
import updateKeys from './lib/updateKeys';
export default function decryptChunk(encryptedChunk: Buffer, [key0, key1, key2]: [number, number, number]): Buffer {
const dv = new DataView(encryptedChunk.buffer);
const decryptedChunk = new Buffer(encryptedChunk.length);
const dvOut = new DataView(decryptedChunk.buffer);
for (let i = 0; i < length; i += 1) {
//read and decrypt byte
let curChar = dv.getUint8(i);
const keyPart = (key2 | 2) & 0xFFFF;
const decryptedByte = (keyPart * (keyPart ^ 1)) >>> 8;
curChar ^= decryptedByte & 0xFF;
//Skip the first 12 bytes (random encryption header)
if (i >= 12) {
dvOut.setUint8(i - 12, curChar);
}
//update keys
[key0, key1, key2] = updateKeys([key0, key1, key2], curChar);
}
return decryptedChunk;
}

View file

@ -3,6 +3,7 @@
import * as stream from 'stream';
import * as zlib from 'zlib';
import { ISsnFileEntry } from '../interfaces/ISsnFileEntry';
import decryptStream from './streams/decryptStream';
import streamSetMaxLength from './streams/streamSetMaxLength';
/** Extracts the file with the given metadata from the stream.
@ -25,22 +26,28 @@ export default function extractFileStream(file: ISsnFileEntry, inputStream: stre
//skip local file name and extra field
inputStream.read(localFilenameSize + localExtraSize);
//TODO: pipe into decryption if file is encrypted
const decryptTransform = new stream.Transform({
read() {
//...
},
});
inputStream.pipe(decryptTransform);
//-------------------------------------------------
//TODO: pipe into decompression if file is compressed
const decompressTransform = zlib.createInflateRaw();
decryptTransform.pipe(decompressTransform);
let curStream = inputStream;
//TODO: output file
return streamSetMaxLength(decompressTransform, file.size);
//set max length
const maxLength = streamSetMaxLength(curStream, file.compressedSize);
curStream = maxLength;
/*const out = new stream.Readable();
return out;*/
//pipe into decryption if file is encrypted
if (file.decryptionKeys !== undefined) {
const decryptTransform = decryptStream(curStream, file.decryptionKeys);
curStream = decryptTransform;
}
//pipe into decompression
const decompressTransform = zlib.createInflateRaw();
curStream.pipe(decompressTransform);
curStream = decompressTransform;
//set max length
const maxLength2 = streamSetMaxLength(curStream, file.size);
curStream = maxLength2;
return curStream;
}

View file

@ -0,0 +1,30 @@
import * as stream from 'stream';
import decryptChunk from '../decryption/decryptChunk';
export default function decryptStream(inputStream: stream.Readable, decryptionKeys: [number, number, number]): stream.Readable {
let skippedRandomHeader = false;
const outStream = new stream.Readable({
encoding: 'binary',
read(size) {
//There are 12 random bytes at the beginning, we need to use them to initialize the decryption keys, but we can ignore the decrypted bytes.
if (!skippedRandomHeader) {
const encryptedHeader = inputStream.read(12);
decryptChunk(encryptedHeader, decryptionKeys);
skippedRandomHeader = true;
}
//Decrypt chunk
const encryptedChunk = inputStream.read(size);
const decryptedChunk = decryptChunk(encryptedChunk, decryptionKeys);
this.push(decryptedChunk);
},
});
inputStream.on('end', () => {
outStream.emit('end');
});
return outStream;
}