You are not logged in.
Pages: 1
Just a small post to ensure I haven't missed something obvious and I'm using everything "right"
The goal here is to establish a communication TCP channel, authenticated and encrypted by symmetric keys.
First data I send is a nonce of 16 bytes of random, followed by the HMAC_SHA256 of the connection key (implementation below) with the nonce as message. This is used to authenticate the client-side of the connection.
procedure HMAC_SHA256(const key : RawByteString; msgPtr : Pointer; msgLength : Integer; var result : TSHA256Digest);
var
i, n : Integer;
pad : array [0..31] of Byte;
sha : TSHA256;
firstPass : TSHA256Digest;
begin
n:=Length(key);
for i:=0 to n-1 do
pad[i]:=$36 xor Ord(key[i+1]);
for i:=n to High(pad) do
pad[i]:=$36;
sha.Init;
sha.Update(@pad, SizeOf(pad));
sha.Update(msgPtr, msgLength);
sha.Final(firstPass);
for i:=0 to n-1 do
pad[i]:=$5c xor Ord(key[i+1]);
for i:=n to High(pad) do
pad[i]:=$5c;
sha.Init;
sha.Update(@pad, SizeOf(pad));
sha.Update(@firstPass, SizeOf(firstPass));
sha.Final(Result);
end;
Then for the rest of the stream, I'm using a TAESCFB, where the key is the output of SHA256Weak of the connection key (in case the users entered a weak key).
The initialization vector is static, and the TAESCFB is created only once for the whole duration of the connection, *but* each message sent down the wire is pre-padded with 16 bytes of random (new random generated for each message), and those bytes are ignored on the other end. The messages themselves are made of compressed content followed by a simple CRC32.
The random bytes for nonce & padding come from CryptGenRandom, and are further XOR-ed by a weak random function based on RDTSC, QueryPerformanceCounter & GetTickCount (to minimize vulnerability to automated hacks in case a weakness in CryptGenRandom were to be uncovered).
Anything obvious I missed?
Last edited by Eric (2013-09-09 15:14:01)
Offline
Initial connection sounds right to me.
My only concern is during content connection.
If the key is always the same (i.e. SHA256Weak of a per-connection constant), it opens potential replay attack, or brute force.
I would rather change the AES cypher key for every request, adding a random nonce at the beginning of the stream, then using it as salt for every AES key computation.
But perhaps I've missed something.
Offline
I would rather change the AES cypher key for every request, adding a random nonce at the beginning of the stream, then using it as salt for every AES key computation.
I see, even though the first AES block of a message is always 100% new random, and that random carries over the rest of the message through CFB, a message is "correct" in isolation and thus can be replayed.
However, that raises another question, to avoid the replay, it means that the nonce must be provided by the other side of the communication channel? Ie. for a client to server message, the client would have to use a nonce provided by the server, and vice-versa? (otherwise unless the server caches recent nonces, the client could replay by reusing the same nonce?)
Offline
IMHO the nonce could be sent with the stream.
In mORMot we try avoid MIM replay attack as such (extracted from our SAD pdf):
In order to enhance security, the session_signature parameter will contain, encoded as 3 hexadecimal 32 bit cardinals:
- The Session ID (to retrieve the private key used for the signature);
- A Client Time Stamp (in 256 ms resolution) which must be greater or equal than the previous time stamp received;
- The URI signature, using the session private key, the user hashed password, and the supplied Client Time Stamp as source for its crc32 hashing algorithm.
At this level, a simple crc32 is used for the signature, but we may use a similar algorithm for data encryption.
Offline
Thanks. Client time stamp looks like a simple enough varying salt to validate.
I suppose some server-provided salt could also periodically be passed down to the client in the encrypted message to provide further strengthening.
What do you use for generating nonces in the field? The tests in mORMot use the Delphi Random function which is very weak and Randomize seeds exclusively on the machine time.
Offline
Yes, we do not use Random() in the mORMot.pas unit itself.
It is indeed too weak.
Random() is only used during the tests since it is very fast, and good enough for our testing purpose: in fact, I observed Random() has a similar entropy to real data, which makes it a good candidate for regression tests.
On Server side, we use a simple value derived from GetTickCount, which will be valid for about 5 minutes.
On Client side, TSQLRestServerAuthenticationDefault.ClientSetUser() uses SHA256(NowToString) which does a pretty good job.
I've just made stronger client-generated nonce for TSQLRestServerAuthenticationDefault - see http://synopse.info/fossil/info/13e2e69581 - but the client nonce is not meant to be very strong, and predictability is not a problem here.
Offline
I observed Random() has a similar entropy to real data
I've observed the opposite (http://delphitools.info/2011/12/13/pimp … -xorshift/)
On Server side, we use a simple value derived from GetTickCount, which will be valid for about 5 minutes.
What about using RDTSC? It's wildly varying, especially on machines with multiple processors.
On Client side, TSQLRestServerAuthenticationDefault.ClientSetUser() uses SHA256(NowToString) which does a pretty good job.
Wasn't the randomness of it quite low? There were only 86400 different hash values possible per day, and they are predictable long in advance.
I'm a bit wary of pseudo-random generated from time-based seeds at the millisecond level, since the machine time is usually known at that level of precision (these days, most machines are time-synchronized so they're typically within a second of the reference time).
While GetTickCount is a bit less predictable since it depends on the time the machine was last rebooted, it doesn't evolve very fast, and for Windows servers, you can make a good guess based on the latest critical windows updates release dates.
Anyway, my old quad-core CPU can f.i. compute 6 million SHA256 hashes per second with SynCrypto, that's enough to brute-force the whole 42 days range of GetTickCount-based salted hashes in about 10 minutes, and a GPU brute-forcers could scan the whole range in a matter of seconds.
I.FromNow;
inc(I.Value,GetTickCount+PtrUInt(Sender));
Given the above, since I.FromNow will be guessable, GetTickCount range is limited, so the PtrUInt(Sender) is the only portion that strengthens the nonce, but the range isn't that huge and similar values will occur between runs of the executable (since the TSQLRestClientURI instance size is rather large, there is a good change it'll be allocated from a highly-aligned sub-allocator block in the memory manager)
Last edited by Eric (2013-09-10 14:46:52)
Offline
I've observed the opposite (http://delphitools.info/2011/12/13/pimp … -xorshift/)
This was in the context of our random string generation functions.
What about using RDTSC? It's wildly varying, especially on machines with multiple processors.
No need of hardware depending high-resolution timer, since high resolution (minutes) is needed.
Wasn't the randomness of it quite low? There were only 86400 different hash values possible per day, and they are predictable long in advance.
Yes, but this is client-side hash, so it used as salt, not as key.
Anyway, my old quad-core CPU can f.i. compute 6 million SHA256 hashes per second with SynCrypto, that's enough to brute-force the whole 42 days range of GetTickCount-based salted hashes in about 10 minutes, and a GPU brute-forcers could scan the whole range in a matter of seconds.
... if you multiply by the network latency, I suppose you have much more time...
Given the above, since I.FromNow will be guessable, GetTickCount range is limited, so the PtrUInt(Sender) is the only portion that strengthens the nonce, but the range isn't that huge and similar values will occur between runs of the executable (since the TSQLRestClientURI instance size is rather large, there is a good change it'll be allocated from a highly-aligned sub-allocator block in the memory manager)
But this is still a client-defined nonce, so IMHO this is not the weakness of the algorithm.
Offline
Didn't you said on the server side that a value derived from GetTickCount is used as well?
... just to ensure that it will change within a minute-wide period...
Since it is used as salt, it should not break the security, or did I miss something?
Offline
I was under the impression that a known or predictable nonce / salt was as good as no salt from a brute-force hacking point of view, for the same reason that a salted password hash with SHA256 won't be enough to secure password shorter than 8-9 characters from a GPU brute-force crack if the salt is known and SHA256 is not applied thousands of times.
I've read that given the GPU perfs, an ASIC chip could likeley brute-force a salted hash password up to 10-12 characters passwords (numbers, upper and lower case characters and the common punctuation symbols) in a short time frame, and that this was the reason why even salted password databases were hacked these days.
But that may not apply to the situation here
Offline
Pages: 1