1 from pycryptopp.hash.sha256 import SHA256
3 from allmydata.util.netstring import netstring
5 # Be very very cautious when modifying this file. Almost any change will
6 # cause a compatibility break, invalidating all outstanding URIs and making
7 # any previously uploaded files become inaccessible. BE CONSERVATIVE AND TEST
10 # Various crypto values are this size: hash outputs (from SHA-256d),
11 # randomly-generated secrets such as the lease secret, and symmetric encryption
12 # keys. In the near future we will add DSA private keys, and salts of various
16 class _SHA256d_Hasher:
17 # use SHA-256d, as defined by Ferguson and Schneier: hash the output
18 # again to prevent length-extension attacks
19 def __init__(self, truncate_to=None):
21 self.truncate_to = truncate_to
23 def update(self, data):
24 assert isinstance(data, str) # no unicode
27 if self._digest is None:
30 h2 = SHA256(h1).digest()
32 h2 = h2[:self.truncate_to]
38 def tagged_hasher(tag, truncate_to=None):
39 hasher = _SHA256d_Hasher(truncate_to)
40 hasher.update(netstring(tag))
43 def tagged_hash(tag, val, truncate_to=None):
44 hasher = tagged_hasher(tag, truncate_to)
46 return hasher.digest()
48 def tagged_pair_hash(tag, val1, val2, truncate_to=None):
49 s = _SHA256d_Hasher(truncate_to)
50 s.update(netstring(tag))
51 s.update(netstring(val1))
52 s.update(netstring(val2))
55 ## specific hash tags that we use
58 STORAGE_INDEX_TAG = "allmydata_immutable_key_to_storage_index_v1"
59 BLOCK_TAG = "allmydata_encoded_subshare_v1"
60 UEB_TAG = "allmydata_uri_extension_v1"
61 PLAINTEXT_TAG = "allmydata_plaintext_v1"
62 CIPHERTEXT_TAG = "allmydata_crypttext_v1"
63 CIPHERTEXT_SEGMENT_TAG = "allmydata_crypttext_segment_v1"
64 PLAINTEXT_SEGMENT_TAG = "allmydata_plaintext_segment_v1"
65 CONVERGENT_ENCRYPTION_TAG = "allmydata_immutable_content_to_key_with_added_secret_v1+"
67 CLIENT_RENEWAL_TAG = "allmydata_client_renewal_secret_v1"
68 CLIENT_CANCEL_TAG = "allmydata_client_cancel_secret_v1"
69 FILE_RENEWAL_TAG = "allmydata_file_renewal_secret_v1"
70 FILE_CANCEL_TAG = "allmydata_file_cancel_secret_v1"
71 BUCKET_RENEWAL_TAG = "allmydata_bucket_renewal_secret_v1"
72 BUCKET_CANCEL_TAG = "allmydata_bucket_cancel_secret_v1"
75 MUTABLE_WRITEKEY_TAG = "allmydata_mutable_privkey_to_writekey_v1"
76 MUTABLE_WRITE_ENABLER_MASTER_TAG = "allmydata_mutable_writekey_to_write_enabler_master_v1"
77 MUTABLE_WRITE_ENABLER_TAG = "allmydata_mutable_write_enabler_master_and_nodeid_to_write_enabler_v1"
78 MUTABLE_PUBKEY_TAG = "allmydata_mutable_pubkey_to_fingerprint_v1"
79 MUTABLE_READKEY_TAG = "allmydata_mutable_writekey_to_readkey_v1"
80 MUTABLE_DATAKEY_TAG = "allmydata_mutable_readkey_to_datakey_v1"
81 MUTABLE_STORAGEINDEX_TAG = "allmydata_mutable_readkey_to_storage_index_v1"
84 DIRNODE_CHILD_WRITECAP_TAG = "allmydata_mutable_writekey_and_salt_to_dirnode_child_capkey_v1"
86 def storage_index_hash(key):
87 # storage index is truncated to 128 bits (16 bytes). We're only hashing a
88 # 16-byte value to get it, so there's no point in using a larger value. We
89 # use this same tagged hash to go from encryption key to storage index for
90 # random-keyed immutable files and convergent-encryption immutabie
91 # files. Mutable files use ssk_storage_index_hash().
92 return tagged_hash(STORAGE_INDEX_TAG, key, 16)
95 return tagged_hash(BLOCK_TAG, data)
97 return tagged_hasher(BLOCK_TAG)
99 def uri_extension_hash(data):
100 return tagged_hash(UEB_TAG, data)
101 def uri_extension_hasher():
102 return tagged_hasher(UEB_TAG)
104 def plaintext_hash(data):
105 return tagged_hash(PLAINTEXT_TAG, data)
106 def plaintext_hasher():
107 return tagged_hasher(PLAINTEXT_TAG)
109 def crypttext_hash(data):
110 return tagged_hash(CIPHERTEXT_TAG, data)
111 def crypttext_hasher():
112 return tagged_hasher(CIPHERTEXT_TAG)
114 def crypttext_segment_hash(data):
115 return tagged_hash(CIPHERTEXT_SEGMENT_TAG, data)
116 def crypttext_segment_hasher():
117 return tagged_hasher(CIPHERTEXT_SEGMENT_TAG)
119 def plaintext_segment_hash(data):
120 return tagged_hash(PLAINTEXT_SEGMENT_TAG, data)
121 def plaintext_segment_hasher():
122 return tagged_hasher(PLAINTEXT_SEGMENT_TAG)
126 def convergence_hash(k, n, segsize, data, convergence):
127 h = convergence_hasher(k, n, segsize, convergence)
130 def convergence_hasher(k, n, segsize, convergence):
131 assert isinstance(convergence, str)
132 param_tag = netstring("%d,%d,%d" % (k, n, segsize))
133 tag = CONVERGENT_ENCRYPTION_TAG + netstring(convergence) + param_tag
134 return tagged_hasher(tag, KEYLEN)
137 return os.urandom(KEYLEN)
139 def my_renewal_secret_hash(my_secret):
140 return tagged_hash(my_secret, CLIENT_RENEWAL_TAG)
141 def my_cancel_secret_hash(my_secret):
142 return tagged_hash(my_secret, CLIENT_CANCEL_TAG)
144 def file_renewal_secret_hash(client_renewal_secret, storage_index):
145 return tagged_pair_hash(FILE_RENEWAL_TAG,
146 client_renewal_secret, storage_index)
148 def file_cancel_secret_hash(client_cancel_secret, storage_index):
149 return tagged_pair_hash(FILE_CANCEL_TAG,
150 client_cancel_secret, storage_index)
152 def bucket_renewal_secret_hash(file_renewal_secret, peerid):
153 assert len(peerid) == 20, "%s: %r" % (len(peerid), peerid) # binary!
154 return tagged_pair_hash(BUCKET_RENEWAL_TAG, file_renewal_secret, peerid)
156 def bucket_cancel_secret_hash(file_cancel_secret, peerid):
157 assert len(peerid) == 20, "%s: %r" % (len(peerid), peerid) # binary!
158 return tagged_pair_hash(BUCKET_CANCEL_TAG, file_cancel_secret, peerid)
162 return "".join([chr(ord(c) ^ ord(b)) for c in a])
165 ikey = _xor(tag, "\x36")
166 okey = _xor(tag, "\x5c")
167 h1 = SHA256(ikey + data).digest()
168 h2 = SHA256(okey + h1).digest()
171 def mutable_rwcap_key_hash(iv, writekey):
172 return tagged_pair_hash(DIRNODE_CHILD_WRITECAP_TAG, iv, writekey, KEYLEN)
174 def ssk_writekey_hash(privkey):
175 return tagged_hash(MUTABLE_WRITEKEY_TAG, privkey, KEYLEN)
176 def ssk_write_enabler_master_hash(writekey):
177 return tagged_hash(MUTABLE_WRITE_ENABLER_MASTER_TAG, writekey)
178 def ssk_write_enabler_hash(writekey, peerid):
179 assert len(peerid) == 20, "%s: %r" % (len(peerid), peerid) # binary!
180 wem = ssk_write_enabler_master_hash(writekey)
181 return tagged_pair_hash(MUTABLE_WRITE_ENABLER_TAG, wem, peerid)
183 def ssk_pubkey_fingerprint_hash(pubkey):
184 return tagged_hash(MUTABLE_PUBKEY_TAG, pubkey)
186 def ssk_readkey_hash(writekey):
187 return tagged_hash(MUTABLE_READKEY_TAG, writekey, KEYLEN)
188 def ssk_readkey_data_hash(IV, readkey):
189 return tagged_pair_hash(MUTABLE_DATAKEY_TAG, IV, readkey, KEYLEN)
190 def ssk_storage_index_hash(readkey):
191 return tagged_hash(MUTABLE_STORAGEINDEX_TAG, readkey, KEYLEN)