What is required to store for recognizing the machine securely?
I assume you meant reasonably uniquely and reliably - in which case, this is a hard problem. Made harder by the fact that any web application does not have access to the underlying hardware - just transient information such as browser version and IP address. Yes - you can get a lot of information about a system, e.g. as panopticlick does, but that information is changeable on demand.
Moreover, any of these metrics can change. Using CPUID? What happens if the end-user upgrades their processor? Your "trusted device" status disappears. That might be acceptable, or it might not - think Windows Activation.
In any case, in order to protect against token interception, MITM, replay and all other nasties of this sort, you absolutely must use SSL for this channel which brings me to:
He will still have to log in using password + username, however, he can ONLY log in from given machine.
This sounds like a use case for SSL client certificates, in my mind. The usual logic looks like this:
- Ask the browser for a client certificate.
- If you get one, check that cert, find the user DB etc and log the user in.
- Otherwise display the user login page.
I think what you're asking for, however, is a variation, in which if you find the certificate you present a login form and otherwise you display a 403.
That deals with the authentication side of things quite nicely. It also alleviates the need to store unique machine IDs and all the problems of generating them - although you could do so alongside this if you wished - and allows the user to designate trusted devices just by installing the certificate.
Can I safely store an encryption key (private) on the machine, so the user, doesn't need to input it when uploading data etc.?
Well, you've never got any guarantee of client side security on the web. You simply have to trust users are looking after their credentials.
The same goes for cookies. Remember, users may do all sorts of things to cookies, including clean them up unexpectedly. If you're building a web app and intend to do client-side crypto in JS, and you lose that key, the user is going to lose their data.
The alternatives are:
- Encrypt the data on the server. As you've probably guessed, this means anyone with access to the server can get at that data - and no protection you put in place will help.
- Encrypt the data on the client outside the browser, where storage is more reliable. When I say "outside the browser", I mean via a mechanism with proper persistent storage that is not cookies.
- Wait for homomorphic encryption.
- Design a way of extracting the key from the cookie and ensure your users can re-input it again as necessary.
Generally speaking, the standard advice for cookies (this includes your session cookies) over https is to use secure and httponly flags so that XSS does not work and the cookie does not leak.