1 | |
---|
2 | """ |
---|
3 | This is a reference implementation of the lease renewal secret derivation |
---|
4 | protocol in use by Tahoe-LAFS clients as of 1.16.0. |
---|
5 | """ |
---|
6 | |
---|
7 | from allmydata.util.base32 import ( |
---|
8 | a2b as b32decode, |
---|
9 | b2a as b32encode, |
---|
10 | ) |
---|
11 | from allmydata.util.hashutil import ( |
---|
12 | tagged_hash, |
---|
13 | tagged_pair_hash, |
---|
14 | ) |
---|
15 | |
---|
16 | |
---|
17 | def derive_renewal_secret(lease_secret: bytes, storage_index: bytes, tubid: bytes) -> bytes: |
---|
18 | assert len(lease_secret) == 32 |
---|
19 | assert len(storage_index) == 16 |
---|
20 | assert len(tubid) == 20 |
---|
21 | |
---|
22 | bucket_renewal_tag = b"allmydata_bucket_renewal_secret_v1" |
---|
23 | file_renewal_tag = b"allmydata_file_renewal_secret_v1" |
---|
24 | client_renewal_tag = b"allmydata_client_renewal_secret_v1" |
---|
25 | |
---|
26 | client_renewal_secret = tagged_hash(lease_secret, client_renewal_tag) |
---|
27 | file_renewal_secret = tagged_pair_hash( |
---|
28 | file_renewal_tag, |
---|
29 | client_renewal_secret, |
---|
30 | storage_index, |
---|
31 | ) |
---|
32 | peer_id = tubid |
---|
33 | |
---|
34 | return tagged_pair_hash(bucket_renewal_tag, file_renewal_secret, peer_id) |
---|
35 | |
---|
36 | def demo(): |
---|
37 | secret = b32encode(derive_renewal_secret( |
---|
38 | b"lease secretxxxxxxxxxxxxxxxxxxxx", |
---|
39 | b"storage indexxxx", |
---|
40 | b"tub idxxxxxxxxxxxxxx", |
---|
41 | )).decode("ascii") |
---|
42 | print("An example renewal secret: {}".format(secret)) |
---|
43 | |
---|
44 | def test(): |
---|
45 | # These test vectors created by intrumenting Tahoe-LAFS |
---|
46 | # bb57fcfb50d4e01bbc4de2e23dbbf7a60c004031 to emit `self.renew_secret` in |
---|
47 | # allmydata.immutable.upload.ServerTracker.query and then uploading a |
---|
48 | # couple files to a couple different storage servers. |
---|
49 | test_vector = [ |
---|
50 | dict(lease_secret=b"boity2cdh7jvl3ltaeebuiobbspjmbuopnwbde2yeh4k6x7jioga", |
---|
51 | storage_index=b"vrttmwlicrzbt7gh5qsooogr7u", |
---|
52 | tubid=b"v67jiisoty6ooyxlql5fuucitqiok2ic", |
---|
53 | expected=b"osd6wmc5vz4g3ukg64sitmzlfiaaordutrez7oxdp5kkze7zp5zq", |
---|
54 | ), |
---|
55 | dict(lease_secret=b"boity2cdh7jvl3ltaeebuiobbspjmbuopnwbde2yeh4k6x7jioga", |
---|
56 | storage_index=b"75gmmfts772ww4beiewc234o5e", |
---|
57 | tubid=b"v67jiisoty6ooyxlql5fuucitqiok2ic", |
---|
58 | expected=b"35itmusj7qm2pfimh62snbyxp3imreofhx4djr7i2fweta75szda", |
---|
59 | ), |
---|
60 | dict(lease_secret=b"boity2cdh7jvl3ltaeebuiobbspjmbuopnwbde2yeh4k6x7jioga", |
---|
61 | storage_index=b"75gmmfts772ww4beiewc234o5e", |
---|
62 | tubid=b"lh5fhobkjrmkqjmkxhy3yaonoociggpz", |
---|
63 | expected=b"srrlruge47ws3lm53vgdxprgqb6bz7cdblnuovdgtfkqrygrjm4q", |
---|
64 | ), |
---|
65 | dict(lease_secret=b"vacviff4xfqxsbp64tdr3frg3xnkcsuwt5jpyat2qxcm44bwu75a", |
---|
66 | storage_index=b"75gmmfts772ww4beiewc234o5e", |
---|
67 | tubid=b"lh5fhobkjrmkqjmkxhy3yaonoociggpz", |
---|
68 | expected=b"b4jledjiqjqekbm2erekzqumqzblegxi23i5ojva7g7xmqqnl5pq", |
---|
69 | ), |
---|
70 | ] |
---|
71 | |
---|
72 | for n, item in enumerate(test_vector): |
---|
73 | derived = b32encode(derive_renewal_secret( |
---|
74 | b32decode(item["lease_secret"]), |
---|
75 | b32decode(item["storage_index"]), |
---|
76 | b32decode(item["tubid"]), |
---|
77 | )) |
---|
78 | assert derived == item["expected"] , \ |
---|
79 | "Test vector {} failed: {} (expected) != {} (derived)".format( |
---|
80 | n, |
---|
81 | item["expected"], |
---|
82 | derived, |
---|
83 | ) |
---|
84 | print("{} test vectors validated".format(len(test_vector))) |
---|
85 | |
---|
86 | test() |
---|
87 | demo() |
---|