Javascript/NodeJS equivalent code for the Java code Cipher.doFinal(byte[])?
Asked Answered
B

2

3

I am migrating some server-side Java code to a new NodeJS server. I am looking for an equivalent method call in Javascript to Java's Cipher.doFinal(byte[]) Note that I can't use NodeJS Buffers because they don't support negative Byte values. So to do my encryption, I'll need a method that accepts an array of positive and negative numbers.

Here's all of what I currently have that is related to this problem:

Node JS / Javascript:
var crypto = require('crypto'); var cipher = crypto.createCipher('aes256',key);

Java (javax.crypto.Cipher):

Cipher cipher;
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
try {
    cipher = Cipher.getInstance("AES");
} catch (NoSuchAlgorithmException e) {
} catch (NoSuchPaddingException e) {
}try {
      cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
} catch (InvalidKeyException e) {
}

later in the Java code, I call this method where Iv represents Initialization Vector: byte[] newIv = cipher.doFinal(myIv);

How can I get the same result in JavaScript as I do in the doFinal Java method?

Benevento answered 6/7, 2014 at 4:4 Comment(0)
B
2

Turns out you can place an empty IV as follows:

var cipher = require('crypto').createCipheriv('aes-256'ecb', key, '');

As for the replacement method, simply store your old IV temporarily as a new IV and then attempt to update that new IV using the old one. Here's how it would look like in NodeJS using some of the above code on Initialization Vectors created as buffers:
var newIV = oldIV.slice(); newIV = cipher.update(newIV); oldIV = newIV;

Benevento answered 10/7, 2014 at 3:43 Comment(0)
A
3

Byte handling

You can use NodeJS buffers. The byte arrays in Java may just consist of signed bytes, but those bytes are not handled any differently from unsigned bytes. Only the value of the actual bits matter. If you need to treat bytes directly, it is often best to use hexadecimals instead. You can convert to an positive integer value by performing b & 0xFF and you can do the opposite by performing (byte) b.

You could of course also do something similar in NodeJS to make NodeJS handle signed numbers, but it is common to treat keys, IV's etc. as unsigned.

Cipher selection

Now for the Java AES encryption, you are using the unsafe "AES/ECB/PKCS5Padding" mode, as the Oracle Java JCE provider defaults to ECB mode of encryption and PKCS#7 padding (incorrectly named "PKCS5Padding" by Java). ECB does not use an IV, so you can ignore the value of the IV. Strangely enough, you do have to use crypto.createCipheriv(algorithm, key, iv) as the crypto.createCipher(algorithm, password) uses a password instead of a key. Of course you should also use algorithm "AES-256-ECB" for NodeJS/OpenSSL - if your key is indeed 256 bits in size.

Abominable answered 6/7, 2014 at 11:31 Comment(9)
I've left out the actual writing to the NodeJS cipher stream. That should be relatively simple once you've created the right algorithm and keys. You should migrate to a more secure protocol (TLS for preference if you need transport level security).Abominable
I think there are some areas in my code where bit manipulation on the negative bytes (signed bytes) comes out differently than their unsigned counterparts. You can't cast as a byte in JS. How would I make NodeJS handle signed numbers? I am using a specific AES custom encryption for a game, both of which I found online. The IV associated with this AES is 4 bytes long so var cipher = crypto.createCipheriv('aes256',key,iv); is returning invalid IV length... Also, this AES requires me to refresh the IV every so often as in the "newIv" Java code above which I need in JS.Benevento
I am trying to write someone else's server code in Javascript/Node for educational reasons. Specifically, I'm trying to write the crypt method in this class xp-dev.com/svn/MapleGame/Common/Security/AesCryptograph.csBenevento
Or even in the same method in this class in Java: svn6.assembla.com/svn/MoopleDEV/src/tools/MapleAESOFB.java If you're wondering, I'm making a server for a old MMORPG client so there are a few sources online.Benevento
This answer was helpful but didn't answer the question entirely. Actual writing to the NodeJS cipher stream wasn't easy to figure out as I am also a NodeJS noob. The more in-depth the better when you help noobs in the future :)Benevento
That's a trade off between my time and your time. There are plenty answers on CryptoJS on SO, including ones that use the CryptoJS as a stream. Note that for all this work, I don't even have received a single upvote.Abominable
I don't have 15 reputation, but I would if I did!Benevento
Solved that for you :) Note that I did not target you particularly with that comment, it's hard getting upvotes/downvotes for crypto answers (or answers that require readers to understand the Q/A in general). Should have joined earlier I guess.Abominable
I understand. Plus you have just about infinitely more experience in Cryptography than me so I do appreciate your time. Thanks again, upvoted :DBenevento
B
2

Turns out you can place an empty IV as follows:

var cipher = require('crypto').createCipheriv('aes-256'ecb', key, '');

As for the replacement method, simply store your old IV temporarily as a new IV and then attempt to update that new IV using the old one. Here's how it would look like in NodeJS using some of the above code on Initialization Vectors created as buffers:
var newIV = oldIV.slice(); newIV = cipher.update(newIV); oldIV = newIV;

Benevento answered 10/7, 2014 at 3:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.