Anonymous computing: Peer-to-peer encryption with Ember.js


Bugbuzz is an online debugger, one of my pet projects. What I wanted to provide is kind of really easy-to-use debugging experience, I envisioned the debugging with it should be like dropping one line as what you usuallly do with ipdb or pdb.

import bugbuzz; bugbuzz.set_trace()

You can do it anywhere, no matter it’s on your Macbook or it’s on server. Then there comes a fancy Ember.js based online debugging UI.

To make this happen, instead of providing debugging service on your local machine, a debugging API service is needed.

The architecture is pretty simple, Python debugger library sends source code and local variables with all other necessary information to the Bugbuzz API server, then Bugbuzz API server will notify the Ember.js dashboard via PubNub. When user clicks buttons like next line / next step, the dashboard calls to the API server, then the API server publishes these commands vai PubNub to the debugging Python program. Upon receiving the commands, the debugging library executes then sends source code and local variables to the API server again.

No, you should not trust me.

Although Bugbuzz does provide easy-to-use service, it still concerns some developers, as all source code and local variables will be passed to the server. You may ask

Can I trust you with my source code and debugging data?

My answer is

No, you should not trust me.

In fact, this not only concerns you but also concerns me, I don’t want to have any chance to read your source code and the debugging data either. It feels like a paradox to me, I want to provide you an easy-to-use service, but I want to know nothing about your data. So how do you solve this problem?

Anonymous computing

The answer is encryption!

I have this concept for a long while, I called it Anonymous Computing. The idea is to provide service without knowing senstive data while processing. As a service provider, it’s really hard to do as the less I know, the less I can provide. But if one can manage to do so, users don’t need to trust the service provider, they can trust the encryption mechanism.

One approach to do it is to encrypt the data in the source, pass it to the client via server, then decrypt the data in the client side. As long as the server doesn’t know the secret key, the data shall remain unknown to the server.

In the past, this is almost impossible to do with web, as

  • Web server renders the web page, i.e.
  • server will know your data anyway
  • Functionalities of browser is pretty limited

Fortunately, it’s 2015 now, browser is not merely a web-page viewer anymore, it’s an application platform. Not just in terms of functionality, also the performance has been enhanced over time. Even better, there are booming web technology communities all around in this era, you can pick any one you like and start crafting awesome web app without worrying low level details, enjoy the beautiful view on shoulders of giants.

How does it work?

For Bugbuzz, I use Embjer.js for developing the dashboard app. It works like this

Instead of sending plain text source code and debugging information, when a debugging session starts, the library creates a secret key, then encrypts source code and debugging information with the secret key and pass it to the server. All Bugbuzz API server can see is encrypted data. To allow the Ember.js dashboard to decrypt the data, the secret key will be passed to the dashboard as part of hash in URL.

/#/sessions/<SID>?access_key=<SECRET KEY>

It’s Ember.js nature to use hash style URL, by doing this, the web server cannot see the secret key, as the browser will only send URL part to the server. Visiting a debugging session without the secret key, you can only see it asks you to provide access key

Encryption with Ember.js in action

The encryption algorithm we use here is AES. I am not teaching you cryptography here, we will focus on how encryption works with Ember.js only, if you are interested it cryptography, you can read CRYPTO101.

To understand how encryption works with Ember.js model, let’s see a very simple file model

export default DS.Model.extend({
  breaks: DS.hasMany('break'),
  session: DS.belongsTo('session'),
  filename: DS.attr('string'),
  content: DS.attr('string')
});

As you can see the model has content property, it supposes to be encrypted. I will suggest you use base64 to encode it. Given an example

pOdIPxiVgjCl3YAhZPSMSytg7GMojkE8VuWu88rAxMuFPNZkCob9rTSI9JeUv3tzlxYBCiRQYQE7gaiylyT0AEDDiiIDvPt7YN0/OZ7kS34IevNNHkxSnzw393M81YaE2F8R5mYpMSbfmnX/dZrbhMw3XzvR+VN5g9bEW1nrBreltXG6bg+m7lCk1M9pyoxMDhfhU5TReiFHQvxPDwU38w==

Let’s decode it and see what it looks like

Looks like completely nonsense huh? Well, that’s the point of encryption :P

To decrypt it, you need the access key. It will be passed in as a queryParam for the controller like we mentioned, you can define your access_key parameter like this

export default Ember.Controller.extend({
  queryParams: {access_key: null},
  access_key: null,
  // ...
})

The secret key usually needs to be passed as a part of URL, you can also encode it in base64, but remember to use URL-safe base64 encoding. Upon receiving that access key, you can validate it and set it to the model like this

  paramAccessKeyChanged: function() {
    var self = this;
    var session = this.get('model');
    if (Ember.isNone(session)) {
      return;
    }
    var accessKey = this.get('access_key');
    if (!Ember.isNone(accessKey)) {
      accessKey = normalizeURLSafeBase64(accessKey);
      if (session.validateAccessKey(accessKey)) {
        session.set('accessKey', accessKey);
        this.set('access_key', null);
        self.transitionToRoute('session', session);
      }
    }
  }.observes('access_key', 'model'),

I also clear the access_key parameter then call self.transitionToRoute('session', session), that’s because I don’t like to leave the access key in URL.

Since even with a wrong access key, the decryption still works, but just the output is garbage. It’s hard to tell whether is the output correctly decrypted or not sometimes. In this case, you can provide a validation_code as plain text in the data along with a encrypted validation_code. So that you can decrypt it and see if the validation code matches, like this

  // validate given access key
  validateAccessKey: function (accessKey) {
    var decryptedStr = decrypt_with_b64_as_string(
      accessKey,
      this.get('aes_iv'),
      this.get('encrypted_code')
    );
    return decryptedStr === this.get('validation_code');
  },

If the access key is not valid, you can prompt user to input correct one. With the access key properly set to the debugging session model, we can now write this:

import Ember from 'ember';
import DS from 'ember-data';
import { decrypt_with_b64_as_string } from '../utils/encryption';

export default DS.Model.extend({
  breaks: DS.hasMany('break'),
  session: DS.belongsTo('session'),
  filename: DS.attr('string'),
  content: DS.attr('string'),
  aes_iv: DS.attr('string'),

  source_code: Ember.computed(
    'aes_iv',
    'content',
    'session.accessKey',
    function() {
      if (Ember.isNone(this.get('session.accessKey'))) {
        return 'Encrypted';
      }
      var decryptedStr = decrypt_with_b64_as_string(
        this.get('session.accessKey'),
        this.get('aes_iv'),
        this.get('content')
      );
      return decryptedStr;
    }
  )
});

It reads accessKey from session model and decrypt it. So in the template, you can access file.source_code

I open-sourced the Ember.js dashboard project, you can see how it works and play around it by yourself. Oh, and by the way the javascript AES library I use is aes-arraybuffer.

The future

I feel we actually only unleashed a minor portion of cryptography power with modern browser technologies. I envision in the future, more interesting anonymous computing browsed-based application will be introudced, by leveraging asymmetric key encryption, blind signature, Bitcoin block chain and all awesome technologies in cryptography world. Bugbuzz is just a very simple example shows how we can build accessible but also trustable service with Ember.js + encryption.

Feel free to let me know what you think :P

Discuss on Hacker news

Recent articles:

How I discovered a 9.8 critical security vulnerability in ZeroMQ with mostly pure luck and my two cents about xz backdoor
High-speed 10Gbps full-mesh network based on USB4 for just $47.98
Why I built a self-serving advertisement solution for myself