Background: I have little knowledge of hashing and encryption, so please bear with me. I have posted a related question here: /mjbrxy/options-for-client-side-encryption-of-local-web-databases for the programming perspective, which may give some background. That question was about the general feasibility of the overall product. In a sense, this question is a follow-up, about the actual implementation, but as it is more technical on the security side I felt it would be better posted here. Feel free to post on either question/both questions as appropriate.
I have been tasked in securing local data for a web application that can be used offline, so interaction with the server for authentication and encryption is not an option. This would be optional, for users who would like an extra layer of protection on top of the hardware encryption.
The application will be for a single user per device. The goal is to try and reduce the risk of unauthorised access to sensitive data if a device is lost or stolen.
My initial ideas of how I could do this are:
The local data will be encrypted - however the encryption/decryption logic will be evident from looking at the JavaScript source code. So the key used to encrypt/decrypt cannot just be the stored, hashed password, as that would be obvious.
Q: How could this approach be improved? Would hashing the password in two different ways, one for storage, and one for encryption/decryption, be sufficient? Is there anything more that I could be doing, bearing in mind the limitations of working with web storage and without a server/external hardware to assist?
Also - although the user will be working offline with the application, so the data needs to be local and encrypted, there will be an initial connection to the server to actually download the application. So if there is anything I can do based on that initial connection that might help then let me know.
You are going about it wrong. There is no point at all to a hash for authentication if the comparisons are being done locally because an attacker can simply inject the hash value directly into memory and bypass the authentication check.
For local purposes, you have to use something like your second part of your idea, but that part should be done using existing standards. What you need is a key derivation function. A key derivation function is an algorithm that can securely take a password and use it to form an encryption key. Since the keys that are built are frequently relatively weak, it should be used to encrypt a truly random key which is then used for the actual encryption and decryption of the DB.
Using an encryption based approach, it becomes irrelevant if the user forces a key in to memory because they will be unable to access the encrypted data. The encryption itself acts as both the authentication and data protection mechanism. (If you want a way to verify proper decryption, you can always encrypt a known value and check the decryption of that value.)
Local articles referenced by this article: