Skip to content

Reverse Engineering the QR Code

Steve Donaghy edited this page May 7, 2019 · 6 revisions

Overview

The Yi home application lets you pair devices by having them scan a QR code generated by the app itself. Scanning the QR codes with a regular barcode reader reveals that the QR codes themselves are simple text.

The Yi Home camera systems are using the ZBAR QR Code Scanning library https://github.com/Zbar/Zbar.

Examples

Below is an example of a typical generated QR code

QR Code

This QR code was generated at 2019-02-23 13:24 (UTC).

The wifi network was named as The Normandy.

The wifi password was AAAAAAAAAAAA.

Text

Scanning this reveals a piece of text as such:

b=EU28FM4aoN1vWOML&s=VGhlIE5vcm1hbmR5&p=eXgLBxIrLnkJFCMp

Raw

The raw bytes from the QR code itself are as follows (Note this is just typical QR code encoding, there's nothing special here):

43 86 23 d4 55 53 23 84   
64 d3 46 16 f4 e3 17 65
74 f4 d4 c2 67 33 d5 64   
76 86 c4 94 53 57 66 36
d3 16 86 26 d5 23 52 67   
03 d6 55 86 74 c4 27 84
97 24 c6 e6 b4 a4 64 34   
d7 00 ec 11 ec 11 ec 11
ec 11 ec 11 ec 11 ec 11   
ec 11 ec 11 ec 11 ec 11

Breakdown

Working through the text, the following can be broken down as follows: b=EU28FM4aoN1vWOML&s=VGhlIE5vcm1hbmR5&p=eXgLBxIrLnkJFCMp

Component Name Example Encoding Decoded
b= bindKey EU28FM4aoN1vWOML Unknown Unknown
s= SSID VGhlIE5vcm1hbmR5 Base64 The Normandy
p= Wifi Password eXgLBxIrLnkJFCMp Xor + Base64 AAAAAAAAAAAA

BindKey

The bind key is a response code from the Xiaoyi servers. The YI phone application communicates to https://api.us.xiaoyi.com sending a GET for a bind key supplying the YI ID of the user, Time and Mac address [1]

GET /v2/qrcode/get_bindkey?hmac=<redact>    %3D&userid=00110011&seq=1&timestamp=1522268058227 HTTP/1.1
Content-Length: 0
Host: api.us.xiaoyi.com
Connection: Keep-Alive
User-Agent: YI Home/2.20.20.0_20180227 (Alcatel_4060A; Android 10.2; en-US)
Accept-Encoding: gzip
x-xiaoyi-appVersion: android;73;2.20.20.0_20180227

The Camera then appears to verify this information, if it cant it verbalises an error and disregards the configuration. On next reboot the camera will be unable to connect to wifi, and a QR code will need to be shown again.

More information is needed about this.

SSID

This is the SSID (Wifi Network) for the camera to connect to, simply Base64 encoded.

Password

The password is also Base64 encoded, however the password is XOR'd against a static string before it's base 64 encoded:

Static string

The following string is used as a kind of obfuscation key. In reality this doesn't obfuscate much as it's trivial to reverse-engineer such a key 89JFSjo8HUbhou5776NJOMp9i90ghg7Y78G78t68899y79HY7g7y87y9ED45Ew30O0jkkl

Example code to encode a password

The following example is written in C#

public static string EncodePassword(string plainText, string obfuscationKey)
{
	StringBuilder sb = new StringBuilder();

	// This is a standard XOR routine
	for (var i = 0; i < plainText.Length; i++)
	{
		sb.Append((char)(plainText[i] ^ obfuscationKey[(i % obfuscationKey.Length)]));
	}
	var encipheredText = sb.ToString();

	// We convert the XOR'd text into an array of bytes
	var bytes = Encoding.ASCII.GetBytes(encipheredText);

	// And convert those bytes to a Base 64 string
	return Convert.ToBase64String(bytes);
}
public static string DecodePassword(string plainText, string obfuscationKey)
{
       // Convert the Base 64 string back to bytes
       byte[] newBytes = Convert.FromBase64String(plainText);
       // Convert array of bytes back to XOR'd text
       plainText = Encoding.ASCII.GetString(newBytes);

       StringBuilder sb = new StringBuilder();

       // This is a standard XOR routine
       for (var i = 0; i < plainText.Length; i++)
       {
           sb.Append((char)(plainText[i] ^ obfuscationKey[(i % obfuscationKey.Length)]));
       }
       var encipheredText = sb.ToString();

       return encipheredText;
}
public static string EncodeBase64SSID(string plainText)
{

       var bytes = Encoding.ASCII.GetBytes(plainText);

       // And convert those bytes to a Base 64 string
       return Convert.ToBase64String(bytes);

}
public static string DecodeBase64SSID(string plainText)
{

       // Convert the Base 64 string back to bytes
       byte[] newBytes = Convert.FromBase64String(plainText);
       plainText = Encoding.ASCII.GetString(newBytes);
       return plainText;
}

The creation of a custom QR code can be done using http://qrcode.azurewebsites.net/ or similar and using above functions to create an image based on the RAW data of

b=00000001&s=BASE_64_ENCODED_SSID&p=BASE_64_AND_XOR_WIFI_PASSWORD

Or you could use this pre-made generator for Yi Cameras: https://yi.kushan.biz/