Is this design of client side encryption secure?

I want to build a secure file storage web application. Users should be sure that server doesn't know how to decrypt files so encryption should take place at client side (i.e. in Javascript) and TLS will be used. Also public key cryptography is required as users should have possibility to send files to each other.

I plan to have encryption process like this:

SymmetricKeyAlgo(file, AssymetricPublicKey)


And decryption is:

SymmetricKeyAlgo(encFile, AssymetricPublicKey(EncryptedAssymetricPrivateKey, SlowS2K(password)))


where AssymetricPublicKey, encFile, EncryptedAssymetricPrivateKey are stored at server and all computations (encryption, decryption, hashing) are performed at client.

Output of AssymetricPublicKey(EncryptedAssymetricPrivateKey, SlowS2K(password)) has a prefix that is used to check whether password is valid. Prefix is fixed and is the same for all messages. It's truncated before supplying output to SymmetricKeyAlgo.

It seems that similar scheme is used by OpenPGP.

I know that there are existing OpenPGP implementations in Javascript but they are very large and not widely-used. I feel that it will be better to use more trustworthy cryptographic primitives supplied by SJCL (AES, PKDF2, key generation). But I haven't found trustworthy asymmetric encryption library.

Is this design right? Or should I use full OpenPGP for my purposes? Is there anything else I should think about?

Edit: Public keys aren't secret and can be sent to anyone. Every user has unique username. When Bob wants to send file to Alice, he sends Alice's username to server, server maps this username to public key and returns it to client. Thus Mallory can't trick Bob to send file to her instead of Alice.

-

It sounds like you're trying to set up a "host-proof" system. ( How can one share information using the 'host-proof' paradigm? ; Encryption scheme for social-network-like data sharing data via untrusted server? ; etc. ). Sounds like a fascinating problem.

I'm assuming you're trying to set things up so that no data is stored on the client -- not even encrypted. (That makes things much more difficult, compared to storing the user's private key on the user's client).

encrypted public keys

All the asymmetric systems I've been involved in are careful to generate the private key inside one box and never, ever let that key outside the box, even in encrypted form.

So I'm a little uncomfortable with storing the (encrypted) private key on the server. However, I'm almost convinced that is excessive paranoia -- several people I respect seem to think it's OK to let a encrypted form of that private key outside the box -- a private key encrypted using a well-vetted algorithm such as AES, encrypted using a key generated from some key-stretching KDF (S2K) such as scrypt or PKDF2, giving the KDF a long passphrase. (Perhaps What is the harm if I publish an encrypted RSA private key publicly? is a better place to talk about encrypted private keys, and How can one securely generate an asymmetric key pair from a short passphrase? is a better place for comparing "encrypted private keys" to the various other ways of obtaining a private key from a passphrase).

message authentication

You may want to add some sort of message authentication code (MAC) or digital signature to the data. After you do that, there's really no need for another process to check whether the password (or the key generated from it) is valid (see Sending KCV (key check value) with cipher text , Can I determine if a user has the wrong symmetric encryption key? ).

So your server blindly sends (encrypted) files to any person who requests them? Then the local client does the check to see if the password(s) that person has are valid are performed locally? I suspect there may be a better way of handling this. Perhaps some sort of zero-knowledge challenge-response protocol?

protocol

So when Bob wants to send a message to Alice,

• Bob types up his message on his own local machine.
• Bob somehow obtains that Alice's public encryption key. (This can be a tricky -- how do you keep Charley from tricking Bob into using Charley's public encryption key?).
• Bob encrypts his message with Alice's public encryption key (locally), and then sends the encrypted file to your server
• Later, Alice pulls a bunch of files from your server:
• her encrypted private key
• the file Bob posted
• some client code. (This is the really tricky bit -- is there any way for Alice to confirm that this code hasn't been maliciously modified, either modified in-flight while it's being transferred from your host to Alice's machine, or worse -- modified by some malicious attacker who has compromised your host?)
• (optional) Alice unplugs her local machine from the Internet
• Alice types in her passphrase on her local machine into your client code.
• The client code runs Alice's passphrase through a slow KDF to get a (symmetric) key, then uses that (symmetric) key to decrypt her private key, and then uses that private key to decrypt Bob's file. (Typically there's yet another file-specific symmetric key involved in that decryption).
• Finally, Alice reads the message Bob typed.