Authentication/Decryption using a subset of Key - cryptography

Is there a cryptographic system where a user(s) can be authenticated (or they can unlock a document) only if they present a subset, of more than one, the of valid keys?
Thanks in advance.

Non-anonymous authentication
If you don't require the users contributing to the successful authentication to remain anonymous, it's easy: The server generates a random nonce and sends it to the subset of users. Each user signs the nonce with his/her private signature key and sends the signature to the server. The server verifies each signature and if enough of them are present then the subset has successfully authenticated.
(Anonymous) Decryption
Someone else here might know of an RFC or a library for that purpose, but If there is none, I would design it like this: Split the secret into n parts where k of them are necessary to recreate the secret using Shamir's Secret Sharing. For each of the n users encrypt a different part of the split up secret with his/her public encryption key. When k of them decrypt their part of the split up secret, they can recreate the secret.
If the public key encryption is deterministic you can even make it anonymous in the sense that if you can get to the secret you can check that each other subset of k users would also be able to get the secret: In preparation of the protocol run you also have to designate a fixed x-coordinate for each user in addition to the public encryption key. When a subset of users successfully recreated the secret and thus the polynomial, they can evaluate it at each of the users x-coordinate and encrypt it with their public key. If the result is identical to those generated by the server, every subset of k users can decrypt the secret.
(Note that deterministic encryption has some caveats. For example, if the plaintext space is small, an attacker can just encrypt each plaintext and compare the result to the given ciphertext.)
Corollary: Anonymous authentication
Using the anonymous decryption you can create an anonymous authentication protocol by having the server encrypt a random nonce for k out of n people in the way described above and send it to the subset of users. They decrypt the nonce, check that each subset of k users would also be able to decrypt it and send the nonce back to the server.

Related

How to store encryption key?

I look out many password managers like keeper, 1password, secret-in and I am following secret-in password manager to create my own project and trying to add same features, but got stuck at storing the data of users like his/her secrets, payment secrets in encrypted form. I read encryption model of keeper here but still didn't understand. Where to store a server side encryption key?
I have some data that is symmetrically encrypted with a single key in my database. Rather than hard coding it into my code, I am looking for a safer way to store the encryption key. Where can I safely store it?
The approach here is quite simple.
You only send encrypted data to the server for storage/backup.
The encrypted data received doesn't come with a key.
You need to ensure all encryption and decryption occurs locally on the users device. Thus the user needs to supply the key.
Users aren't good at providing high quality key material, so instead, require the user to provide a password, take that password and pass it through a hash-based key derivation function with parameters that make the function slow (high ops, high mem requirements). An algorithm like pbkdf2 with a strong PRF like HMAC-SHA-2 should be sufficient.
Update:
To answer your specific questions, you need to perform the following steps, you will need to use a cryptographic library that supports key derivation from password and symmetric encryption, like libsodium.
request password from user on first use
run this password through key derivation to derive a key from it: https://libsodium.gitbook.io/doc/key_derivation
execute encryption of user data with key: https://libsodium.gitbook.io/doc/secret-key_cryptography
destroy the key and send data to server for backup

Handle user login using asymmetric cryptography

Is it possible to implement a login protocol with asymetric cryptography instead of the hashed password method?
For example, while creating an account, the client generates a private/public key pair from a hash of the username and password. The public key is then sent to the server with the username, and the server stores the username and the public key. When the user wants to login, he enters his password, the client regenerates the private key, signs a nonce with it, and sends the signed message to the server. The server is then able to authenticate the user as he knows the public key associated with the username.
Is there any flaws in this protocol?
And what would be the advantages over storing the password hash?
There might be a serious flaw with the authentication, yes, depending on the implementation. If Bob is the server and Alice is the client, with Mallory a malicious eavesdropper:
If Alice generates a random number, concatenates this with her username, encrypts with her private key and sends to server. Server decrypts and verifies with Alice's public key. Without the server saving the random number, this is susceptible to replay attacks - Mallory could just listen in, save the blocks that Alice sends to the server and just replay them later. Without saving them, the server would be none the wiser.
To protect the server against this, the server would have to generate the random number. It would also need to be a secure random number, otherwise Mallory could predict, or at least guess what the next number will be.
If Mallory could intercept messages, then he can purport to be Alice - he intercepts all communications and just relays them, even if the server generates the random number.
Alice and Bob both need to be able to prove that it was the other who has cheated. They also need to be able to detect tampering from Mallory - the protocol needs some extra layers to ensure authenticity of the messages.
There is research going into this at the moment, but as far as I know, it is very difficult to authenticate a user without a trusted certificate authority also being used: public keys can be known by all, but any attacker can swap their own public key for that of another without detection, unless there is trust established through a certificate authority.

how to store a password in webapp that needs to be passed in plain text to a third party?

I have a simple webapp which users login to access to a third party API that also require their personal credential in plain text username and password (no OAuth or anything). What's a proper, safe-ish, and straightforward way to store these third-party passwords so I can decrypt them to plain text when needed and minimise leakage of these passwords?
I'm thinking of just hardcoding GPG keys in to encrypt in webapp for storage and decrypt from another machine behind firewall when needed.
I don't think this is a GPG-specific problem. You could think of a scheme like the following (no need for public key crypto):
Generate a random password to encrypt the plaintext credentials you want to protect
Derive a key to protect this random password from the user's password
Encrypt the password from step 1 with the password from step 2
Now you can access the protected credentials after the user has logged in (since you know the password the user entered). When the user changes his password, you only have to re-encrypt the key from step 1 (in case you use this key in multiple places; so you can't miss one).
For step 2, you should use some (slow) key derivation function like PBKDF2. This makes sure that in case of a security breach, a simple dictionary attack on the encrypted credentials is not possible.

Use Authentication using 2 encrypted strings

so basically I am trying to log user in with a cookie and do not query DB to improve performance
here is a brief idea:
transmit everything via SSL
set a Global secret key A and secret key B
generate a random verification string on registration and password change
encrypt the verification string with A, store it in cookie
encrypt the verification string with B, store it in cookie
when user tries to login, I decrypt each string with A and B, compare if they match
I am wondering if it is a good idea
if it is:
how can I actually do the encryption in Java, using bouncycastle ASE-256, Digest or whatever?
how much does this encryption/decryption process affect the performance, when compared with authentication by storing a session variable in a super fast DB like Redis
if it is not:
what should I do..
You can simply encrypt a known value together with the authentication data, when you decrypt verify that the data is present in the authentication token (the cookie). No need to use two keys.
The speed difference with a database depends on the database configuration as well as the cryptography that is performed. I would rather opt for a proven scheme first and only invent your ownif performance leaves you no other choice.
Schemes as better verified on http://security.stackexchange.com.

Hashing passwords before sending to server

When sending passwords via UTF-8 encoded socket transfer, is it considered to be secure if I hash the password using either MD5 or SHA-1 prior to sending out the data? Keep in mind that I plan to compare the hashed password in a SQL database. I am worried that someone could be able to sniff the hashed password in UTF-8 then decrypt the UTF-8 encoding and could obtain my hashed password which could potentially be used to match the password in my database.
If the client just sends the hashed password, then the hashed password is the "password": a sequence of bytes which the client just needs to show to be authenticated. If the attacker can sniff that then your protocol is doomed.
If the authentication protocol consists in just presenting a piece of secret data (call it a password if you wish), then the exchange should occur within a transport medium which ensures confidentiality (so that the secret data cannot be sniffed) and server authentication (so that an attacker may not mimic a server and convince a client to send him the secret data). This is what you get out of a classic SSL/TLS tunnel (a https:// URL, in a Web context).
If you cannot establish a SSL/TLS tunnel with server authentication (i.e. the server has a certificate which the client can verify), then you may want to resort to an authentication protocol with a challenge: the server sends a sequence of random bytes (the challenge) and the client responds with a hash value computed over the concatenation of the password and the challenge. Do not try this at home! It is very difficult to do it right, especially when the attacker can intercept communications (active attacks).
A more generic answer is password-authenticated key exchange protocols. PAKE combines a cryptographic key agreement protocol (such as Diffie-Hellman) and mutual password authentication between client and server, in a way which defeats both passive and active attackers, even with relatively weak passwords (the attacker cannot get enough data to "try" passwords without interacting with either the client or the server for each guess). Unfortunately, few PAKE algorithms have been standardized beyond mathematical description, and the area is a patent minefield.
Well, if someone can sniff hash - he can fake authorization request and send the hash he already know.
Making up secure system is not easy, you would need to do authorization using asymmetric cryptography with properly signed keys to make it secure.
At least add ~100byte random salt, and use SHA1 - this way it would be way harder to bruteforce.
They could brute-force your passwords if they know the hashing algorithm. The simple (and not perfectly secure) solution is to use a challenge/response instead, the server issues a random string ("nonce") to be hashed along with the password hash. This makes your app invulnerable to the kind of replay attacks you're describing.
For more information, see HTTP's digest access authentication
Hm, if you are talking about 'proper' hashing, that means that it will 'encrypt' your password so it won't be decrypt-able, because hashing is one way function, and to decrypt it - it till take some time, and some kind of great CPU power.
If you are concerned at password sniffers, you can take it to the next level - use PRIVATE/PUBLIC key encryption. Server should send a challenge to the client (public key for encryption), client encrypts with it, and only server know how to decrypt it. For same amount of bits, it offers more protection - ie. more muscle is needed to brute force crack it.
Check this out.
How do you check the password on the database side?
If you store the unsalted hash of the password and just compare it to the input, then the hashed password can be sniffed and reused.
It's exactly as if you were storing the password itself in the database in plain text.
If you are afraid of sniffing, use a challenge-response protocol to authenticate, but in this case the secret will be stored in the database (and will be known to anyone who has access to the database).
Alternatively, you can send a password in plain text over a protected channel (SSL), but you will have to install a certificate which will most probably cost you some money (if you are using an authority from a vendor-provided list, i. e. one your customers' browsers won't complain about)