Embedding Secret Data in QR Code

What text will be displayed when you read the QR code above with your reader?

Interestingly, it depends on your reader.

Result from an official QR Code reader for iPhone ->"Pride and Prejudice"

Result from 'Barcode Reader' for Android ->"Pride and Prejudice and Zombies"

Please note that this is not achieved by the Web server by checking the user agent. The technical design of QR Code allows this kind of hacking, and the results are different between QR Code readers.

In this article, I introduce some methods to embed secret data in QR Code. QR Code is widely used in various application field including some critical payment applications. I would like to bring out that QR Code is a "suggestive" barcode system that allows various hacking.

Method 1: embed NUL (\0) character

You can embed NUL characters to a QR Code, which is often used as a terminator of a string in some programming languages. Some QR Code readers terminate a string when an NUL character is found and skip displaying the following hidden text, and some treats an NUL character as an NUL character, not a terminator. In this case, the reader displays the text following the NUL. That is the reason why the result depends on the readers. Here is a list of the results from various QR Code readers:

PlatformAppResult
iPhoneOfficial QR Code Reader "Q""Pride and Prejudice"
iPhoneGoogle Chrome's in-app QR Code reader"Pride and Prejudice"
iPhoneQRCode Barcode"Pride and Prejudice"
iPhonei-nigma"Pride and Prejudice and Zombies"
AndroidOfficial QR Code Reader "Q""Pride and Prejudice and Zombies"
AndroidBarcode Scanner"Pride and Prejudice and Zombies"
AndroidYahoo! Japan's QR Code reader"Pride and Prejudice and Zombies"

Interestingly, even if the application displays two strings joined with an NUL sequentially, they are still isolated internally. Here is an example:

The code above has two strings joined with an NUL. The first string is "https://fukuchi.org/works/qrhack/normal.html", and the second string is "secret.html". I expected that they are concatenated and treated as a URL "https://fukuchi.org/works/qrhack/normal.htmlsecret.html", but all applications I tested treated only the first string as a URL, and the second string treated as a simple text.

Method 2: putting data after a terminator chunk

The data embedded in a QR Code consist of a set of "chunks". Generally, the set is terminated by a "terminator chunk", followed by padding bits when necessary. Putting some data chunks after the terminator chunk is invalid, but most QR Code readers do not validate this. That means you have a chance to embed hidden data.

In order to embed data after a terminator chunk, you can use the following experimental branch of libqrencode.

Then you need a modified QR Code reader to read the hidden data. Here is a modified Quirc.

Results

The following QR Code has a text "Pride and Prejudice" and a hidden text "and Zombies".

I have tested various QR Code readers, and all readers handled the code valid but could not read the hidden text.

By contrast, the modified Quirc can find the hidden data as shown below. The terminator chunks are displays as '␀'.

This method is a kind of 'steganography'.