diff --git a/docs/changes.txt b/docs/changes.txt new file mode 100644 index 0000000..1aa0caa --- /dev/null +++ b/docs/changes.txt @@ -0,0 +1,13 @@ +v0.1.0 + +first public release + +v0.1.1 + +* nfqws2: fixed crash on 32-bit platforms if debug is enabled + +v0.1.2 + +* nfqws2: 'mtproto' protocol, 'mtproto_initial' payload +* nfqws2: 'known' protocol and payload filter +* nfqws2: 'aes_ctr' luacall diff --git a/lua/zapret-tests.lua b/lua/zapret-tests.lua index 873afc3..4ee0417 100644 --- a/lua/zapret-tests.lua +++ b/lua/zapret-tests.lua @@ -18,7 +18,7 @@ end function test_crypto() - test_run({test_random, test_aes, test_aes_gcm, test_hkdf, test_hash}) + test_run({test_random, test_aes, test_aes_gcm, test_aes_ctr, test_hkdf, test_hash}) end function test_random() @@ -187,6 +187,42 @@ function test_aes_gcm() end end +function test_aes_ctr() + local clear_text="test message "..brandom_az09(math.random(10,50)) + local iv, key, encrypted, decrypted + + for key_size=16,32,8 do + iv = brandom(16) + key = brandom(key_size) + + print() + print("* aes_ctr test key_size "..tostring(key_size)) + + print("clear text: "..clear_text); + + print("* encrypting") + encrypted = aes_ctr(key, iv, clear_text) + print("encrypted: "..str_or_hex(encrypted)) + + print("* decrypting") + decrypted = aes_ctr(key, iv, encrypted) + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted==clear_text) + + print("* decrypting with bad key") + decrypted = aes_ctr(bu8(u8(string.sub(key,1,1))+1)..string.sub(key,2), iv, encrypted) + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted~=clear_text) + + print("* decrypting with bad iv") + decrypted = aes_ctr(key, bu8(u8(string.sub(iv,1,1))+1)..string.sub(iv,2), encrypted) + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted~=clear_text) + end +end function test_ub() diff --git a/nfq2/desync.c b/nfq2/desync.c index ed017d1..162cb14 100644 --- a/nfq2/desync.c +++ b/nfq2/desync.c @@ -1201,7 +1201,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in if (l7proto == L7_UNKNOWN) { l7proto = L7_TLS; - if (ctrack) ctrack->l7proto = l7proto; + if (ctrack->l7proto == L7_UNKNOWN) ctrack->l7proto = l7proto; } if (bReqFull) TLSDebug(rdata_payload, rlen_payload); @@ -1254,6 +1254,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in } else if (ctrack && (ctrack->seq_last - ctrack->seq0)==1 && IsMTProto(dis->data_payload, dis->len_payload)) { + DLOG("packet contains telegram mtproto2 initial\n"); // mtproto detection requires aes. react only on the first tcp data packet. do not detect if ctrack unavailable. l7payload = L7P_MTPROTO_INITIAL; if (l7proto == L7_UNKNOWN) diff --git a/nfq2/lua.c b/nfq2/lua.c index 6490118..e9f5325 100644 --- a/nfq2/lua.c +++ b/nfq2/lua.c @@ -446,7 +446,6 @@ static int luacall_aes_gcm(lua_State *L) uint8_t *output = malloc(input_len); if (!output) luaL_error(L, "out of memory"); - gcm_initialize(); if (aes_gcm_crypt(bEncrypt, output, input, input_len, key, key_len, iv, iv_len, add, add_len, atag, sizeof(atag))) { lua_pushnil(L); @@ -462,6 +461,38 @@ static int luacall_aes_gcm(lua_State *L) LUA_STACK_GUARD_RETURN(L,2) } +static int luacall_aes_ctr(lua_State *L) +{ + // aes_ctr(key, iv, in) returns out + lua_check_argc(L,"aes_ctr",3); + + LUA_STACK_GUARD_ENTER(L) + + size_t key_len; + const uint8_t *key = (uint8_t*)luaL_checklstring(L,1,&key_len); + if (key_len!=16 && key_len!=24 && key_len!=32) + luaL_error(L, "aes_ctr: wrong key length %u. should be 16,24,32.", (unsigned)key_len); + + size_t iv_len; + const uint8_t *iv = (uint8_t*)luaL_checklstring(L,2,&iv_len); + if (iv_len!=16) + luaL_error(L, "aes_ctr: wrong iv length %u. should be 16.", (unsigned)iv_len); + + size_t input_len; + const uint8_t *input = (uint8_t*)luaL_checklstring(L,3,&input_len); + + uint8_t *output = malloc(input_len); + if (!output) luaL_error(L, "out of memory"); + + if (aes_ctr_crypt(key, key_len, iv, input, input_len, output)) + lua_pushnil(L); + else + lua_pushlstring(L,(const char*)output,input_len); + free(output); + + LUA_STACK_GUARD_RETURN(L,1) +} + static int luacall_hkdf(lua_State *L) { // hkdf(hash_type, salt, ikm, info, okm_len) returns okm @@ -2553,6 +2584,7 @@ static void lua_init_functions(void) {"hash",luacall_hash}, {"aes",luacall_aes}, {"aes_gcm",luacall_aes_gcm}, + {"aes_ctr",luacall_aes_ctr}, {"hkdf",luacall_hkdf}, // parsing diff --git a/nfq2/protocol.c b/nfq2/protocol.c index 9287f7d..07693fc 100644 --- a/nfq2/protocol.c +++ b/nfq2/protocol.c @@ -1151,7 +1151,7 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si pn_offset += tvb_get_varint(data + pn_offset, &payload_len); if (payload_len<20 || (pn_offset + payload_len)>data_len) return false; - gcm_initialize(); // initialize aes keygen tables + aes_init_keygen_tables(); uint8_t sample_enc[16]; aes_context ctx; @@ -1394,13 +1394,8 @@ bool IsMTProto(const uint8_t *data, size_t len) { if (len>=64) { - aes_context ctx; - uint8_t dcopy[64]; - - aes_init_keygen_tables(); - memcpy(dcopy,data,sizeof(dcopy)); - aes_setkey(&ctx, true, data+8, 32); - aes_ctr_xcrypt_buffer(&ctx, data+40, dcopy, sizeof(dcopy)); - return !memcmp(dcopy+56,"\xEF\xEF\xEF\xEF",4); + uint8_t decrypt[64]; + aes_ctr_crypt(data+8, 32, data+40, data, 64, decrypt); + return !memcmp(decrypt+56,"\xEF\xEF\xEF\xEF",4); } }