TLS1.2 Decrypting "Finished" message - ssl

I am implementing simplified version of TLS1.2 server socket, and I have troubles decrypting clients "Finished" message. I have successfully exchanged messages up to clients "Finished" message. I have computed master_secret correctly(master_secret extracted from browser matches one computed by me), expanded material for keys but I have no luck decrypting clients message. Here is what have I exactly done:
Exchanged messages with following important result:
cipher_suite = "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"
master_secret = "bee102cfec022435774e97a9718628798643563b2e95626dc405f20660e023b6da73846bf54879bc53780760535316fd"
client_random = "99ab80aa2659df3ddb367f0d1e65b121d87782e26f7d75a7121c763833138529"
server_random = "0000000000000000000000000000000000000000000000000000000000000000"
Based on above I have generated following key material:
key_client_write = "64288957f9ad56be81db1af6a00f49713bd1fc7e89a56093fc8d18a9efe62267"
key_server_write = "280b12c845df613e5bc62f92337e6cbb91fcba5a63df535c77d06d16b5ef85ce"
But no luck decrypting following "Finished" message sent by client(Firefox browser), I separated record layer header by a single space from encrypted part:
client_finished = "1603030040 b5d75b9c79a08d3895ae4e623187078e099c9af49ec5dcd65bfe31c11b0a404689b75d4bf73aabb74c947449adf52c15d01f541dbccf83c14ef8cdbfaeef94d3"
I am treating data as follows:
iv = "b5d75b9c79a08d3895ae4e623187078e"
ciphertext = "099c9af49ec5dcd65bfe31c11b0a404689b75d4bf73aabb74c947449adf52c15d01f541dbccf83c14ef8cdbfaeef94d37ffbbbdfe042200e2db7"
Tried to use both keys but decrypted messages does not make any sense.
Are my keys wrong or, am I interpreting data wrong?

Ok, I was interpreting key_material in a wrong way. I took 32 bytes for MAC key, but it should be 20 bytes.

Related

Redis PSUBSCRIBE Problems

A server is sending a message via Redis on a channel composed of some name and a unique id. I need to essentially find this channel and publish something back to it.
So far, I tried reading the documentation and experimenting with PSUBSCRIBE. However, the message that is received doesn't have the full channel name. It just has the pattern that I sent to PSUBSCRIBE. So, how can I go about finding the channel name?
I also included some code below if that would help understand my logic.
red = redis.StrictRedis(...)
pub = red.pubsub()
pub.psubscribe("name_pattern*")
for msg in pub.listen():
if msg["data"] == "...":
channel_name = msg["channel"]
red.publish(channel_name, "SOME MESSAGE")

how to encrypt the chat message with multiple people public key together and restore the message?

I have a application with two users and one middle man, all of them holding the private and public key, To make the secured chat, two users and one middle man are all sending the public key and generate a secured channel. After establishing the channel, the middle man doesn't have the ability to see the encrypted message unless one of the user is sending his own key to the middle man.
i am not very familiar with cryptography, so for this app i know how to encrypt and decrypt the message.
encrypt(data) {
try {
var cipher = Crypto.createCipher('aes-256-cbc', this.password);
var encrypted = Buffer.concat([cipher.update(new Buffer(JSON.stringify(data), "utf8")), cipher.final()]);
FileSystem.writeFileSync(this.filePath, encrypted);
return { message: "Encrypted!" };
} catch (exception) {
throw new Error(exception.message);
}
}
but I don't know how to establish the encrypted channel from the stakeholders' key, and how can the one middle to see the message using his key and one of users' key?
is there a way to accomplish this using the cryptography?
I'm not sure I completely understand, but I think if you want to go with a system that doesn't use public key crypto I would suggest a system using 2 stages of encryption, actually a lot like PGP only both stages use symmetric keys-
1) There is a fixed session key generated by the first person in the chat, this can be a randomly generated number.
2) This session key is then encrypted by the keys belonging to every new member of the chat group and individually sent to them.
3) The new members decrypt with their own unique keys to get the plaintext session key back.
4) This session key is subsequently used to decrypt the messages sent to all participants. The same key can also be used to encrypt and send any new messages from any entitled participant(i.e. has the valid session key) on the chat group.
This is used in some systems but it relies on the unique keys being securely transmitted, in the first instance. If this condition can't be met, it's a problem that can be solved with public key crypto to build an end-to-end secure message system like PGP, whatsapp, etc.

XMPP SASL SCRAM-SHA1 Authentication

Recently, I was able to get MD5 authentication working for XMPP streams in Swift IOS following the instructions on the following two websites (I used the CC-MD5 function of Apple's CommonCrypto C library for the actual hashing):
http://wiki.xmpp.org/web/SASLandDIGEST-MD5
http://www.deusty.com/2007/09/example-please.html
I'm searching for a similar explanation for how to get other hashed SASL authentication schemes working, especially SCRAM-SHA1. I have found the official RFC5802 document but I'm having a lot of trouble understanding it (it is not specific to XMPP either). I would appreciate a simpler explanation or some simple readable code (C, PHP, C++, Javascript, Java) specific to XMPP authentication that doesn't use libraries for anything other than the actual hashing.
I'm interested in understanding the process and am not looking to use the ios XMPP-Framework. Any help would be appreciated.
SCRAM-SHA-1
The basic overview of how this mechanism works is:
The client sends the username it wants to authenticate as.
The server sends back the salt for that user and the number of iterations (either by generating them or looking them up in its database for the given username).
The client hashes the password with the given salt for the given number of iterations.
The client sends the result back.
The server does a variation of the hashing and sends it result back to the client, so the client can also verify that the server had the password/a hash of the password.
The cryptographic algorithms you'll need are SHA-1, HMAC with SHA-1 and PBKDF2 with SHA-1. You should look up how to use them in your language/framework, as I don't recommend implementing them from scratch.
In detail
First normalize the password (using SASLprep), this will be normalizedPassword. This is to ensure the UTF8 encoding can't contain variations of the same password.
Pick a random string (for example 32 hex encoded bytes). This will be clientNonce.
The initialMessage is "n=" .. username .. ",r=" .. clientNonce (I'm using .. for string concatenation).
The client prepends the GS2 header ("n,,") to the initialMessage and base64-encodes the result. It sends this as its first message:
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="SCRAM-SHA-1">
biwsbj1yb21lbyxyPTZkNDQyYjVkOWU1MWE3NDBmMzY5ZTNkY2VjZjMxNzhl
</auth>
The server responds with a challenge. The data of the challenge is base64 encoded:
<challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
cj02ZDQ0MmI1ZDllNTFhNzQwZjM2OWUzZGNlY2YzMTc4ZWMxMmIzOTg1YmJkNGE4ZTZmODE0YjQyMmFiNzY2NTczLHM9UVNYQ1IrUTZzZWs4YmY5MixpPTQwOTY=
</challenge>
The client base64 decodes it:
r=6d442b5d9e51a740f369e3dcecf3178ec12b3985bbd4a8e6f814b422ab766573,s=QSXCR+Q6sek8bf92,i=4096
The client parses this:
r= This is the serverNonce. The client MUST ensure that it starts with the clientNonce it sent in its initial message.
s= This is the salt, base64 encoded (yes, this is base64-encoded twice!)
i= This is the number of iterations, i.
The client computes:
clientFinalMessageBare = "c=biws,r=" .. serverNonce
saltedPassword = PBKDF2-SHA-1(normalizedPassword, salt, i)
clientKey = HMAC-SHA-1(saltedPassword, "Client Key")
storedKey = SHA-1(clientKey)
authMessage = initialMessage .. "," .. serverFirstMessage .. "," .. clientFinalMessageBare
clientSignature = HMAC-SHA-1(storedKey, authMessage)
clientProof = clientKey XOR clientSignature
serverKey = HMAC-SHA-1(saltedPassword, "Server Key")
serverSignature = HMAC-SHA-1(serverKey, authMessage)
clientFinalMessage = clientFinalMessageBare .. ",p=" .. base64(clientProof)
The client base64 encodes the clientFinalMessage and sends it as a response:
<response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
Yz1iaXdzLHI9NmQ0NDJiNWQ5ZTUxYTc0MGYzNjllM2RjZWNmMzE3OGVjMTJiMzk4NWJiZDRhOGU2ZjgxNGI0MjJhYjc2NjU3MyxwPXlxbTcyWWxmc2hFTmpQUjFYeGFucG5IUVA4bz0=
</response>
If everything went well, you'll get a <success> response from the server:
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
dj1wTk5ERlZFUXh1WHhDb1NFaVc4R0VaKzFSU289
</success>
Base64 decoded this contains:
v=pNNDFVEQxuXxCoSEiW8GEZ+1RSo=
The client MUST make sure the value of v is the base64 encoding of the serverSignature.
Extras
This is the basic version of the algorithm. You can extend it to do:
Channel binding. This mixes in some information from the TLS connection to the procedure to prevent MitM attacks.
Hashed storage. If the server always sends the same salt and i values, then the client can store only saltedPassword instead of the user's password. This is more secure (as the client doesn't need to store the password, just a hard to reverse salted hash) and faster, as the client doesn't need to do all the key stretching every time.
The server can also use hashed storage: the server can store only salt, i, storedKey and serverKey. More info on that here.
Possibly, also adding SCRAM-SHA-256 (though server support seems non-existent).
Pitfalls
Some common pitfalls:
Don't assume anything about the length of the nonces or salt (though if you generate them, make sure they are long enough and cryptographically random).
The salt is base64 encoded and can contain any data (embedded NULs).
Not using SASLprep may work fine for people using ASCII passwords, but it may completely break logging in for people using other scripts.
The initialMessage part of the authMessage does not include the GS2 header (in most situations, this is "n,,").
Test vectors
If you want to test your implementation, here are all the intermediate results for the example from the RFC:
Username: user
Password: pencil
Client generates the random nonce fyko+d2lbbFgONRv9qkxdawL
Initial message: n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL
Server generates the random nonce 3rfcNHYJY1ZVvWVs7j
Server replies: r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096
The salt (hex): 4125c247e43ab1e93c6dff76
Client final message bare: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j
Salted password (hex): 1d96ee3a529b5a5f9e47c01f229a2cb8a6e15f7d
Client key (hex): e234c47bf6c36696dd6d852b99aaa2ba26555728
Stored key (hex): e9d94660c39d65c38fbad91c358f14da0eef2bd6
Auth message: n=user,r=fyko+d2lbbFgONRv9qkxdawL,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096,c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j
Client signature (hex): 5d7138c486b0bfabdf49e3e2da8bd6e5c79db613
Client proof (hex): bf45fcbf7073d93d022466c94321745fe1c8e13b
Server key (hex): 0fe09258b3ac852ba502cc62ba903eaacdbf7d31
Server signature (hex): ae617da6a57c4bbb2e0286568dae1d251905b0a4
Client final message: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=
Server final message: v=rmF9pqV8S7suAoZWja4dJRkFsKQ=
Server's server signature (hex): ae617da6a57c4bbb2e0286568dae1d251905b0a4

How should an application authenticate with a datastore?

I'm writing an iPad game that sends hi-score type data (ie data beyond what Game Center supports) to a Google appengine datastore. It sends these updates via http GET or POST requests, such as http://myapp.appspot.com/game/hiscore/925818
Here is how I thought to ensure the appengine datastore isn't spammed with false data.
zip/encrypt the payload data using hardcoded p#ssw0rd saved in the iOS binary. Encode that binary data as base64. Pass base64 payload in the url query string or in the POST data. At handler, unbase64, then unzip data with p#ssw0rd. Follow instructions in payload to update highscore-type data.
CON: If p#ssw0rd is somehow derived from the iOS binary, this scheme can be defeated.
Is this adequate/sufficient? Is there another way to do this?
There is absolutely no way to make sure it's your client that sends the data. All you can try is to obfuscate some thing to make it harder for spammers to submit data.
However I think there are two thing you can do:
Have some kind of secrect key saved in the binary
Have a custom algorithm calculating some checksum
Maybe you can go with a combination of both. Let me give you an example:
Create some custom (complex!) alorithm like (simplyfied):
var result = ((score XOR score / 5) XOR score * 8) BITSHIFT_BY 3
Then use your static stored key with that result and a well known hash function like:
var hash = SHA256(StaticKey + result)
Then send that hash with the score to the server. The server has to "validate" the hash by performing the exact same steps (evaluate algorithm + do the SHA256 stuff) and compare the hashes. If they match the score hopefully comes from your app otherwise throw it away, it comes from a spammer.
However this is only one thing you can do. Have a look at the link from mfanto, there are many other ideas that you can look at.
Be sure to not tell anybody about how you're doing it since this is security through obscurity.
Ok me, there are 2 methods to do this.
1) Purchase an SSL certificate for $FREE.99 and open HTTPS connections only to your server to submit hiscore type data. Connection speed should be around 500 ms due to handshake roundtrip time.
2) Embed an RSA public key certificate in your iOS app, and have the RSA private key on your server.
You can then do 1 of 2 things with this second scheme:
IF your data messages are really small (≤256 B) you can just encrypt and send 256B packages (RSA payload is limited by the number of bits in the key)
ELSE IF the data is too large (>256B), generate a random symmetric key (AES), and pack:
SYMMETRIC AES KEY ENCRYPTED WITH RSA PUBLIC KEY
BINARY DATA ENCODED WITH SYMMETRIC AES KEY
The server then takes the first 256 bytes and decodes it, then the server uses that AES key to decrypt the rest of the message.
The above 2 only prevent eavesdropping, but it means the data format of your messages is hidden. At some level, it is still a type of security by obscurity, since if the hacker has your public key AND your message format, they can manufacture messages.

Pre-master secret mistmatched when implementing Diffie-Hellman key exchange

I am trying to implement DHE_DSS into go's crypto/tls package. Unfortunately I can not seem to get the PreMasterSecret (Z) to be the same, my basic workflow is:
Receive Server Key Exchange Message
Extract P, G, Ys
Verify using the digital signature provided
Prepare Client Key Exchange Message
Create client's Xc
Generate Yc (Yc = G^Xc % P)
Generate Z (Z = Ys^Xc % P)
Send back Yc, packed like so:
ckx := make([]byte, len(yC)+2)
ckx[0] = byte(len(Yc)>>8)
ckx[1] = byte(len(Yc))
copy(ckx[2:], yBytes)
However, when I am debugging this with gnutls-serv the two PreMasterSecrets (Z) are different. Do I need to sign the returned Yc, or perhaps pack it in another way? I can not see anything in RFC 5246 to suggest this.
<-- EDIT -->
Here is a patch of my changes:
https://08766345559465695203.googlegroups.com/attach/48587532c74b4348/crypto.patch?part=4&view=1&vt=ANaJVrHbwydqEZc3zjUWqQ5C8Q5zEkWXZLdL0w6JJG3HYntOlBurUTY7mc9xR9OTfE0bJxs4eeL5a5SGd2jj9eIfXcwJQgLvJchXOgkYKBBynbPfshY8kuQ
Client key exchange will contain:
length (2 bytes) --> Y_C (in plain text)
I have implemented TLS in Java and I follow the same structure and works fine for me.
Do I need to sign the returned Yc?
No there is no need to sign the client DH public value, it is transferred in plain text.
You can take a pcap and check whether same values are being transferred in the packet. Also if GNU TLS has logger for printing the Y_C received, then you can check if proper data is being received.
If in case you still getting different Pre-Master secret then there seems to be some issue with the logic of generation of secret.