The biggest flaw in this scheme is that it depends on javascript code that will be transmitted to the client by the (a) server.
So, what's to keep the server (or a man in the middle) to send the client modified javascript that circumvents all the security measures? How would the client, or, for that matter, the user ever know? All the code that you write to check fingerprints, checksums, digital signatures etc can likewise be circumvented.
A related problem is other, malicious javascript code running in your Browser that can't be reliably isolated from your security-related javascript code.
This is impossible to fix. In-Browser Javascript is currently not a secure platform and all browser client-side cryptography suffers from this gaping security hole that can't be closed.
Summary of the discussion in the comments regarding the updated question
Calculating pw = sha256(sha256(user_password)) strikes me as a bad idea for several reasons.
- The first one was already mentioned by AgentMe: Don't use simple hash functions such as sha-whatever to hash passwords. These hash functions were designed to be implemented efficiently in hardware and are much, much too fast; to hash passwords, you want slow hash functions. See AgentMe's answer.
- With this scheme, pw can be calculated if you know gk (which is just sha256(user_password)). So when someone steals your localstorage, you give him access both to the master encryption key and to the authentication/authorization token he needs to download the encrypted files. It would be better to keep the two secrets independent of each other, so if one is compromised by a third party, it's not enough to calculate the other one and break the confidentiality of the encrypted data.
- Finally, you're not salting your user_password with this scheme. This means that identical passwords across your whole userbase will yield identical hash values (and there are already large rainbow tables for unsalted sha-hashes out there containing the few million most common passwords).
You suggest an alternative, e.g. gk=sha256(user_password) and pw=sha128(user_password). While this solves point 2, it doesn't address 1 und 3. Also I wouldn't recommend it because I could imagine that this needlessly provides additional information to an attacker (the same password hashed to two different hash values), even though I don't know how to exploit it.
I suggested using gk=hmac(user_password, n) and pw=hmac(user_password, m), where m and n are known, but different for each user. How you arrive at m and n is irrelevant, as long as they're random and sufficiently large to make them unique across your user base with a high probability. You could create them on the client and submit them for storage at the server, indexed by the username so they can be retrieved on other clients. Or you can have the server generate them when the user first creates an account. The values don't need to be kept secure; they're worthless without the user_password. An improvement improvement would be to use gk=hmac(bcrypt(user_password), n) and pw=hmac(bcrypt(user_password), m) to make brute force attacks harder.
Now, I'm not convinced that this suggestion is a good idea, since hmac is designed for message authentication, not for creating authentication tokens or encryption keys, so I'd take that suggestion with a grain of salt. But it seems to solve all three points I raise, so it seems like a better solution than chaining the same hash function or using two different hash functions on the password.
gk
is stored in a cookie, it's also transmitted to the server - isn't this then enough for the server to decrypt the data?