xioustic / btsync-tools

A set of utilities for BitTorrent Sync
Other
0 stars 0 forks source link

Add Native Generation of RO keys #3

Open xioustic opened 8 years ago

xioustic commented 8 years ago

This might require some reverse engineering but would keep us from having to include the binaries with distribution code and would also give us cross-platform support of Read-Only key generation.

Presently we lean upon the btsync binaries being available at run-time.

xioustic commented 8 years ago

Promising information here: https://forum.bittorrent.com/topic/21338-inofficial-protocol-specification/ but only covers standard keys, not encrypted keys.

Specifically:

Secrets: The read only secret is basically just a hashed version of the normal secret (all code is valid python code (after importing hashlib.* and base64.*)):

roSecret='R'+(b32encode(sha256(b32decode(secret)).digest())[:32]) The roSecret is hashed again. That hash is transmitted in LAN announces as well as to the tracker at t.usyncapp.com:

shareHash=sha256(b32decode(roSecret[1:])).digest() That's about all the magic that's in the share secrets.

xioustic commented 8 years ago

Example:

xioustic commented 8 years ago

The linked post doesn't seem to work given our test cases; we expect B3KTFE2GJ7JOUJNW5C45RHKWY7YMZENBJ at the end.

Python 2.7.10 (default, May 23 2015, 09:40:32) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from hashlib import sha256
>>> from base64 import b32encode, b32decode
>>> secret = "AOVD7B5MHX6RC4FYAIHNSHAUUIJPKWZOF"
>>> roSecret='R'+(b32encode(sha256(b32decode(secret)).digest())[:32])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\base64.py", line 198, in b32decode
    raise TypeError('Incorrect padding')
TypeError: Incorrect padding
>>> secret = secret[1:]
>>> roSecret='R'+(b32encode(sha256(b32decode(secret)).digest())[:32])
>>> roSecret
'R27ZRIK6FQ3MCCW5NWOGYXHNY3SYGJW2C'
xioustic commented 8 years ago

I suspect this all involves some combination of b32encode, b32decode, sha1 or sha256, RSA/ECDSA private/public key related stuff. R/W keys correspond to private keys, R/O keys correspond to public keys, R/O encrypted correspond to a public key and a symmetric encryption key, and R/O storage correspond to a public key (less the symmetric encryption key).

xioustic commented 8 years ago

Placed a small bounty on bountysource; I suspect anyone moderately interested in public/private/symmetric cryptography with some spare time can figure this out with some experimentation. Worst case someone might need to take a look internally at what btsync does with the --generate-secret and --get-ro-secret flags.

xioustic commented 8 years ago

The following is all that is needed to start solving this bounty (make the two failing tests pass by figuring out the relation between rwenc/rwreg and roenc/roreg keys):

import unittest
from hashlib import sha1, sha256
from base64 import b32encode, b64encode
from os import urandom

def baseKey2RWreg(baseKey):
    return 'A'+baseKey

def baseKey2RWenc(baseKey):
    return 'D'+baseKey

def ROenc2ROsto(ROenc):
    return 'F'+ROenc[1:33]

def RWreg2ROreg(RWreg):
    assert False, "Needs to be implemented."

def RWenc2ROenc(ROenc):
    assert False, "Needs to be implemented."

class TestKeyMethods(unittest.TestCase):

    def test_baseKey2RWreg(self):
        self.assertEqual(baseKey2RWreg("OVD7B5MHX6RC4FYAIHNSHAUUIJPKWZOF"),
            "AOVD7B5MHX6RC4FYAIHNSHAUUIJPKWZOF")

    def test_baseKey2RWenc(self):
        self.assertEqual(baseKey2RWenc("OVD7B5MHX6RC4FYAIHNSHAUUIJPKWZOF"),
            "DOVD7B5MHX6RC4FYAIHNSHAUUIJPKWZOF")

    def test_ROenc2ROsto(self):
        self.assertEqual(ROenc2ROsto("EAOJPGYQTTEAMZM2XQH2XQB7I5MYKE4MSSFYWJC55PLS6CTUGAIBUZ7K2OY"),
            "FAOJPGYQTTEAMZM2XQH2XQB7I5MYKE4MS")

    def test_RWreg2ROreg(self):
        self.assertEqual(RWreg2ROreg("AOVD7B5MHX6RC4FYAIHNSHAUUIJPKWZOF"),
            "B3KTFE2GJ7JOUJNW5C45RHKWY7YMZENBJ")

    def test_RWenc2ROenc(self):
        self.assertEqual(RWenc2ROenc("DOVD7B5MHX6RC4FYAIHNSHAUUIJPKWZOF"),
            "EAOJPGYQTTEAMZM2XQH2XQB7I5MYKE4MSSFYWJC55PLS6CTUGAIBUZ7K2OY")

if __name__ == '__main__':
    unittest.main()