« Home | Expanding on Josh Smith's WPF MVVM app » | Wifi Geolocation » | Sending a DKIM Signed Email from C# » | Verifying a DKIM signature in C# » | Windows Azure - SlashView » | Windows Azure - Getting Started » | Silverlight 2: MVVM, Databinding & Cascading Combo... » | Silverlight 2: MVVM, Databinding & Cascading Combo... » | Google App Engine - Tetris Challenge » | IIS, SSL and Host-Headers » 

Sunday, January 10, 2010 

Should you trust lastpass.com?

lastpass.com looks like a handy online service for storing all your website passwords. Browser extensions are available to make the whole process easier. If you use the web from several PCs it does sound nice to have all your passwords available and synced between your PCs.

First thought was wether I should hand over my passwords to the 3rd party, hopefully they are storing them with some serious crypto. Perusing their FAQ I found some info on this:

We only support keeping the encryption done on your computer so LastPass can't see your sensitive data
...your sensitive data is always encrypted and decrypted locally on your computer before being synchronized. Your master password never leaves your computer and your key never leaves your computer. No one at LastPass (or anywhere else) can decrypt your data without you giving up your password (we will never ask you for it). Your key is created by taking a SHA-256 hash of your password. When you login, we make a hash of your username concatenated with your password, and that hash is what's sent to verify if you can download your encrypted data.

So they are encrypting everything with a key derived from your password - plus they don't know your password - so they CANNOT access any of your passwords. Nice. But why stop there? Let's fire up fiddler to make sure they definitely don't have my passwords.

I've created a junk account on lastpass username: russell.sayers.junk@gmail.com, password: test1234 (the account will be gone by the time you read this!). The first form I see submitted to the server is when I create my account:

username russell.sayers.junk@gmail.com
hash 53c81a859a3f3d4dc3762d3a47bab07fad7ad3f2673724deb20fb420e8bdc03a
password ********
password2 ********
password_hinttesting
timezone2 +10:00,1
language2 en-US
agree on
agreeupload on
loglogins on
improve on
json 1

I don't see my password going to their servers in the clear. I can confirm that the hash getting sent is geniune by creating the same hash elsewhere via an online SHA256 generator, or writing some code myself. Try it yourself, the hash created is SHA256(SHA256(username + password) + password) - everything checks out. All the C# code to verify the encryption/hashing is at the end of the article.

The login form:

methodweb
hash53c81a859a3f3d4dc3762d3a47bab07fad7ad3f2673724deb20fb420e8bdc03a
usernamerussell.sayers.junk@gmail.com
encrypted_usernameT2tBleI3PxuLOoNEwNkv5PZ/rYr5dDIoYZS+We4vER4=
otp
gridresponse
trustlabel
uuid
sesameotp
emailrussell.sayers.junk@gmail.com
password

Again the same hash is being used to verify me when I login. I can see an encrypted username is being sent (although I'm not sure why?), rooting around in the javascript I can see the key being used for encyption is SHA(username+password). Importantly this is different to the hash being used to authenticate me - as we don't want the server to be able to decypt anything encypted by the client, i.e. they would have to know my password to derive the same key on their side.

The form to add a new website:

hasplugin0
extjs1
search
purgeext0
deleteext
undeleteext0
ajax1
ob
basic_auth0
isbookmark0
openid_url
aid0
useurid0
fromwebsite1
namepyJlY+AX0Aoczlx50hwlHg==
grouping
origurl
url66616365626f6f6b2e636f6d
usernameICkGIGAn7SIk16iKNkl3DA==
passworddl78FYUSIdsxxSdkBuBWEA==
extrafaESoIpzmCQg5PeHpXN0GQ==
We can see here the client is sending encyrypted versions of name, username, password, and the extra info. Again this is encrypted with a key we only have on our client - no one at lastpass could have this key. For some reason the URL is being sent in a HEX representation of the string - not sure why they aren't just sending the string?

So when I log back into lastpass, I can drill down into this entry and see it again. Let's make sure everything looks okay here. The HTML that renders this screen is available in fiddler:

<tr>
  <td class='col1'>Name</td>
  <td><input name='name' id='name' type='text' value='pyJlY+AX0Aoczlx50hwlHg==' style='width: 250px'></td>
</tr>
...
<tr>
  <td class='col1'>Username</td>
  <td><input name='username' id='idusername' type='text' value='SgVkuVKH4MjkP+Saz64UhA=='> </td>
</tr>
...
<tr>
  <td class='col1'>Notes</td>
  <td><textarea name='extra' id='extra' rows='6' cols='35'>1rZ3sSuggtdavyCu446GZA==</textarea></td>
</tr> 
The server is sending down our encrypted details, and relying on the client to decrypt everything.

So, yes - you CAN trust lastpass.com with your passwords! Don't just take my word for it; fire up Fiddler, and compare the hashed/encrypted values with what you expect.

Lastly the c# code to confirm the AES encrypted strings above are geniune.

static void Main(string[] args)
{
    string username = "russell.sayers.junk@gmail.com";
    string password = "test1234";
    string hash_auth = ByteArrayToHexString(SHA256(ByteArrayToHexString(SHA256(username+password)) + password));
    byte[] hash_key = SHA256(username + password);

    Console.WriteLine("hash for authentication => " + hash_auth);
    Console.WriteLine("hash for encryption => " +  ByteArrayToHexString(hash_key));
    Console.WriteLine("'{0}' encrypted => {1}", username, Encrypt(username, hash_key, ""));
    Console.WriteLine("'{0}' encrypted => {1}", "facebook", Encrypt("facebook", hash_key, ""));
    Console.WriteLine("'{0}' encrypted => {1}", "cryptolearner", Encrypt("cryptolearner", hash_key, ""));
    Console.WriteLine("'{0}' encrypted => {1}", "password", Encrypt("password", hash_key, ""));
    Console.WriteLine("'{0}' encrypted => {1}", "no notes", Encrypt("no notes", hash_key, ""));
}

static byte[] SHA256(string data)
{
    byte[] indata = Encoding.UTF8.GetBytes(data);
    SHA256 shaM = new SHA256Managed();
    return shaM.ComputeHash(indata);
}

/// <remarks>From http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/3928b8cb-3703-4672-8ccd-33718148d1e3</remarks>
static string ByteArrayToHexString(byte[] data)
{
    StringBuilder sb = new StringBuilder(data.Length * 2);
    foreach (byte b in data)
    {
        sb.AppendFormat("{0:x2}", b);
    }
    return sb.ToString();
}

/// <remarks>From http://stackoverflow.com/questions/1079131/c-aes-256-encryption</remarks>
static public string Encrypt(string plaintext, byte[] KeyBytes, string InitialVector)
{
    byte[] PlainTextBytes = Encoding.UTF8.GetBytes(plaintext);
    byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
    RijndaelManaged SymmetricKey = new RijndaelManaged();
    SymmetricKey.Mode = CipherMode.ECB;
    SymmetricKey.Padding = PaddingMode.PKCS7;
    ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes);
    MemoryStream MemStream = new MemoryStream();
    CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
    CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
    CryptoStream.FlushFinalBlock();
    byte[] CipherTextBytes = MemStream.ToArray();
    MemStream.Close();
    CryptoStream.Close();
    return Convert.ToBase64String(CipherTextBytes);
}

Labels:

Very nice, careful analysis. I've been using lastpass for my "throwaway" passwords, and was wondering how safe it is from the perspective of what gets sent to their servers.

Excellent analysis. But it only holds for the current release. What is to prevent a future LP client software update from installing a breach, such as surreptitiously sending name and password back to the server upon login? This possibility is why I only trust LP for low- and medium- security passwords(and use Keepass for high-security items).

Hi there,

Thanks for the excellent analysis - makes me feel more comfortable. Lastpass is a great concept.

I do have a question though - whilst your review does seem to prove that Lastpass never receives your master login password - which is great...how do we know that they havent added a second key to the encrypted data - ie a Lastpass master key that they hold? In other words both I can decrypt the data with my own key, and they can also use their masterkey?...which I dont even know exists?

Wouldnt checking that involve ensuring the encrypted data that they are sent is indeed only encrypted with one key? I assume the same data with a second key added would result in different data being sent once its encrypted.

If that occurred, then surely Lastpass would never need to know my password - they can simply use their master-password?

As I can log into their site and view my entire vault, then surely that means they have a full encrypted copy of all site and login details on their server. And if they had made sure that those details were encrypted with both my password and their master password, then surely they have the ability to decrypt my data if they want it?

In the bottom part of your post - is that what you did...did your own AES encryption of the data to ensure the encrypted version sent to Lastpass exactly matched what your encryption said the encryped data should be - ie checked that no extra master keys were added?

Also one more question: when I view my main vault at Lastpass.com, is the decryption all done locally, or am I viewing data thats being served up by their server? I would hope its decrypted locally!

Id appreciate your comments!

Richard (sir.richard_REMOVEME!!!_@gmail.com)

Hi Richard, yes you are correct that I want to demonstrate encrypting the same data myself to ensure LastPass isn't doing anything 'extra'. My post was looking at the lastpass website only, not any broswer plugin. With the website version we can see all the javascript code that is being used to do the encryption. So someone who is a bit more of an expert than me could review all the javascript involved.
Russ

I get that only the hashes of your username and password are ever used but what is there to prevent a replay attack. If the username and password always hash to the same value what is stopping someone for copying the hash value and sending it themselves? Surely some sort of timestamping or random number generation should be used in the hash?

Hi Dave, yes there isn't a timestamp/nonce involved in the hashed password. This is being sent over SSL so it would very hard to grab.
Russ

Ah that explains it, so unless you can grab the hash from the computer before its sent its pretty secure. And if you had enough access to the computer to get the hash you probably have a lot better ways of getting the passwords.

Anyone have anything to say about the second comment from top? "What is to prevent a future LP client software update from installing a breach"? Ultimately unless you are willing to perform this analysis on a daily basis you just have to trust that they will continue to do the right thing.

Hi I know this post is very old but I have a question.

You said: "Hi Dave, yes there isn't a timestamp/nonce involved in the hashed password. This is being sent over SSL so it would very hard to grab.
Russ"

But it's easy to grab for the developers. They could copy my hash and login into my vault, couldn't they?

@Anonymous re: the developers grabbing your hash. The hash you use to authenticate with doesn't decrypt your passwords. All your passwords are encrypted/decrypted client-side with the hash SHA(username+password), and you authenticate with the hash SHA256(SHA256(username + password) + password). The server authenticates you, and sends down your encrypted database - but has no way to decrypt your passwords.

Dave: you also have the ability of using the additional protection they offer with YubiKey and Google Authenticator.

Knowing the master password and userID then isn't enough to download the encrypted blob.

In the case of Yubikey, it adds an extra round of encryption so would seem to prevent decryption of the data if taken from the LastPass servers or the browser storage of the local machine, even if the master password was known or gleaned.

The title misses the point. The fact that we need to trust the company tells a lot. We shouldn't have to trust a host-proof service. There should be significant external evidence that your data is never compromised (either now or in future logins). Their website says "we do this, that and the other in order for us to not have access to your data" without external review. And we have to trust they actually do that. At least Clipperz seems to have more transparency wrt code review, etc. I personally think the whole idea of host-proof hosting (i.e. on the web, hosted by a single provider) is pretty much a red herring, and it seems like LastPass is just a company who jumped on that bandwagon in order to get a share of the pie in a booming market. I see very little innovation coming from these guys. If you give me a month (full-time, maybe less) and if I have the need and motivation for it, I will likely succeed in coding myself something similar (I currently have something different and more ambitious in mind).

What we really need is a standard and widespread protocol for storing encrypted data on a server (whatever it is) and retrieving it, and TRUSTED (as in FOSS and reviewed/signed by independent reviewers, and with no automatic update) clients (not websites).

Post a Comment