node.jsaesencryption-symmetricaescryptoserviceprovider

nodejs aes256 encrypt is different from online aes256 encryption tool


I encrypted word HelloWorld using nodejs-aes256 https://www.npmjs.com/package/nodejs-aes256 with key apple the output was 1ivBqj+nVPcHvZjQlx7Di0SoxV49bNpWtog= then I encrypted same word with same key using online tool http://aesencryption.net/ the output was LIxrc1buLeLLr9nJxtPhjHSYFVaceqsXiFamWiVWzYI=

Whey are they different?


Solution

  • First, "apple" can't be a key for AES-256. It's not long enough. An AES-256 key has to be exactly 256 bits (32 bytes). "apple" is, in the likely ways of encoding it, 5. So there's already a problem here. The systems may be padding it out with zeros for you, but you can't rely on that. This isn't what AES keys should look like anyway; they need to be 32 "effectively random" bytes; "apple" is not "effectively random."

    The nodejs package indicates that it generates a random IV. That likely means it also encodes the random IV in the output and expects it in the input, and sure enough that's what we see in the code:

    ciphertext = Buffer.concat([iv, ciphertext, cipher.final()]);
    

    Assuming that the source code below the PHP page is actually related to the tool, then they've called this:

    $this->setIV("");
    

    which probably translates somewhere into 16 bytes of zeros (which is a very insecure IV).

    The shorter answer is that there is absolutely no standard for applying AES or encoding the output. The vast majority of implementations you find (including these two) are very insecure because they assume you know how to add all the pieces they're missing. For example, both of these implementations need an HMAC, since they used CBC mode, but neither includes one, and if you want to hand a string like "apple" as the password, you need a key derivation function like PBKDF2 to convert it to a key. (This is how you convert a string like "apple" into something "effectively random.") Any secure implementation will be incompatible with any other secure implementation. There just isn't a widely used standard format that is also secure.

    All that said, a secure format should always cause two encryptions to have different resulting cipher texts. The nodejs package does this correctly by including a random IV, and if you ran it multiple times, you would get different results. That's a feature that prevents certain kinds of attacks. So having different results shouldn't be surprising.

    If you're looking for an off-the-shelf AES format that includes all the pieces you need, take a look at RNCryptor or libsodium.