0

I'm in node js, trying to compress an object using zlib.deflate and then encrypt it using cryptojs AES.

Then, when I try to get the original value, I fail on the zlib.inflate call with the error: "incorrect header check".

const zlib = require('zlib');
const { AES, enc } = require('crypto-js');

const obj = {
    a: "a",
    b: "b"
};

const inputToDeflate = JSON.stringify(obj);
const compressed = zlib.deflateSync(inputToDeflate);
const encrypted = AES.encrypt(compressed.toString(), 'f11').toString();


const decrypted = AES.decrypt(encrypted, 'f11');
const decompressed = zlib.inflateSync(decrypted.toString(enc.Utf8));
1
  • Compressed data is binary, but Buffer.toString() treats it as UTF8, which destroys much of it, and encrypt by default encodes it as UTF8 which is also harmful (though it could be recovered). Use enc.Latin1.parse(compressed.toString('latin1')). And similarly for the decrypted WordArray use .toString(enc.Latin1). Commented Feb 20, 2022 at 16:46

1 Answer 1

1

I think you're losing zlib header when converting it to string before encryption. We need to change this compressed.toString() some way that the header still preserve inside, something like base64 encoding.

const buffer = Buffer.from(compressed).toString("base64")
const encrypted = AES.encrypt(buffer, 'f11').toString();

Decryption is remind the same, but we need to decode the result back from base64 to original zlib data like before.

const decrypted = AES.decrypt(encrypted, 'f11').toString(enc.Utf8);
const decryptedBuffer = Buffer.from(decrypted,'base64')
const decompressed = zlib.inflateSync(decryptedBuffer);

const resultString = decompressed.toString()

That's it. But I have suggestion here to do encryption part first before compression. Because the result string is different. Take a look in this full code :

Full Code

const zlib = require('zlib');
const { AES, enc } = require('crypto-js');

const obj = {
    a: "a",
    b: "b"
};

const inputToDeflate = JSON.stringify(obj);
const compressed = zlib.deflateSync(inputToDeflate);

// Compact the data to base64
const buffer = Buffer.from(compressed).toString("base64")
const encrypted = AES.encrypt(buffer, 'f11').toString();

console.log("compressed + base64 + encrypted length",encrypted.length)

const decrypted = AES.decrypt(encrypted, 'f11').toString(enc.Utf8);

// Convert the result from base64 to original compressed data
const decryptedBuffer = Buffer.from(decrypted,'base64')
const decompressed = zlib.inflateSync(decryptedBuffer);

// Convert buffer to string
const resultString = decompressed.toString()

// vice versa
console.log(resultString)

Output:

compressed + base64 + encrypted length 88
{"a":"a","b":"b"}

Suggestion

const zlib = require('zlib');
const { AES, enc } = require('crypto-js');

const obj = {
    a: "a",
    b: "b"
};

const inputData = JSON.stringify(obj);
const encrypted = AES.encrypt(inputData, 'f11').toString();
const compressed = zlib.deflateSync(encrypted);

console.log("encrypted + compressed length",encrypted.length)

const decompressed = zlib.inflateSync(compressed);
const decrypted = AES.decrypt(decompressed.toString(), 'f11').toString(enc.Utf8);

console.log(decrypted)

Output:

encrypted + compressed length 64
{"a":"a","b":"b"}

I think it much more efficient to do encryption first and then compression.

Sign up to request clarification or add additional context in comments.

3 Comments

Um, no. Encrypted data can't be compressed. It is a waste of time to attempt to do so. Compress before encryption, when there might be something compressible.
@MarkAdler: in general yes, but cryptojs encryption returns a CipherParams object whose default formatter, used by toString() with no argument, encodes in base64, which of course can be compressed by 25% minus epsilon -- although avoiding the encoding entirely is at least as effective and faster, given binary output is desired or acceptable.
You would still want to compress before encryption. After base64 encoding, if you want the compactness of a binary representation, then it is more efficient and far less time consuming to simply base64 decode it than it would be to compress it. Compression after encryption in that case is just as silly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.