Tox data parser

The tox data save is in binary format, I thought it would be nice to able to parse it, here is a little script to do it.

From crypto_core.h

#!/usr/bin/python

import struct
import sys

__author__ = "Mohamed Aziz Knani"

CRYPTO_PUBLIC_KEY_SIZE = 32
CRYPTO_SECRET_KEY_SIZE = 32

from messenger.c

MESSENGER_STATE_COOKIE_GLOBAL      = 0x15ed1b1f
MESSENGER_STATE_COOKIE_TYPE        = 0x01ce
MESSENGER_STATE_TYPE_NOSPAMKEYS    = 1
MESSENGER_STATE_TYPE_DHT           = 2
MESSENGER_STATE_TYPE_FRIENDS       = 3
MESSENGER_STATE_TYPE_NAME          = 4
MESSENGER_STATE_TYPE_STATUSMESSAGE = 5
MESSENGER_STATE_TYPE_STATUS        = 6
MESSENGER_STATE_TYPE_TCP_RELAY     = 10
MESSENGER_STATE_TYPE_PATH_NODE     = 11
MESSENGER_STATE_TYPE_END           = 255

This is calculated manually, so it can absolutely change, you can't assume for sure how much the size of the data is

FRIEND_SIZE = 2216
COOKIE_LEN = 8
ERROR = -1
END   = -2

def read_chunk(data, offset, cookie, length):
    if cookie == MESSENGER_STATE_TYPE_NOSPAMKEYS:
        print "[!] Printing Keys"
        #nospam
        nospam = data[offset:offset+4].encode("hex")
        print "    Nospam: " + nospam
        #public key
        offset += 4
        pubkey = data[offset:offset+CRYPTO_PUBLIC_KEY_SIZE].encode("hex")
        print "    PubKey: " + pubkey
        #secret key
        seckey = data[offset+CRYPTO_PUBLIC_KEY_SIZE:offset+CRYPTO_PUBLIC_KEY_SIZE+CRYPTO_SECRET_KEY_SIZE].encode("hex")
        print "    SecKey: " + seckey + " ==="
    elif cookie == MESSENGER_STATE_TYPE_NAME:
        print "[!] Printing Name"
        print " "*4+data[offset:offset+length]
    elif cookie == MESSENGER_STATE_TYPE_STATUSMESSAGE:
        print "[!] Printing status message"
        print " "*4+data[offset:offset+length]
    elif cookie == MESSENGER_STATE_TYPE_FRIENDS:
        if length % FRIEND_SIZE != 0:
            return ERROR
        num = length // FRIEND_SIZE
        buff = data[offset:length + offset]
        print "[!] Printing %d friends" % num
        friends = [buff[i:i+FRIEND_SIZE] for i in range(0, len(buff), FRIEND_SIZE)]
        for friend in friends:
            #unpack
            #struct.unpack(friend, )
            pass
    elif cookie == MESSENGER_STATE_TYPE_END:
        return END

def read_save(data):
    data0 = struct.unpack_from("<I", data, 0)[0]
    data1 = struct.unpack_from("<I", data, 4)[0]
    offset = COOKIE_LEN
    if data0 == 0 and data1 == MESSENGER_STATE_COOKIE_GLOBAL:
        while True:
            length = struct.unpack_from("<H", data, offset)[0]
            offset += 4
            cookie = struct.unpack_from("<H", data, offset)[0]
            offset += 2
            ck = struct.unpack_from("<H", data, offset)[0]
            offset += 2
            if ck != MESSENGER_STATE_COOKIE_TYPE:
                print "[-] state cookie not matching"
                return
            ret = read_chunk(data, offset, cookie, length)
            if ret == END:
                print "[*] END"
                break
            offset += length

tox_save = sys.stdin.read()
read_save(tox_save)

Download the file here.

to parse your file just do a:

python toxparser.py < ~/.config/tox/tox_save.tox 

NOTE: This is incomplete it can't parse friends structs for now.


Author: Aziz Knani

Date: 2023-03-22 Wed 00:01

Emacs 26.3 (Org mode 9.1.9)

Tunisian flag