Archive for the ‘Cryptography’ Category

TV-Leaks Is Broken and Dangerous

Thursday, September 18th, 2014

In 2013 SVT, Sveriges Television, launched its whistleblowing platform inspired by Wikileaks. TV-Leaks intends to make it easier for Swedish whistleblowers to leak sensitive information to journalists. The problem is that TV-Leaks suffers from a long list of vulnerabilities.

Unencrypted attachments

The form allows visitors to upload files. Even worse: if the encrypted message is too long users are recommended to send it as an attachment instead:

// Check that the lenght of the above is not too long
if ($('#encryptedMessage').val().length > 131072)
{
    alert("Meddelande-texten är för lång, prova med att skicka med en bilaga istället.");
    return false;
}

TV-Leaks does not encrypt attachments:

$('#encryptedMessage').val(openpgp.write_encrypted_message(pub_key, message));

Submitting the form with all fields set to “test” and attaching the file “test.txt” containing the string “test” POSTs the following:

-----------------------------17354154294744539562044116888\r\nContent-Disposition: form-data; name="title"\r\n\r\n\r\n-----------------------------17354154294744539562044116888\r\nContent-Disposition: form-data; name="files[]"; filename="test.txt"\r\nContent-Type: text/plain\r\n\r\ntest\n\r\n-----------------------------17354154294744539562044116888\r\nContent-Disposition: form-data; name="department"\r\n\r\nsvtnyheter\r\n-----------------------------17354154294744539562044116888\r\nContent-Disposition: form-data; name="name"\r\n\r\n\r\n-----------------------------17354154294744539562044116888\r\nContent-Disposition: form-data; name="phone"\r\n\r\n\r\n-----------------------------17354154294744539562044116888\r\nContent-Disposition: form-data; name="email"\r\n\r\n\r\n-----------------------------17354154294744539562044116888\r\nContent-Disposition: form-data; name="encryptedMessage"\r\n\r\n-----BEGIN PGP MESSAGE-----\r\nVersion: OpenPGP.js v.1.20130712\r\nComment: http://openpgpjs.org\r\n\r\nwcBMA9CgkCCRTSS6AQgAgBc3+aFzhuX9d5tqgKmdP7bbsj/HCZgu7Je1qMMs\r\nvefcPPE8gJfpT2zPB023dG11msmbp+3PUXV4qWPYJiwe0CqjshQR6JpdubB7\r\nmP6qrKPiTlOFxaR5E5PTlr0pfdBch6MblCCngQEUVDCcfTIBWnG/4khb+day\r\n8Dd3x0AD8+PmP7EAS2tdv52nwfXc4oMTMhrNRLTBEo0K4osrfr+83WJ62OcN\r\npBkXIpq6MIwPbmeh6HEm6jfrgWmqgYNdOqpkxCF1dwW0f8mC2KKUkhEhbNSd\r\nrFAycEZSEt9rxNNhYRnH/DstM+s8Pf/AgU/mtkNYwSGn8qapvyTPEa/1eiOw\r\nEtJ7ATXj3qFOUuDzoKPkD5KiVmowYX18pcYMkp73ZWe6HBVPPFc9Ir0QGLg2\r\nR9S6IeFBRRnUueYhFCko5gZz5aGrZCGfZOwRQ0bCpRbMvnSEjBZS6JCZYGD2\r\nd9NuSY0qYwQsdGGNb14VFA01gbHQw+1YZvvoAEKY/StL1V6M\r\n=OigO\r\n-----END PGP MESSAGE-----\r\n\r\n-----------------------------17354154294744539562044116888\r\nContent-Disposition: form-data; name="notEncryptedMessage"\r\n\r\n\r\n-----------------------------17354154294744539562044116888\r\nContent-Disposition: form-data; name="submitButton"\r\n\r\n\r\n-----------------------------17354154294744539562044116888--\r\n

Notice that the attached file is sent in plaintext:

filename="test.txt"\r\nContent-Type: text/plain\r\n\r\ntest\n\r\n

Outdated and vulnerable OpenPGP.js

TV-Leaks uses OpenPGP.js.

this.versionstring="OpenPGP.js v.1.20130712";

This version is vulnerable to the findings in Cure53’s security audit of OpenPGP.js. Cleartext Messages Spoofing, EME-PKCS1-v1_5 padding uses Math.random(), Cleartext Message Spoofing in Armor Headers, EME-PKCS1-v1_5 Error Handling in RSA Decryption, Errors in EMSA-PKCS1-v1_5 decoding routineErrors in EMSA-PKCS1-v1_5 decoding routine and Side-channel leak in RSA decryption, just to mention the most serious issues.

The pubkey

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: BCPG C# v1.6.1.0

mQENBFJgF40BCACo55jBfaiPg9L8YdFTurB1INum85ia/MP2WsCYaPShltM0qKS/
2UNmv/bXp0Nq7SgYvrs4xYRM2A71AONdXnyzMz7zCB5H3i/U3qF7D0eMMyQAhCPK
bMEXxpo96bOhlWyHnjPFVvXUwS/w1xDNRVrYetc9vAPM1kIOOcuABY8LpHLviVTZ
m+RIQ7akOhUmGekdo4vHGAlPJjOE0hJUh34ZG79Vp9vVDMd6O+CAZQMhO/dpp7zg
Y6TsL37q44vX6dyJuRLqPjvWfQLjJXDii/6LHz1+S+ETDC1RXtkJOCOkuvAl7S+T
/Bmu+nrEHDW5KvvlmfS5L8F7hTnVcwYtozkHABEBAAG0AIkBHAQQAQIABgUCUmAX
jQAKCRDQoJAgkU0kul56B/oCDRFETr9GFOi0ur6hsRfzJ9pD6FL+2ZcDFudPLlxH
pG80wbJf6SRkC6xK6KCrph6NBaE4FFMIXtO9fVX9nqrmCENwynv8Um+epXLDZUNU
J9YBzwnQ4l9+KDJ5lpIC0LrzHrZmUvg0/zeqOM9k5fLnHZTGQKSSX7vrEKwi/V49
TerDrPot2uNw+fs7rSyD17egCqIMK/0HVQcR4/IF/W1GWor8MxGnn7J57y+5fBN7
4AlT8TLEpmH4eZdwikUwgIBb9MPVId1v5RRBtf/gA0J5BBZvzFpe8f+ai+Qg6AYS
kbxcu3GCCDepEPj6NMxUeuIMM3Nzt2RMjsmR5x2KJf36
=CwA4
-----END PGP PUBLIC KEY BLOCK-----

The public key was generated using dodgy BouncyCastle Java crypto library v1.6.1.0. The public key should be replaced by a key generated by something properly functional and well-tested: GnuPG.

2048 bit keys should be considered as a replacement for the current 1024 bit. NIST has disallowed the use of 1024 bit keys after 31 December 2013 because they are insecure. 1024 bit RSA, which TV-Leaks uses, is broken.

Classical JavaScript verification issue

As usual, JavaScript crypto is a risk by nature since there’s no way for the client to verify that the file sent by the server is the expected file. Classic MITM risk with JavaScript crypto, not exclusive for TV-Leaks.

Is TV-Leaks safe to use?

Not at all.

Solving the browser crypto problem

Sunday, July 14th, 2013

Many developers have worked hard to port critical cryptographic functionality to JavaScript. We all agree that there is a clear requirement in a safer world to have asymmetric crypto support in the web. Porting code to JavaScript is great for users that don’t really care about the strength but only that the data is encrypted. Those people usually believe that they do not need perfect crypto, as long as it is any form of crypto it is “good enough” for them.

There are many problems with porting cryptographic functions directly to JavaScript and we see many great ideas failing on doing things properly. JavaScript cryptography is very young when comparing its lifespan to established binary solutions, such as GnuPG, that have been audited for long. GnuPG has been around since 1999 and GPG4Browsers, now OpenPGP.js, since 2011.

Auditing JavaScript ports leads to better design and less failures in time, but even when everything has been solved some problems remain due to design. Web browsers live in a very hostile world and we systematically witness XSS vulnerabilities and 0day exploits which enable dumping critical data, like private keys, as soon as either the DOM or HTML5 local storage is accessed. We can take care of badly implemented cryptography but we can’t take care of the way that the JavaScript implemented cryptography is accessible to anything that can execute JavaScript in the correct environment. As long as cryptography is done in JavaScript this will always be a huge threat.

The users that care more about their security and privacy are demanding solutions aligned with their requirements, and JavaScript implemented cryptography is by design insecure due to the surrounding threats in its domain. These users are actively choosing not to use JavaScript ported functionality but instead continue to use their local binaries that have been around and audited for decenniums more than newborn ports. And they are completely correct in doing so, because how can we actually trust JavaScript? We are stepping over the security requirements in order to deliver working solutions faster than science can keep up with it. We are impatient and we need something to work as soon as possible, especially in modern day and age with the ongoing war against free unmonitored online communication. By doing so we bypass the most important core ideas of implemented cryptography: security and privacy.

The solution

In order to expose GnuPG functionality to the web we must create an API for it which can perform cryptographic operations with non sensitive elements, such as armored public keys and private key metadata, without exposing anything of importance. The best way of doing it and successfully integrating it into web browsers is to run a webserver locally which pre accepted remotely served content can communicate with. The most important detail is that private keys should never ever be available for the web browser but instead reside in the local GnuPG keyring which the API manipulates through the local GnuPG binary.

I came up with a solution that I named pygpghttpd which I am currently working on supporting in my OpenPGP plugin for Roundcube: rc_openpgpjs. pygpghttpd is an open source minimalistic HTTPS server written in Python. pygpghttpd exposes an API enabling GnuPG’s cryptographic functionality to be used in web browsers and other software which allows HTTP requests. pygpghttpd runs on the client’s localhost and allows calling GnuPG binaries from the user’s browser securely without exposing cryptograhically sensitive data to hostile environments. pygpghttpd bridges the required elements of GnuPG to HTTP allowing its cryptographic functionality to be called without the need to trust JavaScript based PGP/GPG ports. As pygpghttpd calls local GnuPG binaries it is also using local keyrings and relying on it entirely for strength. In short pygpghttpd is just a dummy task router between browser and GnuPG binary.

pygpghttpd acts as a HTTPS server listening on port 11337 for POST requests containing operation commands and parameters to execute. When a request is received it checks the “Origin”, or if missing the “Referer”, HTTP header to find out which domain served the content that is contacting it. It then detects if the domain is added to the “accepted_domains.txt” file by the user to ensure that it is only operational for pre accepted domains. If the referring domain is accepted it treats the request and serves the result from the local GnuPG binary to the client. In the response a Cross-origin resource sharing HTTP header is sent to inform the user’s browser that the request should be permitted. If the referring domain is missing from accepted_domains.txt the user’s browser forbids the request in accordance with the same origin security policy.

The HTTPS certificate used by pygpghttpd is self signed and is not used with the intention to enhance security since all traffic is isolated to the local network interface. It uses HTTPS to ensure that both HTTPS and HTTP delivered content can interact with it.

pygpghttpd exposes metadata for both private and public keys but only allows public keys to be exported from the local keyring. The metadata for private keys is enough for performing cryptographic actions. Complete keypairs can be generated and imported into the local keyring.

For example, generating a keypair with cURL:

curl -k –data “cmd=keygen&type=RSA&length=2048&name=Alice&[email protected]&passphrase=foobar” -H “Origin: https://accepted.domain.com” https://localhost:11337/

Or from JavaScript:

$.post("https://localhost:11337/", {
  cmd: "keygen",
  type: "RSA",
  length: "2048",
  name: "Alice",
  email: "alice\@foo.com",
  passphrase: "foobar"
}, function(data) {
  if(data == "1")
    return true;
  return false;
});

Please see the project on Github, API documentation and example for full details.

rc_openpgpjs: Ending seven years of Roundcube insecurity

Monday, January 7th, 2013

Roundcube is a popular open source IMAP webmail application. Roundcube is used by Harvard University, UC Berkeley and University of Michigan. Apple Mac OS X 10.7 uses Roundcube per default in its Mail Server. While writing this a lazy Google dork estimates 133 000 public Roundcube installations.

PGP support was first requested seven years ago and set critical six years ago. PGP support has been requested actively ever since. One of the core developers began the development of his PHP implementation, the Enigma plugin, two years ago but the plugin has not been made functional yet.

Today I am proud to release a beta version of my Roundcube plugin that implements PGP using the OpenPGP.js (based on GPG4Browsers) JavaScript library. rc_openpgpjs enables OpenPGP to function in the user’s browser so that fundamental key storage security isn’t immediately broken by design, in opposite to the official Enigma plugin.

At its current beta stage; rc_openpgpjs is able to generate an encryption key pair, save it in HTML5 web storage (in your own browser, guys) and perform encryption and decryption of email. rc_openpgpjs works in any modern browser that can parse HTML5 and supports the window.crypto object. Unfortunately this is limited to Google Chrome today, but Mozilla is struggling working on it.

rc_openpgpjs is available on Github. rc_openpgpjs will become stable as soon as some small glitches have been corrected. It has been written for Roundcube 0.8.4 with the Larry skin.

Introducing TrueCrypt Volume Manager

Saturday, January 5th, 2013

Linux has DM-CRYPT, FreeBSD has GEOM_ELI and Oracle is holding ZFS encryption options closed source. The incompatible nature of encrypted storage throughout various UNIX systems is an obvious problem. TrueCrypt supports most popular platforms but until now there hasn’t been a simple way to organize and maintain TrueCrypt containers over different types of systems. TrueCrypt Volume Manager aims to be this bridge.

TrueCrypt Volume Manager, shortened TCVM, is a UNIX shell environment written in Python. It provides a simple CLI shell interface to easily create, mount, unmount and list containers and also the possibility to easily change the passphrase of a given encryption container. Since TCVM is intended to run as a UNIX shell this allows you to securely administrate your TrueCrypt containers over the SSH protocol.

TCVM also provides the function to automatically generate secure passphrases for TrueCrypt containers and store the passphrases in a separate container. This function is fully optional to use and is essentially inspired by the KeePass project. TCVM flexes a custom wrapper for TrueCrypt.

Please note that TCVM is still new and may be slightly rough around the edges. I am happy to fix any issue you may encounter.

The project is available on Github.

Presenting DNSDH

Thursday, March 29th, 2012

DNSDH is a protocol for exchanging cryptographic keys using the Diffie-Hellman algorithm. Instead of exchanging keys traditionally, the clients speak to a bogus DNS server to initiate an encrypted session in an existing channel of communication. The cryptographically relevant packets travel through a data path that appear to be normal domain name resolve queries to remain stealth and effective even behind limited and surveillanced networks. Please understand that the DNS server is only pretending to be a server for performing name lookups by using its language but performing different tasks.


The bogus DNS server is the center of the key exchange. It uses memcached to store data in memory and deletes any output after it’s been delivered to its recipient. The point of DNSDH is to establish a reliable network enabling anything that can perform a DNS request to exchange cryptographic keys using discrete bogus domain name queries. The nodes communicating, Alice and Bob, could possibly be two cellphones, IRC clients or even death stars. It’s also a great blast to teasingly merge cryptographic key exchanges with traffic that is rarely looked at by network administrators unless they want to censor or monitor you.

When initializing the session Alice first declares the values of p, g and Alice’s private key (alice_private) and then queries the bogus DNS server with dnsdhinit.p.g.alice_public. The DNS server creates a sessionid and stores it in the memory with the data provided in Alice’s query. Alice tells Bob that she wants to talk privately and sends him a packet containing the sessionid provided by the DNS server. Bob queries the DNS server with the sessionid recieved from Alice. The DNS server replies with the information provided in Alice’s query. Bob then proceeds by declaring his own private key (bob_private) and calculates the value of his public key: g^bob_private mod p. Bob can then calculate the secret he shares with Alice: alice_public^bob_private mod p. Then Bob queries the DNS server with dnsdhinit.bob_public, receives an id and sends it to Alice in a packet. Alice then queries the DNS server with the id, receives bob_public and calculates the secret she shares with Alice: bob_public^alice_secret mod p.

Alice

$ ./client.example.pl 1337 1338 init
[+] Generating keys...
[+] alice_pub_key: 7
[+] alice_priv_key: 19
[+] Query dnsdhinit.23.5.7
[+] SEND DNSDH_INIT: 6035559
[127.0.0.1:58602]: DNSDH_FINISH: 9300804
[+] Query sessionid.9300804
[+] p: 23
[+] g: 5
[+] bob_public: 1
[+] Shared secret: 1

Bob

$ ./client.example.pl 1338 1337
[127.0.0.1:60267]: DNSDH_INIT: 6035559
[+] Query sessionid.6035559
[+] p: 23
[+] g: 5
[+] alice_public: 7
[+] Generating keys...
[+] bob_pub_key: 1
[+] bob_priv_key: 0
[+] Shared secret: 1
[+] Query dnsdhinit.1
[+] SEND DNSDH_FINISH: 9300804

Source code

The source code is available on Github.

Erroneous cryptography usage in reCAPTCHA API

Friday, September 2nd, 2011

As a developer you’ll definitely stumble upon a lot of ugly code, and sometimes some snippets are just plain “wtf?”. I found this one by an accident a couple of months ago while browsing through the reCAPTCHA API library developed by Google. First, let’s take a quick look at the PHP manual for a libmcrypt introduced function called mcrypt_encrypt():

string mcrypt_encrypt ( string $cipher , string $key , string $data , string $mode [, string $iv ] )

reCAPTCHA offers a way to only display email addresses to users that solve a CAPTCHA (catchy, huh?) called Mailhide. The Mailhide part of recaptchalib declares a function called _recaptcha_aes_encrypt() and it is declared as below:

function _recaptcha_aes_encrypt($val,$ky) {
        if (! function_exists ("mcrypt_encrypt")) {
                die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
        }
        $mode=MCRYPT_MODE_CBC;
        $enc=MCRYPT_RIJNDAEL_128;
        $val=_recaptcha_aes_pad($val);
        return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
}

As you can see, the initialization vector (the last parameter of mcrypt_encrypt()) used is statically defined as a nullbyte string. If you’ve studied cryptography to some extent you probably know that the entire purpose of the initialization vector is to ensure that the same data encrypted with the same key outputs different ciphertext, just like the purpose of a password salt is to generate different hashes for equal password strings in authentication.

By using the \0 IV string Google simply silences a warning which PHP would generate if mcrypt_encrypt() would be called using Rijndael in CBC mode without a specified IV, thus it is possible that the used IV is nothing but a fix of this warning. However, using a static nonrandom IV makes the algorithm susceptible to dictionary attacks. _recaptcha_aes_encrypt() may not be a very important part of the reCAPTCHA API to keep secure, but a very easy solution to this would be to use another block cipher mode which does not require an initialization vector.