This can be solved using public-key cryptography:
- Generate a public/private key pair for each user; and only ever decrypt the private key temporarily with the user's password.
- For each data item, randomly choose a (symmetric) key S and encrypt the data d with it. Store S(d).
- Encrypt S with the the public key P+u of the user you want to grant access. Initially, that's the user u whose data you're storing.
- Store P+u(S) permanently. Forget all other keys.
Now, when a user u wants to share the data with the user x, do the following:
- Decrypt the user's private key P-u with the user's password.
- Using that private key, decrypt the stored data: P-u(P+u(S)) = S.
- Encrypt S with the public key of the user you want to share the information with.
- Store the resulting P+x(S) permanently. Forget all other keys.
Now, when any user x wants to access the data, perform the following process:
- Decrypt the user's private key P-x with the user's password.
- Find P+x(S). (If it's not stored, that means nobody shared the data with the poor user x).
- Using the private key, decrypt the stored data: P-x(P+x(S)) = S.
- Using S, decrypt the stored encrypted S(d): S(S(d)) = d.