Open xioustic opened 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.
Example:
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'
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).
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.
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()
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.