Is RSA Privatekey and Publickeys what I need...

Started by
14 comments, last by ankhd 8 years, 8 months ago

Hi all.

I'm looking into ways clients can send there password to the server, And its looking like a good bet is RSA.

I was thinking that the clients can encrypt there password with the publickey then send that over the wire.

Q1.That will be safe from anyone but the holder of the private key.

Problem 1. I'm using cryptoPP and when you create a key pair you specify the key size.

Q2.This seams to limit the size of the message you can encrypt based on key size So if you create it say 2048 does that matter too much or should that be kept under 1024 bytes.

Q3.The Publickey can then be shipped with the app is this the norm.

this is a bit of code so far I can create the 2 keys and encrypt and decrypt

.


//rsa private an a public key so users can encrypt the pass but no one can unencrypt
	CryptoPP::AutoSeededRandomPool rnd;
	CryptoPP::RSA::PrivateKey privKey;

	//For demonstration purposes, the program below will use a 64 bit modulus. The modulus is artificially small, and the parameters were generated with the following program
	privKey.GenerateRandomWithKeySize(rnd, 1024);
	CryptoPP::RSA::PublicKey pubKey(privKey);

//Its always a good idea to validate any loaded keys. The code below validates the private and public keys at level 3, 
	//which is most thorough (for a full discussion, see Keys and Formats). The check on the public key is redundant since 
	//the private key is validated. It is shown for completeness
	if(!privKey.Validate(rnd, 3))
		std::cout << "Rsa private key validation failed" << std::endl;

	if(!pubKey.Validate(rnd, 3))
		std::cout << "Rsa public key validation failed" << std::endl;

	//Next, we want to encrypt the string "secret". In RSA, encryption is simply c = me. So our task is to encode the string as an Integer in preparation for encryption. To accomplish the encoding, we perform the following. (See this example in one file)
	std::string message = "secret Dont tell any one this is a long message to see if its going to work so now I dont";// have a job I will worrk on thi9s staff all day to learn and do my game";
	CryptoPP::Integer m((const byte *)message.data(), message.size()); 

	//After the above, m (the word secret) is encoded as an integer. We can use C++'s insertion operator to inspect m:
	std::cout << "m: " << m << std::endl;
	//m: 736563726574h 

	//At this point, we have n, e, d and m. To encrypt m, we perform the following. 
	CryptoPP::Integer c = pubKey.ApplyFunction(m);
	std::cout << "c: " << std::hex << c << std::endl;
	//c: 3f47c32e8e17e291h 


	//ApplyFunction is the 'easy to compute' transformation. If we look at rsa.cpp near line 65, we see the RSA class performs the expected exponentiation.
	// Decryption 


	CryptoPP::AutoSeededRandomPool prng; 

	CryptoPP::Integer r = privKey.CalculateInverse(prng, c); 
	
	std::cout << "r: " << std::hex << r << std::endl; 

	// r: 736563726574h 
	std::string recovered; 

	recovered.resize(r.MinEncodedSize()); 

	r.Encode((byte *)recovered.data(), recovered.size()); 


std::ostringstream os;
    os << r;    
	std::string sendinteger = os.str();

	std::cout << "recovered: " << recovered << std::endl; 
	std::cout << "os recovered: " << sendinteger << std::endl; 


Advertisement
1) What kind of attack are you trying to prevent?

2) Typically, the client will create a strong random cryptographic key of size 32-64 bits, encrypt it with the public key of the server, and send this key to the server. The rest of the connection is then encrypted with this key using symmetric cypher. Thus, the size of the payload shouldn't matter.

3) Yes, it's not uncommon to have a private key on the server and a public key on the client. In fact, HTTPS in web browsers work approximately that way. (Because you can connect to unknown servers, the public key is actually downloaded, and then verified with a signature, rather than hard-coded.)

4) If it's actually important that you solve this problem, I suggest you use an existing TLS library, rather than rolling your own over CryptoPP. CryptoPP is a great library (and someone should implement a shallow TLS wrapper on top of it!) but there are so many other things in key management and initialization vectors and known plaintexts and such, that getting the entire end-to-end system right is really hard.

5) See 1) -- what attack are you really trying to prevent here, and how much is it worth to actually prevent such an attack (rather than just thinking you kind-of have a slightly higher fence?)
enum Bool { True, False, FileNotFound };

Don't send passwords over the line, whether encrypted or not. Hash the password on the client, send the hash (encrypted if you wish) then compare the hash with a stored hash on the server. That way the server doesn't need to store passwords in plain text either.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Don't send passwords over the line, whether encrypted or not. Hash the password on the client, send the hash (encrypted if you wish) then compare the hash with a stored hash on the server. That way the server doesn't need to store passwords in plain text either.

This is very good advice and I remember reading last week a thread very close to this one discussing some of the finer points to securing the connection between your game and the game server. Also if you can when you hash the password make sure to add in a salt value to change the password just enough that someone can't use a dictionary attack against your accounts. Hashes are very fast to create which is why many systems like to use them but adding in a salt that isn't stored with the hash of the password will also help increase your security.

If you want to really paranoid then you would create a different salt for each account and store that data in a very secure location that is separate from your account database.

Hey all.

1) What kind of attack are you trying to prevent?

middle man sniffing passwords only.

My next question was going to be should I also Hash the password on the client. I take it we do.

Ther server will send the client the Public key, Salt and a IV in case I want to change the encryption later(support layered encryption if needed).

4) If it's actually important that you solve this problem, I suggest you use an existing TLS library

Heading towards this but need to do baby sets first, It's taken nearly 2 weeks to get to this point.

If you want to really paranoid then you would create a different salt for each account and store that data in a very secure location that is separate from your account database.

Yes I have taken the blue pill I am total paranoid now, Especially now after a group of people gained access to someones car remotely.

They cant decrypt the hash with the salt its oneway only. The Salt can stay in the same area as hashed password. same with IV(Not sure On IV).

For some reason when setting key like this privKey.GenerateRandomWithKeySize(rnd, 1024); in my code limits the amount of data you can encrypt.

But the tutorials load files with there same set up but they use 4048 or I've seen 2048 as key sizes, they never talk about the size limit.

there is a limit the keys and data make up the system and to large of a message and the key will lose precision.

This is fine its only going to be password when hashed will not be more then 256 bytes.

The problem with not using ssl at the moment is that my protocol is a message system I created with google protocols. The more I read about HTTP is its sort of like my system anyway, all I would need to work out is to do the packet sending for the hand shake and reading cert data and passing it back to server. I can see why people say use HTTP. I having fun any way.

Alas though reading up on this I found a hole in my server login area, where a spammer could keep sending hand shakes, I will set up the messagemonitor system to take IPs of connecting clients and delay the connection if to many attempt(ON the TODO list).

Don't send passwords over the line, whether encrypted or not. Hash the password on the client, send the hash (encrypted if you wish) then compare the hash with a stored hash on the server. That way the server doesn't need to store passwords in plain text either.


That doesn't work -- someone who breaks into your server, and extracts the hash, then knows exactly what data to send you to log in for each user. That's no better than storing the passwords in cleartext.

Separately, someone who sniffs the wire will also be able to log into your server as the sniffed user, because they know what to send to the server. Unless you also use a random challenge for each login attempt, but then you need to store clear-text passwords on the server.


Really, the safest "standard operating procedure" is:

1) Use HTTPS or an existing TLS library to communicate login information.
2) Use a secret server key / certificate, and ship the public certifiate/key to the client.
3) Send the password cleartext that the user entered to the server. memset() the buffer that contains the password to 0 after you do, so it's not left in RAM. (Also, if you use a password input control, be sure to reset its text value to XXXXXXXXXXXXXXXXXXXX and then to empty.)
4) On the server, use scrypt() or bcrypt() with a reasonable number of generations/iterations/load value.
5) On successful auth, return a randomly generated unique session token to the user to use for future authentication. This is like a session cookie for web browsers.
6) If you need to use UDP for gameplay, also send a "ephemeral player id" and a "player session key" to the client, and use some in-memory database to store ephemeral player id to session key and token. The player's packets will then contain <player-id> + encrypt(<session-token> + <data>, <session-key>) + hmac(<player-id> + <encrypted-data>, <session-key>)
enum Bool { True, False, FileNotFound };

memset() the buffer that contains the password to 0 after you do, so it's not left in RAM

That was my first idea when designing key class fill the values with junk on destruction, but you did remind me to do that on the editbox the user types password in.ph34r.png

That doesn't work -- someone who breaks into your server, and extracts the hash, then knows exactly what data to send you to log in for each user. That's no better than storing the passwords in cleartext.


I think the main point of this suggestion is so that the server never receives plain passwords which may be associated with the same user elsewhere. This should even not be a concern since users are not meant to reuse the same password in multiple places, unfortunately the reality is far from that (but then again, if I had my way everyone would be using password managers or similar with a single 80-bit master secret generated at random and engraved into their memory, which is actually not that hard to remember if you spend a few minutes learning it).

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Don't send passwords over the line, whether encrypted or not. Hash the password on the client, send the hash (encrypted if you wish) then compare the hash with a stored hash on the server.

What I got from that was the client has a personal Salt that the app hashes with there password then sends to server where it hashes the password with the salt and saves double hashed + salt to database.

All that plus the public encryption should do for the password.

And as for the Key size thats all about.

When choosing a bit size, current best practices (from NIST) dictates we use a security level of 128 (80 and 112 bits of security should not be used in new systems). This means we should use an RSA modulus size of 3072 bits. This also means that a DSS version 1 or version 2 DSA key pairs are too weak to satisfy contemporary security requirements (a 1024 bit DSA key offers about 80 ideal bits of security).

In the code below, we create an RSA key of 3072 bits, and a DSA key of 1024 bits (per DSS Version 2). AutoSeededRandomPool is a PGP Random Pool-like generator. If you need more security in a generator, use an X917RNG (from ANSI 9.17 Appendix C and based on DES) or AutoSeededX917RNG based on the AES block cipher.

Read this a few time and only now find it. Are they crazy 3072 for a key size make the.

Public key 840 bytes

Private Key 3582 bytes that can be bigger

Signature for signing 3072 bytes this ones the killer.

What the quantum computer can't crack this.

Size's For Keys with 1024

Public Key 320

Private Key 1264

Signature 256

Edit These values are after the CryptoPP::HexEncoder bloats them convert back reduces there size

Public Key was 840 after HexDecoder its half 420

What I got from that was the client has a personal Salt that the app hashes with there password then sends to server where it hashes the password with the salt and saves double hashed + salt to database.


What if the user wants to log in from another computer -- how does that "private" salt get put on the next computer?
(Or if the user re-installs, or wants to use a cell phone, or ...)

These values are after the CryptoPP::HexEncoder bloats them


It kind-of doesn't matter how big they are. You pre-install the public key (or you download it once.) You then use this to come up with a 256-bit (32 bytes) symmetric encryption key, which you actually use for all bulk data.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement