iCATA: Building a realtime bus locator app

For my last semester of college, I took a class on iOS development. The last assignment of the class was a five week project of our own choosing. My idea was to build a better bus locator app for the local bus service, CATA. The CATA available on the app store leaves a lot to be desired. Most notably, I want to see multiple bus routes on the map simultaneously. This is very useful for anyone that uses the buses to get around campus since there are four bus routes that go around campus. When you’re running for the bus, every second counts so it’s quite advantageous to be able to see all four campus routes on the same map at once.

The first challenge was getting access to the API that provides the bus location info. CATA provides a web-based bus locator at http://realtime.catabus.com/InfoPoint/, but this is quite basic; nothing more than the bus location and the data from the server is all XML (yuck). Fortunately, there is a new web-based bus locator at http://50.203.43.19/InfoPoint/. Besides the fact that it’s just an IP address, this page provides more information including the direction of the bus, how many people are on board, even the name of the driver and the format of the data from the server is JSON (yay!). But how to get URLs to get data from the API? This is actually quite easy with the Live HTTP Headers Firefox addon. Just refresh the page and look for RESTful URLs. For this project these turned out to be:

  • http://50.203.43.19/InfoPoint/rest/RouteDetails/Get/[route ID] for info about a specified route. This includes info about buses on the route, the coordinates of each stop on the route, and the filename of the KML file for the route.
  • http://50.203.43.19/InfoPoint/rest/StopDepartures/Get/[stop ID] for upcoming departures from the specified stop. This includes the route IDs of buses as well as their scheduled and expected times of arrival and departure in UNIX time.
  • http://50.203.43.19/InfoPoint/Resources/Traces/[KML filename]. The KML file is used for drawing the line of the route on a map. The filename is given in the route details JSON file.
  • There was also a resource for downloading all the available routes, but since these rarely change, I chose to keep a static copy of these in a plist distributed with the app so that it does not need to download them each time the app is started (like the existing CATA app does).
Working with binary data in C and OpenSSL

My post on how to do basic AES and RSA encryption has, for a while now, been one of the most popular posts on my blog, but I continually get questions about why people can’t print out the encrypted messages like a normal string or write them to a file using fprintf(). The short answer is that encrypted messages are binary data, not ASCII strings with a NUL terminator and thus, they can’t be treated as if they’re ASCII data with a NUL terminator. You might be saying, “but I want to send an encrypted message to my friend as ASCII!”.

Well, time for base64.

We can use base64 to encode our encrypted messages into ASCII strings and then back again to binary data for decryption. OpenSSL has a way of doing this for us:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
char* base64Encode(const unsigned char *message, const size_t length) {
    BIO *bio;
    BIO *b64;
    FILE* stream;

    int encodedSize = 4*ceil((double)length/3);
    char *buffer = (char*)malloc(encodedSize+1);
    if(buffer == NULL) {
        fprintf(stderr, "Failed to allocate memory\n");
        exit(1);
    }

    stream = fmemopen(buffer, encodedSize+1, "w");
    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new_fp(stream, BIO_NOCLOSE);
    bio = BIO_push(b64, bio);
    BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
    BIO_write(bio, message, length);
    (void)BIO_flush(bio);
    BIO_free_all(bio);
    fclose(stream);

    return buffer;
}
MITM Protection via the Socialist Millionaire Protocol (OTR-style)

Crypto disclaimer!  I am NOT a crypto expert. Don’t take the information here as 100% correct; you should verify it yourself. You are dangerously bad at crypto.


The problem

Man-in-the-middle attacks are a serious problem when designing any cryptographic protocol. Without using a PKI, a common solution is to provide users’ with the fingerprint of exchanged public keys which they should then verify with the other party via another secure channel to ensure there is no MITM. In practice, this is a very poor solution because most users will not check fingeprints and even if they do, they may only compare the first and last few digits of the fingerprint meaning an attacker only need create a public key with the same few first and last digits of the public key they are trying to impersonate.

The solution

There’s no good protection from MITM, but there is a way to exchange secrets without worrying about a MITM without using a PKI and without checking fingerprints. OTR (off-the-record) messaging utilizes the Socialist Millionaire Protocol. In a (very small) nutshell, SMP allows two parties to check if a secret they both hold are equal to one another without revealing the actual secret to one another (or anyone else). If the secrets are not equal, no other information is revealed except that the secrets are not equal. Because of this, a would-be MITM attacker cannot interfere with the SMP, except to make it fail, because the secret value is never exchanged by the two parties.

How does it work?

As usual, the Wikipedia article on SMP drowns the reader with difficult to read math and does a poor job explaining the basic principle behind SMP. Luckily, there are much better explanations out there. The actual implementation of it is, unfortunately, just as convoluted as the math. The full implementation details can be found in the OTR protocol 3 spec under the SMP section. Below is the basic implementation of the protocol as defined in OTR version 3:

Cryptully: Simple Encrypted Chat

Back in May I started a project with the goal of allowing simple chat (instant messaging if you will) between two people, except that everything was encrypted. The original goal was not to reinvent the chat program, but rather make a chat program with a very specific purpose: quick, encrypted chat between two people. Why? There are more chat clients that anyone can count out there and a similar number of them are encrypted. The problem is that few people use encryption and setting it up is a pain. The user has to install software and configure software. This does nothing but deter the user from using any type of secure communication. I set out to create a simple chat client with the following goals:

  • All messages are encrypted.
  • Easily accessible to everyone.As in, no knowledge of crypto required.
  • Cross platform; it should run on Linux, Windows, and OS X.
  • No software to install and no user accounts to create.
  • Just bare bones chat with a minimal interface. Nothing fancy here.
  • Simple enough that the code could be inspected by anyone who is curious to verify nothing suspicious is going on.
  • Ability for users to host their own servers if desired.
  • Open source (of course).

After a few months and iterations of designs and chat clients, I’m very happy to say that I’ve accomplished all those goals. Here’s what the finished product looks like:

It’s called Cryptully and it’s a basic encrypted chat program. The only cryptography the user needs to know is how to check a public key fingerprint and that is explained as simple as possible (read these numbers, if they match, everything is fine). Further, binaries are available for download where all the user need to do is download and run. There’s no dependencies to install or accounts to create.

Cross-platform deployment of Python applications with PyInstaller

A primary goal for my Cryptully project (an encrypted chat program) was to make a desktop application accessible to as many users as possible. Nothing annoys me more than wanting to use a service or program and having to install a program that I’ll just uninstall later or having to create an account. I’m a big proponent of making the barrier to entry to using a new service as low as possible. Since the nature of my program (cryptography) did not warrant a web application, I was pushed to the desktop. The desktop isn’t exactly known for getting something up and running quickly verses just going to a website. This led me to want to accomplish the following for my project:

  • Build and run on Linux, Windows, and OS X
  • No need to install any software
  • No user registrations

With that in mind, I selected the language and libraries that would facilitate that goal. This led to:

  • Python
  • QT
  • M2Crypto
  • PyInstaller

Python for cross platform development was a natural choice as was QT. I’ve found that QT has some nuances with presentation of my application on OS X, but the fact that it worked exactly as intended on Linux, Windows, and OS X was extremely impressive. This allowed me to get my program running on all three OSs, but it wasn’t user friendly, even for a developer. Windows, for example, required the installation of Python, PyWin, PyQt, M2Crypto, and the Visual C++ Redistributable Package. Hell, it took me a few hours to get all those installed and working correctly and I wrote the program. How could I package everything into a single binary file?

In comes PyInstaller.