Kim Dotcom’s coders hacking on Mega’s cryptography even as we speak – true “perpetual beta” style

Kim Dotcom’s new file sharing storage venture, Mega, wants to shield itself from accusations of failing to take action against piracy.

It does so by using cryptography to make sure it doesn’t see, and indeed cannot tell, what you’ve uploaded.

That provides privacy for you (other people, including Mega’s own staff, can’t snoop on your files) and deniability for Mega (other people, including Mega’s own staff, can’t even tell what your files might be).

But to deliver on that promise, you have to get the crypto right.

As we explained yesterday, early indications were that Mega’s coders hadn’t done so: we wrote about problems with entropy (randomness), deduplication and the use of poorly-chosen data in Mega’s sign-up emails, needlessly making password dictionary attacks possible.

Researchers at hacking group fail0verflow subsequently wrote up yet another cryptographic error: the use of a faulty hash function to authenticate the JavaScript code that makes the whole service work.

I’ll try to explain briefly.

You’d expect a secure site to deliver all its content via HTTPS, including (or perhaps especially) the JavaScript code that drives the cryptography.

Mega uses HTTPS, but to save money it serves up most of its JavaScript from “cheap” servers in distributed content delivery networks that use 1024-bit RSA keys.

→ Shorter RSA keys require less CPU power, so you get more performance for a given outlay. But distributed networks mean more servers and require widepsread key distribution, so you increase the risk of a compromise.

To raise overall security, Mega also serves up, from centralised servers that use 2048-bit keys, a list of cryptographic hashes for the content hosted in the “cheap seats”. These centralised servers also serve up the cryptographic code needed to verify those hashes.

That means that you would have to compromise the 2048-bit-protected servers and the 1024-bit-protected servers in order to serve unauthorised scripts from the lower-security part of the network.

Lo! A neat way to have your security cake but pay less to deliver it.

Yesterday, however, fail0verflow documented the crypto code served up from the higher-security servers.

The hashing code used to authenticate the JavaScript coming from lower-security servers was the function h() below:

function h(s)
{
    var a = [0,0,0,0];
    var aes = new sjcl.cipher.aes([111111,222222,333333,444444]);
    s += Array(16).join('X');

    for (var i = s.length & -16; i--; ) {
        a[(i>>2)&3] ^= s.charCodeAt(i)<<((7-i&3)<<3);
        if (!(i&15)) a = aes.encrypt(a);
    }
    return a;
}

Don't worry if you don't speak JavaScript. All you need to know is this:

  • The function h() is an algorithm known as a keyed CBC-MAC.
  • CBC-MACs aren't secure unless the key is secure. You can create a forgery if you know the key.
  • The key used in h() is hard-wired and insecure. It’s right there: the JavaScript array [111111,222222,333333,444444].

Ouch. You can't use CBC-MACs like that. You need to use a proper cryptographic hash instead.

SHA-3 or SHA-256 would probably be a good idea. As fail0verflow pointed out, SHA-1 would be OK and even MD5 would be better than the code above, despite MD5's known cryptographic weakness.

The silver lining, of course, is that cloud services can issue updates nearly instantaneously. Just serve the new code the next time a user visits your site.

(Yes, you sidestep traditional change control, because the user doesn't get to choose if or when to update. But you also avoid change control sluggishness, because the user doesn't get to choose if or when to update.)

And, sure enough, by this afternoon, Mega had taken fail0verflow's advice.

The 2048-bit-protected crypto code that protects the 1024-bit-protected crypto code has been updated to:

function sha256(d)
{
    h = new sjcl.hash.sha256();
    for (var i = 0; i < d.length; i += 131072) 
        h = h.update(d.substr(i,131072));
    return h.finalize();
}

Now, SHA-256 is used instead of CBC-MAC with a hard-wired key.

Good work by Mega's coders to get the fixes out quickly. But if you're relying on Mega for your own privacy, you probably want to ask yourself why they didn't get the basics of their crypto implementation right up front.

Commenters on our previous article offered the reasonable suggestion that Mega's main cryptographic need is self-preservation: ensuring its own deniability in order to avoid getting taken down along with its users' data. Your privacy and security comes in second place.

There are two really simple solutions if that's true. You can choose either or both: use a different provider, or encrypt the data yourself before you let Mega encrypt it.

In fact, why not encrypt your own data yourself, always and anyway? It's your data, after all.