Fluid Nexus
mobile messaging without the mobile phone network


Page 1 of 1.

New release

I have released a new version of Fluid Nexus. For the Android version, I have implemented SQLCipher encryption of the local database. For the desktop version, very little has changed, excepting a few corrections of typos.

The Android version has been released again on the market and for download from this site.

I have decided to focus this project as an artistic intervention, a provocation and an example for others to look at. It should be considered as such and is not really suitable for any other purpose.

Posted by admin on . Comments

SQLCipher Support

Early SQLCipher support is available in the experimental repository on github. I’ve also created an early version of a “Welcome” activity to acquaint users to the Fluid Nexus model, present a disclaimer, and setup the SQLCipher passphrase. Network modalities to use must now be chosen by the user, and the Bluetooth modality defaults to only search for bonded devices. Constructive feedback is welcome.

Posted by admin on . Comments

On Examining Local Crypto Solutions

tl;dr: Well-known Android applications providing encrypted services sometimes store passphrases in the clear in memory; this is nothing surprising; you’re currently screwed if someone gets your Android phone; crypto is not necessarily the solution.

As part of research into current best practices in Android security I decided to examine two widely known pieces of software: Android Privacy Guard and textsecure. This was to help understand approaches that might be applicable to certain aspects of the Fluid Nexus project.

I am not a security researcher, nor a security consultant, and I cannot recite the socialist millionaire protocol by heart. What I do know is how to use the tools that are available to me. And I have experience in knowing what types of data need protection, experience that came from being a lab manager/technical assistant (writing analysis software, sysadmining our compute cluster, RAID arrays, and backup system, etc.) in a neuroimaging lab that was subject to HIPAA regulations.

In human subjects research and as a result of HIPAA you are not allowed to use personally identifiable information to refer to a research subject. Therefore you must choose some sort of unique identifier to store with the collected data that cannot be traced back to a particular subject. However, this trace has to exist somewhere in order to conduct meta-analyses regarding certain demographic information, and to potentially conduct follow-up analyses. So you only make the link on paper and store it in a secure location. Yet if that link is discovered then it’s all over in terms of anonymity.

It’s a similar case with crypto. We know this and have internalized all of the exhortations to not reuse our passphrases, not write them down, ensure that your private keys are secure, etc., etc., etc. But if someone apprehends your device while it is still on (and perhaps after it’s off, in the case of cold boot attacks), you’re screwed no matter what if a) they have the ability to get root and/or dump memory, and b) if your passphrase is cached. If you are detained and your phone is on and you have your passphrases cached, no amount of crypto is going to protect you. Crypto will only help you with an offline attack and when your adversary has not been able to dump the memory of your device where your passphrase might be cached.

Knowing these things let’s just go through a few exercises, wrapping up with what this means for Fluid Nexus and the crypto question.

Note: In this post I am primarily considering client-side crypto. A later post will examine crypto over the wire or over the air via techniques such as OTR and will examine what publicly, vetted libraries may or may not exist for doing broadcast encryption that are relevant for Fluid Nexus.


On my to-do list for a long time was integration with sqlcipher, thanks to the hard work of The Guardian Project and Zetetic. I have avoided spending too much time on this aspect since, according to The Guardian Project, “This R1 release should not be integrated into critical or production software“ (italics and bold theirs). But I decided to examine the procedure for doing so on a separate branch of Fluid Nexus. Downloading notepadbot, it’s incredibly simple to add in the correct libraries and make the necessary changes to your library calls; thanks to The Guardian Project for this easy-to-follow example.

But then you’re faced with a rather sticky problem: how do you a) securely pass a passphrase from your main activity to (in the case of Fluid Nexus) your ContentProvider; and b) how do you securely cache your passphrase in memory so that it can’t be found in a memory dump? The latter question, as we mentioned earlier and will show below, is one with no satisfactory solutions for Android at the moment. Curious about how this works I decided to look at APG and examine how it caches passphrases. Let’s take a look:

package org.thialfihar.android.apg;

public class CachedPassPhrase { public final long timestamp; public final String passPhrase;

public CachedPassPhrase(long timestamp, String passPhrase) { super(); this.timestamp = timestamp; this.passPhrase = passPhrase; } public int hashCode() { int hc1 = (int)(this.timestamp & 0xffffffff); int hc2 = (this.passPhrase == null ? 0 : this.passPhrase.hashCode()); return (hc1 + hc2) * hc2 + hc1; } public boolean equals(Object other) { if (!(other instanceof CachedPassPhrase)) { return false; } CachedPassPhrase o = (CachedPassPhrase) other; if (timestamp != o.timestamp) { return false; } if (passPhrase != o.passPhrase) { if (passPhrase null || o.passPhrase null) { return false; } if (!passPhrase.equals(o.passPhrase)) { return false; } } return true; } public String toString() { return “(” + timestamp + “, *******)”; } }

Is that true? Does APG store the passphrase in the clear in the constructor? Something like this raises all sorts of red flags initially, but on further reflection is likely unavoidable.

But lets go through the motions. If the passphrase is stored in the clear, it ought to be trivially easy to dump it from memory. Let’s find out. First, generate a dummy PGP keypair.

gpg --gen-key

Let’s make sure it’s protected by a really “strong” passphrase: “Super secret passphrase!”. Time for export:

gpg -ao ~/fakeprivkey.asc --export-secret-key 8A958014
gpg -ao ~/fakepubkey.asc --export 8A958014

Let’s push these to our sdcard. We assume you know how to import them into APG.

./adb push ~/fakepubkey.asc /sdcard/
./adb push ~/fakeprivkey.asc /sdcard/

Now force close APG so we start from a (relatively) clean slate. Open it up and use it to sign a trivial message so that the passphrase is cached. Now we’re going to dump the memory of the process and analyze it in a very simple way. The following commands in the adb shell require some way of gaining root; busybox is also used to make navigation and other tasks easier.

Follow along:

someuser@somehost platform-tools> ./adb shell
$ su
# chmod 777 /data/misc
# ps
USER     PID   PPID  VSIZE  RSS     WCHAN    PC         NAME
app_110   17973 2381  217088 24612 ffffffff afd0ee48 S org.thialfihar.android.apg
shell     18061 2390  648    336   c031b39c afd0eafc S /system/bin/sh
root      18062 18061 648    336   c031b39c afd0eafc S sh
app_107   18064 2381  209388 15956 ffffffff afd0ee48 S com.noshufou.android.su
root      18071 18062 796    336   00000000 afd0dbbc R ps
# kill -10 17973
# ls /data/misc
# cp /data/misc/heap-dump-tm1313854763-pid17973.hprof /sdcard/
# $ someuser@somehost platform-tools> ./adb pull /sdcard/heap-dump-tm1313854763-pid17973.hprof .
2666 KB/s (4361160 bytes in 1.597s)
someuser@somehost platform-tools> ../tools/hprof-conv heap-dump-tm1313854763-pid17973.hprof apg.hprof
someuser@somehost platform-tools> jhat apg.hprof

Okay, now we’re going to use jhat to make it easy to examine what’s in memory. Go to http://localhost:7000 and you’ll be presented with an easy to read dump of the memory at the time we sent the signal.

Let’s take a look at what’s in the CachedPassPhrase class we suspected earlier was storing our passphrase in the clear. Navigate to the specific instance. And take a look:

There it is under the passPhrase instance variable.

I do hope you created a keypair for your phone that is different from the one that you use elsewhere? And that it uses a different passphrase?

The shortest time that APG allows you to cache your passphrase is 15 seconds; from what I can tell there is no way to tell it to not cache your passphrase at all.

You can try this at home as well with gpg-agent: sudo gcore `pidof gpg-agent`. grep the dump for your passphrase.

Writing an application that runs as a service with root privileges and pulls passphrases from memory is left as an exercise to the reader1.

But again, if someone has root, you’re screwed.


I thought I’d use similar techniques to examine textsecure. Not having the source I must move, somewhat blindly, through the memory dump. But there’s still some interesting things.

Unsurprisingly, if you force a memory dump at the precise time of passphrase entry it’s trivial to find the passphrase. But what about for some time afterwards? Is a garbage collector pass forced after the dialog is dimissed? Or is the instance variable manually set to something else after the passphrase has been used to generate your keys? Let’s take a look. First, we change our textsecure passphrase to “Super secret passphrase!”. We force close to start with a clean slate. Then we enter in our passphrase; note the time is 12:00PM.

We wait a minute to dump the memory; see the following logcat output and note that the dump started at 12:01:08:

08-20 12:01:08.363: INFO/dalvikvm(18323): SIGUSR1 forcing GC and HPROF dump
08-20 12:01:08.375: INFO/dalvikvm(18323): hprof: dumping VM heap to "/data/misc/heap-dump-tm1313856068-pid18323.hprof-hptemp".
08-20 12:01:09.519: INFO/dalvikvm(18323): hprof: dumping heap strings to "/data/misc/heap-dump-tm1313856068-pid18323.hprof".
08-20 12:01:13.355: INFO/dalvikvm(18323): hprof: heap dump completed, temp file removed

Copy, pull, and convert the hprof file as before and fire up jhat. Since we don’t have the source we’ve got to poke around a bit. Perhaps PassphrasePromptActivity is what we want. In there is an EditText called passphraseText. And what’s it’s value?

Yup, there’s our passphrase.

What this suggests to us is that textsecure does not a) force a gc pass after passphrase entry to remove the passphrase from memory; or b) reset the value of the EditText so that it cannot be found in memory. Of course such techniques are not entirely predictable and the passphrase might still be lurking around somewhere.

Seeing how long after passphrase entry you can still retreive it is left as an exercise to the reader; our record is one minute, as shown here, and a dump done about an hour after passphrase entry resulted in nothing. Of course this will likely be highly dependent on the somewhat unpredictable nature of dalvik’s GC processes.

From what I can tell the shortest you can tell textsecure to cache your passphrase is 1 minute.

textsecure storage

But I wanted to look further. What does the actual database look like? Pretty easy to find out.

someuser@somehost platform-tools> ./adb shell
$ su
# cp /data/data/org.thoughtcrime.securesms/databases/messages.db /sdcard
# $ someuser@somehost platform-tools> ./adb pull /sdcard/messages.db .
416 KB/s (38912 bytes in 0.091s)
someuser@somehost platform-tools> sqlite3 messages.db
SQLite version 3.7.2
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .tables
android_metadata  mms               part              thread          
identities        mms_addresses     sms             

What’s in the sms table?

I’ve obscured some of the info, but I encourage you to try this at home. The third column contains the cleartext phone number of the person who sent you a SMS. I assume it would be the same for the MMS table. The message itself is encrypted, but the phone numbers of your correspondents are not. For messages you send there is an eleven digit number in the third column; I’m still not sure what it is.

This should have been clear in retrospect by anyone looking at the home screen before passphrase entry:

How would it be possible for it to know the recipients if the messages are ostensibly encrypted? The phone number, or some other unique identifier used to link textsecure with your Contacts, would need to be stored unencrypted. The only way around this would be to use something like sqlcipher to write the encrypted pages to your sdcard, which I’m told is in the works.

Finishing up, here’s the create table statement for the SMS database:

CREATE TABLE sms (_id integer PRIMARY KEY, thread_id INTEGER, address TEXT, person INTEGER, date INTEGER, protocol INTEGER, read INTEGER DEFAULT 0, status INTEGER DEFAULT -1,type INTEGER, reply_path_present INTEGER, subject TEXT, body TEXT, service_center TEXT); (24 bytes) 

Note that for messages you send your service center is also stored in the clear, which is may or may not be an issue; I defer to others on this point. The “person” column is interesting; I’m not sure what it’s used for because it wasn’t populated in my own dump and I haven’t been able to trace where and how it gets set.


These exercises were not done out of any malicious intent. Nothing that I have written here is new; all of these “attacks” are known. Rather this was a useful exercise to know to what extent encryption of local storage used for Fluid Nexus will help us.

In the Android model applications run in their own sandbox and getting access to the datastores and/or processes is only possible through applications signed with the same key. No such protections exist if you have root. Let’s say you had root but the database you’re trying to get at was encrypted. These exercises show that this doesn’t help you at all if your passphrase is cached in memory, as might happen if the phone was taken while you were using one of these applications that cached your passphrase. A smart adversary, upon taking possession of a phone, would immediately ensure it is on AC power and dump all memory at once to search for passphrases. And perhaps this isn’t even necessary if the device is susceptible to a cold-boot attack; I’m not sure how this applies to the varied devices running Android.

The last possibility is if you have root, are not able to retrieve passphrases from memory, and are left only with an encrypted database. The textsecure example shows that some information is still available, given that textsecure encrypts messages only. Phone numbers are left in the clear, and the nature of the encryption makes it easy to determine that it’s ciphertext. While indeed telcos already have this information, and could easily search through their records to find the numbers associated with those encrypted messages, I do wonder if having these numbers at hand might help reduce the search space. I defer to others on this point.

The potential solution at the moment is to use sqlcipher, where each page is encrypted/decrypted as necessary. There is still the issue that any form of passphrase caching will introduce a vulnerability. With that said, I do not want to incorporate it into the Fluid Nexus application until I am sure that it is ready, which I hope will be soon.

Another solution is full-phone encryption as provided by WhisperSystems. I don’t have a Nexus S or a Nexus One to test this out. I look forward to it being available for other devices, and to it hopefully becoming free software.

Finally, it’s important important to point out InTheClear (github repository), an application under development for, among other things, wiping data in a panic situation. This has the potential to mitigate some of the discussed attacks and is something better suited to an external, specialized, vetted package, rather than existing within Fluid Nexus itself.

I do fear that there are some who suggest turning to crypto as the magic lock that secures everything. It is not, and there are important situations where all the crypto in the world is not going to help you. I am grateful for the work of the guardian project, thialfihar, and moxie and want to thank them for contributing to the community, both for Android and in other situations. But it is clear that there is more to do. Hopefully in the near future there will be a vetted keychain solution so that we do not have to each write our own caching implementation. Given that our mobile devices have hundreds, thousands of pieces of identifiable information, we need to continue working on implementing solutions that not only protect individual applications, but are also secure and trusted enough to be used systemwide. When done right, crypto is absolutely the best thing we have at the moment for certain classes of applications and communications, but it needs to be understood as only one component of a larger set of tools2.

1 Yes, I hated these “exercises” too in my math and physics classes as an undergraduate and in grad school. Which is why you should take this in jest.

2 Thanks to n8fr8 and moxie for helping me think through these issues; the opinions expressed here are mine alone, and any consequent criticisms should be directed at me.

Posted by admin on . Comments

Virtriol has no place here.

And so we have removed a blog post that has, in part, incited some of the most vindictive, vitriolic, ad-hominem attacks that we have seen in a long time. Aspects of the project will hibernate for a short time. And we have learned to not engage with people who fail to understand civilized discussion.

Posted by admin on . Comments

Launching Fluid Nexus!

We’re pleased to announce the first public release of an entirely re-written Fluid Nexus!

Given recent events in Tunisia, Egypt, the UK, the US, and elsewhere, it was clear that the time for Fluid Nexus has come. We began this project in 2008 with a barely functional version for Nokia Series 60 phones that was developed during a workshop held at the Medialab-Prado in Madrid, Spain. Development lapsed as we found ourselves involved in other projects. We always planned on updating the software for desktop devices and potentially other smartphone platforms.

Development in the mobile space changed our focus. With Nokia’s embrace of the Windows platform for its smartphones (and the inability to release apps with GPL code on the Windows 7 market ) we decided to look again at the Android platform. While we have no love for Google, and the Android platform doesn’t give us as much access to low-level functionality as we’d like, we discovered workarounds for these issues. We completely retooled our message passing algorithm to make it easier to send audio, image, and video attachments. And we developed a cross-platform desktop application that runs on Linux, Windows, and hopefully OS X.

The need for message passing independent of centralized networks has never been more clear. The US State Department is itself funneling money towards accomplishing the same thing. Egyptians employed similar techniques during their state-imposed Internet outage. The UK is considering powers that would allow it to shut down social media websites during times of “unrest”, thereby following in the footsteps of Mubarak. Bay Area Rapid Transit (BART) in San Francisco shut down cell phone service in conjunction with a “potential protest” at one of their stations. And finally, our initial goals of not leaving a trace in order to prevent subpoenas is still in place.

We hope that you find Fluid Nexus useful. Source code is available for all platforms as well as this website. Let us know what you think and be sure to e-mail us if you have any questions or problems.

Posted by admin on . Comments

Older Fluid Nexus News

This is a copy of older news from the previous website; you can view it via the wayback machine.

UPDATE 2011.07.28: We’ll be updating this website shortly—hopefully within the next week—with a new design, information about the new applications for Android and Windows/Linux, and new features. Come back soon!

UPDATE 2011.06.15: We’re working on an actual Android version of the software, in conjunction with changes to the desktop/mobile versions. Android provides severe limitations on Bluetooth access so we’re having to modify the protocol a bit. We’re also planning on adding support for Zeroconf and Ad-Hoc Wifi. The current, pre-alpha code is up at github. If you’re interested, clone away and/or contact us at fluidnexus [{{at}} fluidnexus [[dot]]} net.

UPDATE 2010.10.18: After a rather long hiatus, we’d like to say that we are developing a desktop version of Fluid Nexus. The code for this and the mobile phone version is available at github. The desktop version will work similarly to the mobile phone version and is written in Python using QT. If you are interested in testing the application (it will run on Windows, Mac OS X, and Linux), please contact us.

UPDATE 2008.12.28: Two important notes! Fluid Nexus was given an Award of Distinction in the 2008 Memefest competition in the Beyond category. Also, I (Nick) presented some of the theoretical background of Fluid Nexus at the 2008 ISEA conference. You can download a PDF copy of the paper I presented entitled Reinterpreting networks of people as fluid for political purposes.

UPDATE 2008.04.14: See information about the Google Android version submitted for the first round of the Android Developers Challenge. (Information about this version has been removed as it’s no longer relevant.)

Posted by admin on . Comments

Page 1 of 1.