Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with block length in Node.js crypto streams

I want to crypt an input stream and send it to another server via TCP. So far so good. Everything runs smoothly, until the connection is closed. In almost any case the needed block size of 192 bits is not met and the script crashes with wrong final block length, although I turned auto padding on.

It seems like auto padding only works, when using the legacy interface. Am I doing something wrong here?

var net = require("net")
  , crypto = require("crypto");

var credentials = { algorithm: "aes192", password: "password" }
  , decipher = crypto.createDecipher(credentials.algorithm, credentials.password)
  , cipher = crypto.createCipher(credentials.algorithm, credentials.password);

decipher.setAutoPadding(true);
cipher.setAutoPadding(true);

net.createServer(function(socket) {
  socket.pipe(socket);
}).listen(2000);

var socket = net.connect(2000);

socket.pipe(decipher).pipe(process.stdout);
process.stdin.pipe(cipher).pipe(socket); 

socket.write("Too short.");
socket.end();

In my ideal Node.js world, the (De-)Cipher Stream would automatically pad the last block, when the source stream is closed. I think this is a design flaw.

Apart from opening an issue, how can I circumvent this behaviour? Do I have to put a byte counter between Socket and (De-)Cipher Streams?

like image 379
buschtoens Avatar asked May 27 '13 14:05

buschtoens


People also ask

How does node js handle IO operations in a way that they don't block code execution?

Instead of the process being blocked and waiting for I/O operations to complete, the I/O operations are delegated to the system, so that the process can execute the next piece of code. Non-blocking I/O operations provide a callback function that is called when the operation is completed.

Does NodeJS use Epoll?

It is an infinite while loop, calling Epoll (kqueue) “wait” or “pool”, when something interesting (callback, event, fs) happens for a Node. js; it routs that to Node. js, and exits when there is nothing to wait in Epoll. That is how asynchronous things work in Node.

How does node js handle concurrent tasks?

js can handle multiple concurrent requests easily and why it becomes an obvious choice for the development of such applications. Node. js works asynchronously. In other words, it does not block incoming requests from clients when the operating system has one I/O intensive request.


1 Answers

You have set your pipes like this :

stdin | cipher | socket (loopback) | decipher | stdout

But you bypass the encryption by writing directly to the socket, using them like this :

socket (loopback) | decipher | stdout

Try with this code :

var net = require("net")
  , crypto = require("crypto");

var credentials = { algorithm: "aes192", password: "password" }
  , decipher = crypto.createDecipher(credentials.algorithm, credentials.password)
  , cipher = crypto.createCipher(credentials.algorithm, credentials.password);

decipher.setAutoPadding(false); //set to false to keep the padding
cipher.setAutoPadding(true);

//Loopback
server = net.createServer(function(socket) {
  socket.pipe(socket);
})

server.listen(2000);

var socket = net.connect(2000);

//cipher to the loopback socket, to decipher and stdout
cipher.pipe(socket).pipe(decipher).pipe(process.stdout);

//write some data 
cipher.write("Too short.");

//Clean exit
cipher.end();
server.unref();

For the purpose of demonstration, I removed auto padding from the Decryptor object so you can see the leftover padding. Piping the program in xxd (at the command line, not in node) gives me this ouput :

$ nodejs so.js | xxd
0000000: 546f 6f20 7368 6f72 742e 0606 0606 0606  Too short.......

With the 0x06 repeated 6 times.

like image 77
ixe013 Avatar answered Sep 28 '22 09:09

ixe013