I was implementing password authentication for VNC in node.js the other day and faced a problem where it would just never successfully authenticate. I checked my implementation several times and it seemed fine. Then I tried to implement it in Python just to see if I was missing something obvious. It also didn't work. Then I tried doing the authentication through openssl and it was also giving a result I didn't expect. Finally I found some old C code and wrote node-des, which worked. I still haven't figured out why it didn't work in node, python and openssl. Perhaps my readers can help me understand what was going on!

Here is a quick overview of how VNC password authentication works. On the VNC server you set the authentication password. When a VNC client connects, the VNC server generates random 16 byte garbage called challenge and sends it to the client. The client DES encrypts the challenge with the password as the key. The result is called the response and is also 16 bytes in size. The client then sends it to the VNC server. The VNC server then also DES encrypts challenge with the password and compares it with the response. If challenge matches response, the session gets authenticated.

Let's say the password set on the VNC server is browsers, and the challenge that the VNC server sends to the client is the following 16 bytes:

0c fd 6b 8c 5c 04 b3 e5 01 40 b9 de 33 9e 0d db

Then DES encrypting these 16 bytes with the password browsers should produce the following response:

44 ee fc 48 83 bb 95 f1 c0 82 c3 e2 98 c3 6a 4a

I sniffed this data from a real VNC client - VNC server communication and I use this as a test case for node-des as it's the correct result. However now let's look at what happens if I encrypt the challenge with node's crypto module, with Python and with openssl.

First node's crypto module. I wrote the following program to DES encrypt the 16 challenge challenge bytes with the password browsers.

var crypto = require('crypto');
var challenge = Buffer([
   0x0c, 0xfd, 0x6b, 0x8c,
   0x5c, 0x04, 0xb3, 0xe5,
   0x01, 0x40, 0xb9, 0xde,
   0x33, 0x9e, 0x0d, 0xdb

var response = crypto
  .createCipher('des', 'browsers')


When I run it, it produces 27 byte long output and it's not what I'd expect:

<Buffer c3 a9 72 c2 8b c3 a2 10 56 c2 8f c3 94 12 c2 a3 c3 a3 33 c2 ba c3 9e c2 a7 c2 96>

So node.js doesn't produce the expected 16 byte result. In fact I tried all the possible variations of the des algorithm that openssl (which node.js bases its crypto module on) supports. Perhaps I chose the wrong des implementation as there are many?

var crypto = require('crypto');
var challenge = Buffer([
   0x0c, 0xfd, 0x6b, 0x8c,
   0x5c, 0x04, 0xb3, 0xe5,
   0x01, 0x40, 0xb9, 0xde,
   0x33, 0x9e, 0x0d, 0xdb

var algos = ("des des-cbc des-cfb des-ecb des-ede " +
            "des-ede-cbc des-ede-cfb des-ede-ofb " +
            "des-ede3 des-ede3-cbc des-ede3-cfb " +
            "des-ede3-ofb des-ofb des3 desx").split(/\s+/);

algos.forEach(function (algo) {
    try { 
        var response = crypto
          .createCipher(algo, 'browsers')

    catch (x) {
        console.log("Crypto doesn't support:", algo);

It produced the following output and not a single result was what I'd expect:

<Buffer c3 a9 72 c2 8b c3 a2 10 56 c2 8f c3 94 12 c2 a3 c3 a3 33 c2 ba c3 9e c2 a7 c2 96>
<Buffer c3 a9 72 c2 8b c3 a2 10 56 c2 8f c3 94 12 c2 a3 c3 a3 33 c2 ba c3 9e c2 a7 c2 96>
<Buffer 24 43 c2 99 11 c2 8c c3 ac c3 b2 42 c3 b1 77 c3 a2 c2 96 05 c3 b3 c3 94 02>
<Buffer c2 aa 09 c3 98 c3 92 c2 8c 69 68 c2 97 c2 88 09 c2 ae c3 89 4f 3f c3 9f c3 83>
<Buffer c2 84 c2 86 3f c3 ba 2b c2 ba 4b c2 bd 50 05 c3 a8 c3 9d 37 66 15 51>
<Buffer 7d 60 c2 8d 4e 27 c3 b2 0f 6f 0e 48 54 60 38 2e c2 b3 7e>
<Buffer 43 4d c2 ac 19 c3 92 c2 81 c2 a2 3f c2 9a c2 be c2 8a c2 b3 72 44 37 34>
<Buffer 43 4d c2 ac 19 c3 92 c2 81 c2 a2 3f 49 c3 a4 04 24 2c 77 05 40>
<Buffer c2 a4 c2 84 c2 b2 2e 45 c2 90 c2 af c2 9c 21 5b c2 bd c3 aa c2 84 c3 9b 4c 76>
<Buffer c3 81 5c c2 b9 28 c2 be c3 b6 74 c3 89 c3 89 c2 8c 62 c2 ab 3a c2 95 6c 3f>
<Buffer 3f c3 8d 22 c3 8e 5d 01 29 c2 8b c2 85 c2 b5 11 75 6f c2 b5 5b c3 9c>
<Buffer 3f c3 8d 22 c3 8e 5d 01 29 c2 8b c2 8c 64 51 c2 8e c2 a7 2f c2 a8 c2 97>
<Buffer 24 43 c2 99 11 c2 8c c3 ac c3 b2 42 09 68 1b c3 bd 2d 79 c2 ba c3 a1>
<Buffer c3 81 5c c2 b9 28 c2 be c3 b6 74 c3 89 c3 89 c2 8c 62 c2 ab 3a c2 95 6c 3f>
<Buffer 4c 45 c2 bb c2 bd 78 c2 bd c3 b5 c2 b9 c3 96 c3 b7 c3 b0 6d c3 b9 c3 8d c3 a9 2d>

I had no idea what was going on at this point, so I decided to try Python and see if I can get the result I expect through Python's DES algorithm. Worst case I could spawn Python each time I need to authenticate at VNC. I used the pyDes module for my experiment and installed it to virtualenv as following:

$ virtualenv pydes
$ cd pydes
$ . ./bin/activate
$ easy_install pydes

Then I wrote the following test program:

from pyDes import des

challenge = "\x0c\xfd\x6b\x8c" \
            "\x5c\x04\xb3\xe5" \
            "\x01\x40\xb9\xde" \

response = des("browsers").encrypt(challenge);

print ["0x%x" % ord(b) for b in response]

The output was 16 bytes but not what I'd expect:

['0xd0', '0x6f', '0x0', '0x1a', '0x73', '0xb8', '0x24', '0xc6', '0xf1', '0x72', '0x81', '0x6e', '0x6d', '0x59', '0xc8', '0xa7']

Then I thought, perhaps the endianness was incorrect, so I reversed the words in the challenge:

from pyDes import des

challenge = "\xfd\x0c\x8c\x6b" \
            "\x04\x5c\xe5\xb3" \
            "\x40\x01\xde\xb9" \

response = des("browsers").encrypt(challenge);

print ["0x%x" % ord(b) for b in response]

But no, this was also giving some other result that wouldn't work with VNC:

['0x2e', '0xe8', '0xec', '0x7c', '0xde', '0xf7', '0x36', '0x56', '0xf0', '0x60', '0xbe', '0x6f', '0xb', '0xf8', '0x9b', '0x76']

Being totally clueless, I decided to use the plain command line openssl tool just to see if node.js or Python were messing up the binary data or something like that. As I had sniffed the challenge from the VNC session, I put it in a file challenge and ran the openssl tool as following:

$ openssl des -pass pass:browsers -in challenge -e -nosalt | hexdump
0000000 72e9 e28b 5610 d48f a312 33e3 deba 96a7
0000010 d253 826d 9b86 3620                    

The output was again different, 24 bytes in size and it didn't match the response.

At this point I had had enough with all these different results and I started searching the web for the simplest possible DES implementation as I wasn't up to implementing DES myself. I found some C code that was public domain and wrote node-des that produces the results that I expect and that VNC server accepts.

var des = require('../build/Release/des.node');
var challenge = Buffer([
   0x0c, 0xfd, 0x6b, 0x8c,
   0x5c, 0x04, 0xb3, 0xe5,
   0x01, 0x40, 0xb9, 0xde,
   0x33, 0x9e, 0x0d, 0xdb

var response = des.encrypt('browsers', challenge);



$ node des.js
<SlowBuffer 44 ee fc 48 83 bb 95 f1 c0 82 c3 e2 98 c3 6a 4a>

Victory! It worked and my VNC code was functional! The question is, why did every single attempt to DES encrypt with node, python and openssl fail? Any ideas? Let's get to the bottom of this in the comments!


One of my readers noticed that many of the words in node's output were of the form cx xx, so he asked me if I was sure that node wasn't converting the output to utf8? I was pretty sure it wasn't, buffers are buffers of raw bytes after all, but this looked too suspicious. I looked up in the documentation and found out that the default encoding for the buffers was utf8...

So I modified the original program and replaced console.log(Buffer(response)) with console.log(Buffer(response, 'binary')).

var crypto = require('crypto');
var challenge = Buffer([
   0x0c, 0xfd, 0x6b, 0x8c,
   0x5c, 0x04, 0xb3, 0xe5,
   0x01, 0x40, 0xb9, 0xde,
   0x33, 0x9e, 0x0d, 0xdb

var response = crypto
  .createCipher('des', 'browsers')

console.log(Buffer(response, 'binary'));

Now I do get 16 bytes in the output but it still doesn't match the sniffed response:

<Buffer e9 72 8b e2 10 56 8f d4 12 a3 e3 33 ba de a7 96>

I also modified the program that runs through all the DES algorithms by adding the 'binary' encoding to the Buffer's constructor. The output now is 16 bytes for all algorithms:

<Buffer e9 72 8b e2 10 56 8f d4 12 a3 e3 33 ba de a7 96>
<Buffer e9 72 8b e2 10 56 8f d4 12 a3 e3 33 ba de a7 96>
<Buffer 24 43 99 11 8c ec f2 42 f1 77 e2 96 05 f3 d4 02>
<Buffer aa 09 d8 d2 8c 69 68 97 88 09 ae c9 4f 3f df c3>
<Buffer 84 86 3f fa 2b ba 4b bd 50 05 e8 dd 37 66 15 51>
<Buffer 7d 60 8d 4e 27 f2 0f 6f 0e 48 54 60 38 2e b3 7e>
<Buffer 43 4d ac 19 d2 81 a2 3f 9a be 8a b3 72 44 37 34>
<Buffer 43 4d ac 19 d2 81 a2 3f 49 e4 04 24 2c 77 05 40>
<Buffer a4 84 b2 2e 45 90 af 9c 21 5b bd ea 84 db 4c 76>
<Buffer c1 5c b9 28 be f6 74 c9 c9 8c 62 ab 3a 95 6c 3f>
<Buffer 3f cd 22 ce 5d 01 29 8b 85 b5 11 75 6f b5 5b dc>
<Buffer 3f cd 22 ce 5d 01 29 8b 8c 64 51 8e a7 2f a8 97>
<Buffer 24 43 99 11 8c ec f2 42 09 68 1b fd 2d 79 ba e1>
<Buffer c1 5c b9 28 be f6 74 c9 c9 8c 62 ab 3a 95 6c 3f>
<Buffer 4c 45 bb bd 78 bd f5 b9 d6 f7 f0 6d f9 cd e9 2d>

But still no match.


Ryan (in the comments below) found out why this was happening. Turns out that the VNC authentication reverses the order of bits in every byte of the password.

I was basing my implementation on the RFB protocol's specification and it doesn't say a word about it.

I'm quoting that document:

The server sends a random 16-byte challenge. The client encrypts the challenge with DES, using a password supplied by the user as the key, and sends the resulting 16-byte response.

There is no way I could have guessed this. How often do you think of reversing bits in every byte of the password? Never.

Many people are surprised when they hear that sed is Turing complete. How come a text filtering program is Turing complete they ask? Turns out sed is like a small assembly language that has a comparison operation, a branching operation and a temporary buffer. If you translate a problem into a textual representation then these operations are enough to make sed Turing complete!

I didn't want to invent a new proof so I'll just present a proof by Christophe Blaess. The proof may sound silly but it works. Back in the day Christophe wrote an implementation of a Turing machine in sed [download turing.sed]. Now since any programming language that can implement a Turing machine is Turing complete leads us to conclude that sed is also Turing complete. ■ Haha. That's it!

Christophe Blaess offers his own introduction to Turing machines and a description of how his sed implementation works in his article Implementation of a Turing Machine as Sed Script.

Here is an example program for his Turing machine that increments a binary number. The program has the initial tape configuration on the first line of the program, and the program itself below it. In this example the initial tape configuration is the binary number 10010111 (151) and the program increments it by one.

| 10010111

# State 0
0  R0

# State 1
1  L2

# State 2
2 1R3

# State 3
3  RF

To run this program save it to a file increment.tm and run it through turing.sed as following:

$ sed -f turing.sed < example.tm

You'll get the following output:

(0) | |10010111
(0) |1|0010111
(1) 1|0|010111
(1) 10|0|10111
(1) 100|1|0111
(1) 1001|0|111
(1) 10010|1|11
(1) 100101|1|1
(1) 1001011|1|
(1) 10010111| |
(2) 1001011|1|
(2) 100101|1|0
(2) 10010|1|00
(2) 1001|0|000
(3) 10011|0|00
(3) 100110|0|0
(3) 1001100|0|
(3) 10011000| |
(F) 10011000 | |
Final state F reached... end of processing

The output shows the state and tape changes as the program is executed. When it's done the final state F is reached and the computation process terminates producing 10011000 (152) as a result as expected.

Since you can write any program in sed, people have done so and written tetris, sokoban and many other programs. Take a look at these:


The Busy Beaver

If you liked this article, you'll also like my article about the busy beaver. The busy beaver is a Turing machine that puts 1's on an initially blank tape. The busy beaver problem is to find an n-state Turing machine that puts as many 1's on the tape as possible. It hasn't been solved for a 5-state Turing machine yet and theorists doubt that it shall ever be computed for 6 states!

My sed book

I wrote this fun book on sed a while ago called "Sed One-Liners Explained." If you don't know sed yet and wish to learn it, my book teaches it through 100 practical and well-explained examples. Take a look!

I was reading about vim the other day and found out why it used hjkl keys as arrow keys. When Bill Joy created the vi text editor he used the ADM-3A terminal, which had the arrows on hjkl keys. Naturally he reused the same keys and the rest is history!

Here is how the hjkl keys looked:

ADM-3A keyboard's hjkl keys with arrows.

And here is the whole terminal that vi was created on:

Lear Siegler's ADM-3A computer terminal.

Since vim is derived from vi, it uses the same hjkl keys.

And while we're at it, notice where the ESC key is positioned:

Lear Siegler's ADM-3A computer terminal's full keyboard.

That's why the ESC is used to change between vi modes! Because it's so close and easy to reach.

Also ever wondered why home directory is ~ in UNIX? Look at the HOME key in upper right corner!

HJKL T-Shirt!

Update: No longer available.

I just got a deal with Teespring for a hjkl t-shirt! Teespring is like kickstarter for t-shirts. If at least 15 people commit to buy the shirt the deal goes through and everyone gets the shirt. Otherwise nothing happens.

Get your limited edition hjkl t-shirt now! (Ships worldwide in 4-8 days.)

Extra Discussions!

My post has generated a lot of awesome responses, see hacker news, osnews, and reddit discussions (two of them on /r/programming and /r/vim).

Follow me!

If you enjoyed my post, subscribe to my blog, follow me on twitter, google+ or github. Thank you!

We're super excited to announce dedicated plans for Browserling. With a dedicated Browserling plan you get your own Windows server with all the browsers pre-installed, plus you can install any software that you want, any browser plugins you want, and do absolutely anything you wish with it as you also get full administrator rights to your server.

I made a demo video of dedicated plans. Take a look:

Tweet us @browserling if you want to try a free demo. Or you can just buy a dedicated instance right away from the pricing menu!

Browserling is an interactive cross-browser testing tool. You can use it to test your website in IE, Firefox, Chrome, Opera, and Safari.

Hello ladies and gentlemen! I'm happy to announce my 3rd e-book called "Perl One-Liners Explained." This book is based on the "Perl One-Liners Explained" article series that I wrote over the last 3 years and that has been read over 500,000 times!

I went through all the one-liners in the article series, improved explanations, fixed mistakes and typos, added a bunch of new one-liners, added an introduction to Perl one-liners and a new chapter on Perl's special variables.

Table of Contents

The e-book has 111 pages and it explains 130 unique one-liners. Many of one-liners are presented in several different ways so the total number of one-liners in the book is over 200.

The e-book is divided into the following chapters:

  • Preface.
  • 1. Introduction to Perl One-Liners.
  • 2. Spacing.
  • 3. Numbering.
  • 4. Calculations
  • 5. String Creation and Array Creation.
  • 6. Text Conversion and Substitution.
  • 7. Selective Printing and Deleting of Lines.
  • 8. Handy Regular Expressions.
  • 9. perl1line.txt
  • Appendix A. Perl's Special Variables.
  • Index.

What are Perl One-Liners?

Perl one-liners are small and awesome Perl programs that fit in a single line of code and they do one thing really well. These things include changing line spacing, numbering lines, doing calculations, converting and substituting text, deleting and printing certain lines, parsing logs, editing files in-place, doing statistics, carrying out system administration tasks, updating a bunch of files at once, and many more.

Let's take a look at several practical examples that you can easily do with one-liners. All these examples and many more are explained in the e-book.

I have also made the first chapter of the book, Introduction to Perl One-Liners, freely available. Please download the e-book preview to read it.

Example 1: Replace a string in multiple files at once

perl -p -i.bak -e 's/Config/config/g' conf1 conf2 conf3

Suppose you have 3 configuration files, and you discover that you made a mistake and need to replace all occurrences of Config with config. This one-liner does just that. It executes the s/Config/config/g that replaces all occurrences of Config with config on all lines. And since you're smart about it, you always do -i.bak to make backup files in case something goes wrong.

I explain the -i, -p, and -e arguments in the e-book in great detail.

Example 2: Generate a random 8 character password

perl -le 'print map { ("a".."z")[rand 26] } 1..8'

This one-liner generates and prints a random 8 character password. It uses the list range operator .. operator to produce all strings from "a" to "z", which is the alphabet. Then a random letter is chosen by rand 26 and this operation is repeated 8 times.

Example 3: URL-escape a string

perl -MURI::Escape -lne 'print uri_escape($string)'

Here we use the URI::Escape module from CPAN. It exports the uri_escape function that does URL-escaping.

You can install this module from CPAN by running perl -MCPAN -e'install URI::Escape' on the command line.

I have this one-liner as an alias actually for both URL-escaping and unescaping URL-escaping as it's such a common thing to do:

urlescape () { perl -MURI::Escape -lne 'print uri_escape($_)' <<< "$1" }
urlunescape () { perl -MURI::Escape -lne 'print uri_unescape($_)' <<< "$1"; }

Then I can do this in the shell:

$ urlescape "http://www.catonmat.net"

$ urlunescape http%3A%2F%2Fwww.catonmat.net

Very useful!

Example 4: Print all lines from line 17 to line 30

perl -ne 'print if 17..30'

Here we use the binary flip-flop operator .. that becomes true when the input line number is 17, stays true while the line number is less than or equal to 30, and then becomes false. Combining the flip-flop operator with print if makes it print only lines 17-30.

Example 5: Remove all consecutive blank lines, leaving just one

perl -00pe0

I included this one-liner here in the examples just to show you how funny and obscure one-liners can get. This one-liner deletes all repeated blank lines from the input or from the given file. It does it by enabling the paragraph slurp mode through -00 command line argument, which reads the input paragraph-by-paragraph, rather than line-by-line, and prints the paragraphs. This way any number of blank lines between the paragraphs get ignored.

I explain this one-liner in more details in the e-book.

As I hope you can see, knowing how to write one-liners is very useful. It was one of my top priority tasks through the years to become very efficient in the shell. Literally every day when I'm programming, I have to do all kinds of data processing tasks, changing files, verifying output, doing quick calculations, parsing data, etc, and knowing Perl one-liners makes it really fast to get things done.

Now that I have written this e-book, you can become very efficient, too. Enjoy!

Book Preview

I prepared a free book preview that contains the first 13 pages of the book. It includes the table of contents, preface, introduction to Perl one-liners and the first page of the second chapter.

Buy it now!

The price of the e-book is $9.95 and it can be purchased via PayPal:

PayPal - The safer, easier way to pay online!

After you have made the payment, my automated e-book processing system will send you the PDF e-book in a few minutes!

Tweet about my book!

Help me spread the word about my new book! I prepared a special link that you can use to tweet about it:

What's next?

I really love writing about programming and I have planned writing many more books. The next few are going to be a book on mastering vim, a practical guide on how to be anonymous on the web, and the catonmat book.


Enjoy the book and don't forget to leave comments about it! Ask me anything you wish and I'll help you out.

Also if you're interested, take a look at my other two e-books. The 1st one is called "Awk One-Liners Explained" and the 2nd one is called "Sed One-Liners Explained" They're written in a similar style as this e-book and they teach practical Awk and Sed through many examples.

Finally, if you enjoy my writing, you can subscribe to my blog, follow me on Twitter or Google+.