Open KevinAdhaikal opened 1 month ago
here is my AES 128 GCM decrypt
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include "hash/hmac_sha256.h"
#include "libtomcrypt/src/headers/tomcrypt.h"
void print_hex(const char* text, uint8_t* data, int len) {
printf("%s", text);
for (int a = 0; a < len; a++) printf("%02x", data[a]);
printf("\n");
}
int main() {
uint8_t client_random[32] = {0x94, 0x8b, 0x00, 0xd3, 0x83, 0xbb, 0x40, 0x95, 0x37, 0x31, 0xa7, 0x0f, 0x8d, 0x8b, 0x59, 0x40, 0x95, 0x08, 0x38, 0x84, 0xa4, 0xe2, 0x8c, 0xf6, 0x9e, 0x73, 0x9d, 0x35, 0xfa, 0x8c, 0x78, 0x76};
uint8_t server_random[32] = {0x23, 0x19, 0x4b, 0x74, 0x12, 0xdc, 0x90, 0xf5, 0xb4, 0x89, 0x02, 0x9f, 0xf6, 0x3a, 0xfd, 0x5a, 0x35, 0xb8, 0x5e, 0x37, 0x2d, 0xf7, 0x33, 0xae, 0x19, 0x4f, 0xe5, 0x40, 0x4f, 0x82, 0xfa, 0xcf};
uint8_t master_secret[48] = {0x5c, 0x05, 0xe8, 0xe6, 0xa6, 0xca, 0x22, 0xfa, 0x3a, 0xfc, 0xd8, 0x32, 0xa0, 0xcd, 0xa6, 0x1a, 0xfd, 0xe7, 0x80, 0xb3, 0xb2, 0x69, 0x29, 0xe0, 0x7c, 0x82, 0x5e, 0xa1, 0xa5, 0x00, 0xd1, 0x6a, 0x10, 0x5a, 0xf6, 0x72, 0x28, 0xdb, 0x9c, 0x09, 0x14, 0x05, 0xc4, 0x1b, 0x2c, 0x78, 0x2c, 0x77};
uint8_t encrypted_data[40] = {0x1F, 0xDA, 0x89, 0x03, 0xA1, 0x84, 0xBB, 0xB2, 0x07, 0x30, 0xD7, 0xF3, 0x5D, 0xB2, 0x68, 0x6F, 0x1A, 0x7D, 0xB9, 0x80, 0xE3, 0x2C, 0x59, 0xDC, 0x97, 0x96, 0x65, 0x1F, 0xC1, 0x45, 0xEA, 0x2B, 0xED, 0x06, 0x0A, 0x34, 0xD5, 0x99, 0xE8, 0xE2};
uint8_t decrypted_data[40];
uint8_t seed[109];
memcpy(seed + 32, "key expansion", 13);
memcpy(seed + 45, server_random, 32);
memcpy(seed + 77, client_random, 32);
uint8_t a1[32], a2[32], a3[32], a4[32], p[128];
hmac_sha256(master_secret, 48, seed + 32, 77, a1, 32);
hmac_sha256(master_secret, 48, a1, 32, a2, 32);
hmac_sha256(master_secret, 48, a2, 32, a3, 32);
hmac_sha256(master_secret, 48, a3, 32, a4, 32);
memcpy(seed, a1, 32);
hmac_sha256(master_secret, 48, seed, 109, p, 32);
memcpy(seed, a2, 32);
hmac_sha256(master_secret, 48, seed, 109, p + 32, 32);
memcpy(seed, a3, 32);
hmac_sha256(master_secret, 48, seed, 109, p + 64, 32);
memcpy(seed, a4, 32);
hmac_sha256(master_secret, 48, seed, 109, p + 96, 32);
uint8_t result[104];
memcpy(result, p, 20);
memcpy(result + 20, p + 20, 20);
memcpy(result + 40, p + 40, 16);
memcpy(result + 56, p + 56, 16);
memcpy(result + 72, p + 72, 16);
memcpy(result + 88, p + 88, 16);
print_hex("Client MAC key: ", result, 20);
print_hex("Server MAC key: ", result + 20, 20);
print_hex("Client write key: ", result + 40, 16);
print_hex("Server write key: ", result + 56, 16);
print_hex("Client write IV: ", result + 72, 16);
print_hex("Server write IV: ", result + 88, 16);
uint8_t iv[12];
memset(iv + 4, 0, 8);
memcpy(iv, result + 72, 4);
register_cipher(&aes_desc);
uint8_t tag[16];
gcm_state gcm;
gcm_init(&gcm, find_cipher("aes"), result + 40, 16);
gcm_add_iv(&gcm, iv, 12);
gcm_process(&gcm, encrypted_data, 40, decrypted_data, GCM_DECRYPT);
gcm_done(&gcm, tag, &(unsigned long){16});
for (int a = 0; a < 40; a++) printf("%02x ", decrypted_data[a]);
return 0;
}
i dont know why this is doesnt working.
Hi Kevin!
The use of GCM in TLS is explained much better on my TLS 1.3 site, https://tls13.xargs.org. That site goes into detail on what is used for IV and AAD, though the exact AAD will probably be different for TLS 1.2 since the record wrappers are different.
My memory is that the IV will be incremented by (xor'd with) with the record sequence number (starting at zero) to create a new IV for each record. The AAD will generally be all the un-encrypted bytes in the record, though I'd have to check for TLS 1.2 specifically.
If you are using a GCM cipher, changing the IV and providing AAD must be performed for each packet encryption/decryption, it is fundamental to the security of GCM. The security guarantees of GCM can disappear if an IV is used twice (therefore it is always modified, for every encryption/decryption), and AAD is also a required input to the GCM algorithm.
I've just checked the TLS 1.2 RFC, here is the spec for AAD:
additional_data = seq_num + TLSCompressed.type +
TLSCompressed.version + TLSCompressed.length;
where +
is concatenation and where the TLSCompressed
fields are:
ContentType type; /* same as TLSPlaintext.type */
ProtocolVersion version;/* same as TLSPlaintext.version */
uint16 length;
Since you are most likely not using a compression method length
will be the record length, so all together that appears to be the sequence number (a 64-bit number, in big-endian format, counting the number of records sent so far) followed by what I think to be the first five bytes of the packet (the type byte, two bytes for version, and a two-byte length field).
I can't be sure of the correctness of other data in your sample code, but try calling gcm_add_aad()
with the appropriate data (the 13 bytes described above) and increment the IV by your record sequence number (that's the same as XOR'ing it) and see if you can get a successful decryption that way.
Good luck!
(I've made a few edits to the above, not sure if they are sent to you, be sure to refresh the page just in case)
My memory is that the IV will be incremented by (xor'd with) with the record sequence number (starting at zero) to create a new IV for each record. The AAD will generally be all the un-encrypted bytes in the record, though I'd have to check for TLS 1.2 specifically.
Can you give an example of how to get the IV? I'm still dont understand... 😅
Pre-Master key: 5c05e8e6a6ca22fa3afcd832a0cda61afde780b3b26929e07c825ea1a500d16a105af67228db9c091405c41b2c782c77 Client random: 948b00d383bb40953731a70f8d8b594095083884a4e28cf69e739d35fa8c7876 Server random: 23194b7412dc90f5b489029ff63afd5a35b85e372df733ae194fe5404f82facf
Client MAC key: d966c90c69eadfeae377667c305e61c2873f7443 Server MAC key: deb73cfaa5489be7f992bad5c683a9274cb0a416 Client write key: a4d9507245a8bd791f473c13ab9ebe66 Server write key: cf0b718dc53df54ba2acd53830023e4f Client write IV: 721ffb736f49b78bab72aa849a093ac9 Server write IV: de4278bb07ea4bac4026b2f6322dc6c6
So, i must take the first byte of Client write IV, and sequence number and it will like this
IV: 72 1f fb 73 00 00 00 00 00 00 00 00
and then, I must do XOR the IV and I will get the correct IV to decrypt the "Client Handshake Finished" packet?
Sorry if my grammar is bad 🙏
My understanding is that the IV is 4 bytes generated as client_write_IV
/ server_write_IV
, and 8 bytes from explicit IV sent with the record. Here is the spec:
The "nonce" SHALL be 12 bytes long consisting
of two parts as follows: (this is an example of a "partially
explicit" nonce; see Section 3.2.1 in [RFC5116]).
struct {
opaque salt[4];
opaque nonce_explicit[8];
} GCMNonce;
The salt is the "implicit" part of the nonce and is not sent in the
packet. Instead, the salt is generated as part of the handshake
process: it is either the client_write_IV (when the client is
sending) or the server_write_IV (when the server is sending). The
salt length (SecurityParameters.fixed_iv_length) is 4 octets.
The nonce_explicit is the "explicit" part of the nonce. It is chosen
by the sender and is carried in each TLS record in the
GenericAEADCipher.nonce_explicit field. The nonce_explicit length
(SecurityParameters.record_iv_length) is 8 octets.
IV: 72 1f fb 73 00 00 00 00 00 00 00 00 and then, I must do XOR the IV and I will get the correct IV to decrypt the "Client Handshake Finished" packet?
That sounds right, you'll also need to supply the matching AAD or the encrypt/decrypt operations will fail. The design of an AEAD cipher mode like GCM is that it takes constant time whether successful or failing, and that it can give no indication of which input is incorrect (be it the IV, the key, or the AAD).
(still reading your questions):
Client write IV: 721ffb736f49b78bab72aa849a093ac9 Server write IV: de4278bb07ea4bac4026b2f6322dc6c6
actually, since you are using a cipher that only wants 4 bytes of IV from this source, it would be a mistake to use this many bytes for each. I believe in this case the client write IV would be 721ffb73
and the server write IV would be the next four bytes, 6f49b78b
.
This would be combined with an additional 8 bytes of IV that are sent in the record. Hmm, since GCM requires that an IV is never repeated with the same encryption key, I wonder if this means the same 8 bytes of IV data will be sent each time? That sounds right. Then the record number will keep incrementing the IV by 1 each time.
EDIT: I just re-read the spec and I think you'll see the the explicit IV, given in each record, already has the number incremented. So you'll probably see something like this:
record 0:
record 1:
record 2:
... etc. I haven't looked deeply at TLS1.2+GCM so haven't seen this yet.
Hmmmmm... This GCM Encryption Makes my head hurt, hahahaha :joy:
opaque nonce_explicit[8];
so, opaque nonce_explicit[8];
is sequence number, is it correct?
so, opaque nonce_explicit[8]; is sequence number, is it correct?
It doesn't have to be, the spec just says it can't be repeated in two different records. I think the easiest method to do this, and probably what most implementations do, is to just put the sequence number in the IV, yes.
ohhh... btw do you have Discord? so that we can chat about TLS on discord? My discord username is: KevinAdhaikal
if you dont want to chat on the Discord, its okay.
and btw, im sorry if i disturb your time 🙏
okay, after i read https://www.rfc-editor.org/rfc/rfc5246#section-6.2.3.3 (section-6.2.3.3) and https://www.rfc-editor.org/rfc/rfc5288.html
the nonce (IV) it generated from Client/Server write IV (4 bytes) and Sequence Number (8 bytes) but, when i try to read carefully again at RFC 5288, section 8, it needs authentication tag (auth tag)
how do i get authentication tag (auth tag)?
is the auth tag is from the last 16 bytes from encrypted data?
example:
0000 16 03 03 00 28 1f da 89 03 a1 84 bb b2 07 30 d7
0010 f3 5d b2 68 6f 1a 7d b9 80 e3 2c 59 dc 97 96 65
0020 1f c1 45 ea 2b ed 06 0a 34 d5 99 e8 e2
so the, auth tag is 9796651fc145ea2bed060a34d599e8e2
?
sorry if my grammar is bad 🙏
hmmmm... already try like same in the RFC
const crypto = require('crypto');
/*
Client MAC key: d966c90c69eadfeae377667c305e61c2873f7443
Server MAC key: deb73cfaa5489be7f992bad5c683a9274cb0a416
Client write key: a4d9507245a8bd791f473c13ab9ebe66
Server write key: cf0b718dc53df54ba2acd53830023e4f
Client write IV: 721ffb736f49b78bab72aa849a093ac9
Server write IV: de4278bb07ea4bac4026b2f6322dc6c6
*/
function decrypt(ciphertext, key, iv, aad) {
const decipher = crypto.createDecipheriv('aes-128-gcm', key, iv);
decipher.setAAD(aad)
let decrypted = decipher.update(ciphertext, 'hex', 'hex');
decrypted += decipher.final('hex');
return decrypted;
}
const encrypted_text = "1FDA8903A184BBB20730D7F35DB2686F1A7DB980E32C59DC9796651FC145EA2BED060A34D599E8E2";
const decrypted = decrypt(
encrypted_text,
Buffer.from("a4d9507245a8bd791f473c13ab9ebe66", "hex"),
Buffer.from("721ffb730000000000000000", "hex"),
Buffer.from("00000000000000001603030028", "hex"),
);
console.log('Decrypted:', decrypted);
its still doesnt work
Oops, wrong button :facepalm:
Hello, how do i get AAD and IV in AES 128 GCM? Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
in AES 128 CBC (TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)), the IV is on the Client handshake finished Example like in your website
the IV is:
40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
and no need to use AADbut how about AES 128 GCM?
Sorry if my grammar is bad, Thanks.