I've built an API that allows users to submit encrypted data to be stored in the cloud. To retrieve their data, the API requires the user to supply only the MongoDB Object ID that they are given when intially submitted their data, plus the SHA1 hash of the password they used to encrypt the data. I chose to use both the Object ID and the password hash as a unique key to prevent users requesting any data over the API, as different Object IDs are not complex and easy to guess.
I've now switched the hash method from SHA1 to bcrypt as it is more secure, but that has presented an issue. Because bcrypt generates a different salt every time, the hash is always different meaning I can no longer use the generated hash to identify the user's data in the database, unless I force the app to use the same salt each time it generates a bcrypt hash. Note: if I use a constant salt, it will be known to the public as the source code is open source.
My question is, if I use a constant salt with bcrypt for generating password hashes, does this make the hashes easier to decrypt than using SHA1 as I was originally, and if not is it still an impractical approach to creating secure password hashes?
Alternatively, is there a better approach for specifying a unique key for the user's data in the db without asking the user for more information?
Edit: In trying to keep the question as simple as possible, I've realised that I haven't really provided enough context for why I chose the approach I have, so here's a little more information to hopefully mae things clearer and so that people can provide as accurate as possible an answer.
The intention is to create a secure and anonymous service to support the app, that can be run by anyone, anywhere. The app and API are open source and so anyone who wishes to provide their server space for other users of the app can run their own instance of the API. Users of the app can then point it at the API url of their choice, this allows them to use any public-hosted instance of the API, or even host an instance on their own server which only they can use.
Because user's data could be sitting on any public server, it is important that the data is encrypted client-side and that the user never sends their cleartext password over the wire, in case the API server owner (or anyone else) wishes to decrypt the user data being hosted. The service is anonymous for reasons of security and convenience, hence the app user does not have to provide an email address or any other identifying information, they just click a button in the app and their data is encrypted with their password, which is sent to the API along with their hashed password:
Post body example:
{
"data":"DWCx6wR9ggPqPRrhU4O4oLN5P09onApoAULX4Xt+ckxswtFNH/QQ+Y/RgxdU+8+8/muo4jo/jKnHssSezvjq6aPvYK+EAzAoRmXenAgUwHOjbiAXFqF8gScbbuLRlF0MsTKn/puIyFnvJd...",
"passwordHash":"d4de34f15aeadfb34bdf1fbbd57134b2baeb142c"
}
Response:
{
"id":"507f191e810c19729de860ea",
"lastUpdated":"2016-07-06T12:43:16.866Z"
}
The mongodb entry would look like this:
{
"id": "507f191e810c19729de860ea",
"passwordHash": "d4de34f15aeadfb34bdf1fbbd57134b2baeb142c",
"data": "DWCx6wR9ggPqPRrhU4O4oLN5P09onApoAULX4Xt+ckxswtFNH/QQ+Y/RgxdU+8+8/muo4jo/jKnHssSezvjq6aPvYK+EAzAoRmXenAgUwHOjbiAXFqF8gScbbuLRlF0MsTKn/puIyFnvJd...",
"lastUpdated": "2016-07-06T12:43:16.866Z"
}
A user can retrieve their data with a GET request to /api/data/{id}/{passwordHash}
, so for the example above:
/api/data/507f191e810c19729de860ea/d4de34f15aeadfb34bdf1fbbd57134b2baeb142c
Response:
{
"data":"DWCx6wR9ggPqPRrhU4O4oLN5P09onApoAULX4Xt+ckxswtFNH/QQ+Y/RgxdU+8+8/muo4jo/jKnHssSezvjq6aPvYK+EAzAoRmXenAgUwHOjbiAXFqF8gScbbuLRlF0MsTKn/puIyFnvJd...",
"lastUpdated":"2016-07-06T12:43:16.866Z"
}
Since the id value (MongoDB object ID) is not overly complex, a malicious user can potentially guess someone elses id and retrieve their data over the API. For that reason I decided to use the id along with the user's password hash as the key to make it more difficult for a malicious user to guess someone else's unique key. However, if I only used the object id as the key and even if they could guess another user's id, they would only retrieve their encrypted data (not the password hash), which they would then need to decrypt before reading the data. Would this be a better alternative to storing the password hash? Ironically, this would then answer the bcrypt problem as if I were not storing the password hashes on the server, I would not need to hash the password (used to encrypt the data client-side) at all...
So in conclusion, the question as it relates to my app/api is a lot more complex than the question let's on, but I couldn't really think as to how to frame it properly (perhaps I need to change the question). However, if anyone has any opinions on the security aspects of my approach given the requirements, I'd be very grateful for the input.