I have a local server and I'm dissecting my server's input SSL/TLS packets captured by the NIC. As you know, in the TLS handshake process, after the ClientHello and ServerHello messages (server hello + certificate + verification of certificate by client) are sent, the client will send a ClientKeyExchange message which includes the Encrypted Pre-master Secret used by server to generate the session master key. As the RFC says, the formula for generating the master key is:
master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random) [0..47];
Also the random numbers are 32 bytes randoms which had been exchanged during the ClientHello and ServerHello messages.
My questions are:
Which function of OpenSSL can I use to get the master secret?
What is the PRF in my session?
For decrypting the 'Encrypted Pre-Master Key' (which my server's private key is going to be used) what is the decryption algorithm? Is it the key exchange algorithm mentioned in selected cipher suite by server in server hello message? (e.g. in TLS_DH_RSA_WITH_AES_128_CBC_SHA cipher suite the key exchange algorithm is Diffie-Hellman).
If it is, what is the function in OpenSSL library which inputs the key exchange algorithm, private key, encrypted_bufferand outputs the decrypted buffer? (I have used theEVP_openInit()andEVP_DecryptInit()functions, but inEVP_openInit()` the problem is that it inputs the encrypted key and after decrypting it by the private key, it will use this key for decrypting the encrypted data which it shouldn't. It should genearte the master key before that, not use the pre-master key as the session key.
Is the summation of two randoms like:
uint8_t sum[32];
for(int i=0; i<32; ++i)
sum[i] = ClientHello.random[i] + ServerHello.random[i];
If it is, aren't overflows considered?
Related
I've been tasked with creating a custom SNMP agent, and one of the things I need to do is manually encrypt the response I'm sending back.
To do so, I'd ideally like to send back a custom set of varBinds based on the get command, like so:
response = [(varBinds[0][0], v2c.OctetString(b'127.0.0.4')),
(varBinds[0][0], v2c.OctetString((sal+signature+iv+encryptor.tag+cipher_text)))]
Where I'd send the salt, signature, IV, tag and ciphered text (all in bytes) and could manage to
decrypt on the other side (a symmetric key is used), but I can't seem to obtain the same result when on the other side I use the following:
msg = bytes(vars[1][1])
How can I get back exactly the bytes I sent in the OctetString from the agent? Something does misformat in the way I'm decoding, because the bytes I get back are not the same I sent.
Edit: the bytestring does work flawlessly, the bytes on the second variable don't.
Thank you very much for any help :)
So the problem is:
1) There is a plaintext string "Hello"
2) A encrypts it with their private key
3) B encrypts it with its private key
4) There must be a way to confirm that both encrypted messages are result of same information.
So if I have A's encrypted message and B's encrypted message, I can tell this is same encrypted info without getting original message.
An example:
A buys a message from B. A has encrypted information, and when he receives message encrypted with A's public key, he want's to be sure, that B doesn't lie to him and actually sends information, which is firstly encrypted with B's public key
I'm trying to use Schannel SSPI to send/receive data over SSL connection, using sockets.
I have some questions on DecryptMessage()
1) MSDN says that sometimes the application will receive data from the remote party, then successfully decrypt it using DecryptMessage() but the output data buffer will be empty. This is normal and the application must be able to deal with it. (As I understand, "empty" means SecBuffer::cbBuffer==0)
How should I deal with it? I'm trying to create a (secure) srecv() function, a replacement for the winsock recv() function. Therefore I cannot just return 0. Because the calling application will think that the remote party has closed the connection. Should I try to receive another encrypted block from the connection and try to decrypt it?
2) And another question. After successfully decrypting data with DecryptMessage (return value = SEC_E_OK), I'm trying to find a SECBUFFER_DATA type buffer in the output buffers.
PSecBuffer pDataBuf=NULL;
for(int i = 1; i < 4; ++i) { // should I always start with 1?
if(NULL == pDataBuf && SECBUFFER_DATA == buffers[i].BufferType) {
pDataBuf = buffers+i;
}
}
What if I don't find a data buffer? Should I consider it as an error? Or should I again try to receive an encrypted block to decrypt it? (I saw several examples. In one of them they were retrying to receive data, in another one they were reporting an error)
It appears that you are attempting to replicate blocking recv function for your Schannel secure socket implementation. In that case, you have no choice but to return 0. An alternative would be to pass a callback to your implementation and only call it when SecBuffer.cbBuffer > 0.
Yes, always start at index 1 for checking the remaining buffers. Your for loop is missing a check for SECBUFFER_EXTRA. If there is extra data and the cbBuffer size > 0, then you need to call DecryptMessage again with the extra data placed into index 0. If your srecv is blocking and you don't implement a callback function (for decrypted data sent to application layer), then you will have to append the results of DecryptMessage for each SECBUFFER_DATA received in the loop before returning the aggregate to the calling application.
Recently I downloaded Phil Strugeon REST server for CodeIgniter.
I reviewed source code and when I come to Digest authentication I saw following code:
if ($this->input->server('PHP_AUTH_DIGEST'))
{
$digest_string = $this->input->server('PHP_AUTH_DIGEST');
}
elseif ($this->input->server('HTTP_AUTHORIZATION'))
{
$digest_string = $this->input->server('HTTP_AUTHORIZATION');
}
else
{
$digest_string = "";
}
And bit later after some checks for absence of $digest_string and presence of username:
// This is the valid response expected
$A1 = md5($digest['username'].':'.$this->config->item('rest_realm').':'.$valid_pass);
$A2 = md5(strtoupper($this->request->method).':'.$digest['uri']);
$valid_response = md5($A1.':'.$digest['nonce'].':'.$digest['nc'].':'.$digest['cnonce'].':'.$digest['qop'].':'.$A2);
if ($digest['response'] != $valid_response)
{
header('HTTP/1.0 401 Unauthorized');
header('HTTP/1.1 401 Unauthorized');
exit;
}
In Wikipedia I see following text about HTTP Digest Auth:
For subsequent requests, the hexadecimal request counter (nc) must be greater than the last value it used – otherwise an attacker could simply "replay" an old request with the same credentials. It is up to the server to ensure that the counter increases for each of the nonce values that it has issued, rejecting any bad requests appropriately.
The server should remember nonce values that it has recently generated. It may also remember when each nonce value was issued, expiring them after a certain amount of time. If an expired value is used, the server should respond with the "401" status code and add stale=TRUE to the authentication header, indicating that the client should re-send with the new nonce provided, without prompting the user for another username and password.
However I can't see anything about checking cnonce, nc or nonce in source code.
Does it mean that somebody who recorded request from Client to Server that passed authentification may just "replay" it in future and receive fresh value of resource?
Is it really vulnarability? Or I misunderstood something?
I noticed this too when looking at codeigniter-restserver. It IS vulnerable to replay attacks because, as you said, it does not enforce the nonce.
Digest authentication requires a handshake:
client makes request with Authorization. It will fail because the client does not yet know the nonce
server responds with WWW-Authenticate header, that contains the correct nonce to use
client makes same request using the nonce provided in the server response
server checks that the nonces match and provides the requested url.
To accomplish this, you'll need to start a session on your REST server to remember the nonce. An easy scheme for ensuring nonce is always unique is to base it on current time using a function such as uniqid()
Assume that we have two applications:
MasterApp
SlaveApp
MasterApp is executing SlaveApp with some arguments, fe: slaveapp --param1 100 param2 "hello"
You can't see that directly, but somebody may try to inspect arguments provided to slaveapp, and execute it from console.
I want slaveapp to become executable only by masterapp, so that user can't run it in console mode (or as slave or another app). I was thinking about providing some unique_string and md5(unique_string + salt), but if somebody will inspect arguments he may understand what's goin' on. Is there some way to do it only by providing some unique, trusted argument that can't be used twice (and there is no resource sharing like files with private/ public keys etc)?
How about just encrypting the paramaters passed with a pre-defined encryption key and including a check_string of some type (i.e. EPOCH time). Then decode the paramaters in salveapp and verify the check_string (in this example that EPOCH time) is within a certain range or is a certain value.
Here is a simple ruby example, its in a single file so you would need to modify it to handel command line arguments ect.
require 'openssl'
require 'digest/sha1'
c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
c.encrypt
# your pass is what is used to encrypt/decrypt
c.key = key = Digest::SHA1.hexdigest("1094whfiubf9qwer8y32908u3209fn2032")
c.iv = iv = c.random_iv
e = c.update("#{Time.now.to_i}")
e << c.final
puts "encrypted: #{e}\n"
#sleep(15) #if you uncomment this the validation will fail.
c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
c.decrypt
c.key = key
c.iv = iv
d = c.update(e)
d << c.final
if(Time.now.to_i - d.to_i < 10)
puts "decrypted: #{d}\n"
puts "Validated EPOCH Time"
else
puts "Validation FAILED."
end
It is basically impossible to avoid replay attacks if your communication channel only goes master -> slave. Signing the request with a timestamp in it could help, but even that isn't perfect (especially if the attacker has some control of the clock).
The better strategy is to establish a two-way communication between master and slave. I'm not sure what language you're working in, but usually there's a way for the master to talk to the slave after it is forked, other than just the command line.
Using that channel, you can have the slave generate a random nonce, send that to the master, have the master sign it, send it back to the slave, and check the signature in the slave.
Make sure the slave app is owned by the same user the master app runs as, and make sure it's not world readable or executable.