Take the 2-minute tour ×
Cryptography Stack Exchange is a question and answer site for software developers, mathematicians and others interested in cryptography. It's 100% free, no registration required.

I am attempting to duplicate wireshark's packet capture decryption for a TLS HTTP session, where I control the private key of the server.

The cipher suite number is 0x00002f, TLS_RSA_AES_128_CBC_SHA

I wrote a utility that takes apart the packet captures using libpcap, and so far can match what the logs from wireshark say they have in terms of MAC keys, Write keys, and IV's; printing out the binary data as hex characters.

Visually, I can confirm that the keyblock and ciphertext are identical to what wireshark's log display.

However, after I perform the following decryption steps:

... decrypt pre_master_secret, generate keyblock
... initialize cipher context

EVP_CIPHER_CTX_init(&myevp);
if (!EVP_CipherInit_ex(&myevp, cipher, NULL, wKey, IV, 0))
    LogError("evp_cipherinit_ex:", ERR_error_string(ERR_get_error(), NUL));

dec = EVP_DecryptUpdate(&myevp, outb, outlen, data, datalen);
totalcount += outlen;

if (!dec) 
    LogError("evp_decryptupdate:", ERR_error_string(ERR_get_error(), NUL));

if (dec && blocklen != 1) {
    dec = EVP_DecryptFinal_ex(&myevp, outb + totalcount, outlen);
    totalcount += outlen;    
}

...get padding from last bit of outb, and remove padding from outb (plaintext)
...remove the MAC from the plaintext

The resultant plaintext I get is identical to what wireshark spits out in their logs, with the execption of the first block of decrypted data.

I know that in general, this is usually caused by not having a correct initialization vector when you begin the decryption. However, all my computed keyblock values seem correct (that is to say, they jive with what wireshark is spitting out).

here's the first few blocks of what wireshark shows...

Plaintext[432]:
47 45 54 20 2f 68 65 6c 6c 6f 2e 68 74 6d 6c 20
48 54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20
31 37 32 2e 31 36 2e 32 34 34 2e 31 39 36 0d 0a
...

and mine

plaintext_update[432]
e1 a2 f4 b3 2a 93 d1 c4 1b f4 60 d8 c9 92 03 25
48 54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20
31 37 32 2e 31 36 2e 32 34 34 2e 31 39 36 0d 0a
...

It's just that first block. I can verify before the Decryption step that the evp context has the correct original IV value and the current are there.

LogData("evp oiv", &myevp->evp.oiv, &myevp->evp.cipher->iv_len);
LogData("evp iv", &myevp->evp.iv, &myevp->evp.cipher->iv_len);

here's the one from wireshark

Client Write IV[16]:
8b 55 c0 c5 3c 77 dc 91 09 22 18 8b 0c 53 16 66

here's mine

evp iv[16]
8b 55 c0 c5 3c 77 dc 91 09 22 18 8b 0c 53 16 66

Likewise, the keys are the same. I don't think I need to illustrate those values, as the remaining blocks do decrypt correctly.

I've also checked to make sure that first block isn't gzipped, or whatever. I checked the wireshark code, and they are doing the same equivalent stuff I'm doing, albeit in libgpgcrypt.

Anybody ever seen anything like this?

share|improve this question
add comment

1 Answer

up vote 7 down vote accepted

For TLS the IV for the first packet is generated from the shared secrets; quoting the RFC 2246:

To generate the key material, compute

  key_block = PRF(SecurityParameters.master_secret,
                     "key expansion",
                     SecurityParameters.server_random +
                     SecurityParameters.client_random);

until enough output has been generated. Then the key_block is partitioned as follows:

  client_write_MAC_secret[SecurityParameters.hash_size]
  server_write_MAC_secret[SecurityParameters.hash_size]
  client_write_key[SecurityParameters.key_material_length]
  server_write_key[SecurityParameters.key_material_length]
  client_write_IV[SecurityParameters.IV_size]
  server_write_IV[SecurityParameters.IV_size]

I suppose that you have generated these, and checked them? (You need 6 ·16 bytes in your cipher suite, and the last 32 are the IV's, one for each direction.)

Also, the IV for the next TLS-record is the last cipher text block of the previous record in the same direction. So you need to keep track of these as well. So the first IV is never sent, and you need to keep updating the IV as we get new packets in, or send new ones.

share|improve this answer
2  
The last paragraph would be my guess, too. In TLS, the IV generated from the key block will be used for the Finished message at the end of the handshake, and the record for the "GET /..." will use as IV the last 16 bytes of that previous (encrypted) record. From TLS-1.1 onward, each record has its own transmitted IV, but for SSL-3.0 and TLS-1.0 you must use the last block from the previous record. –  Thomas Pornin Sep 17 '11 at 14:13
    
The issue was, as Thomas pointed out, the last paragraph. I wasn't updating the IV from the Finished message. I knew this conceptually (update after last block), but somehow overlooked the idea that it spans across TLS messages themselves as well. Seems obvious in hindsight. Thanks! –  madczar Sep 19 '11 at 12:00
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.