|
9 | 9 |
|
10 | 10 | from iota.crypto import HASH_LENGTH |
11 | 11 | from iota.crypto.kerl import Kerl |
12 | | -from iota.crypto.signing import KeyGenerator |
| 12 | +from iota.crypto.signing import KeyGenerator, normalize |
13 | 13 | from iota.crypto.types import PrivateKey |
14 | 14 | from iota.exceptions import with_context |
15 | 15 | from iota.transaction.base import Bundle, Transaction |
16 | | -from iota.transaction.types import BundleHash, Fragment, TransactionHash, Nonce |
| 16 | +from iota.transaction.types import BundleHash, Fragment, Nonce, TransactionHash |
17 | 17 | from iota.transaction.utils import get_current_timestamp |
18 | | -from iota.types import Address, Hash, Tag, TryteString |
| 18 | +from iota.trits import add_trits |
| 19 | +from iota.types import Address, Tag, TryteString |
19 | 20 |
|
20 | 21 | __all__ = [ |
21 | 22 | 'ProposedBundle', |
@@ -83,6 +84,17 @@ def as_tryte_string(self): |
83 | 84 |
|
84 | 85 | return super(ProposedTransaction, self).as_tryte_string() |
85 | 86 |
|
| 87 | + def increment_legacy_tag(self): |
| 88 | + """ |
| 89 | + Increments the transaction's legacy tag, used to fix insecure |
| 90 | + bundle hashes when finalizing a bundle. |
| 91 | +
|
| 92 | + References: |
| 93 | + - https://github.com/iotaledger/iota.lib.py/issues/84 |
| 94 | + """ |
| 95 | + self._legacy_tag =\ |
| 96 | + Tag.from_trits(add_trits(self.legacy_tag.as_trits(), [1])) |
| 97 | + |
86 | 98 |
|
87 | 99 | Transfer = ProposedTransaction |
88 | 100 | """ |
@@ -322,20 +334,31 @@ def finalize(self): |
322 | 334 | ) |
323 | 335 |
|
324 | 336 | # Generate bundle hash. |
325 | | - sponge = Kerl() |
326 | | - last_index = len(self) - 1 |
| 337 | + while True: |
| 338 | + sponge = Kerl() |
| 339 | + last_index = len(self) - 1 |
| 340 | + |
| 341 | + for (i, txn) in enumerate(self): # type: Tuple[int, ProposedTransaction] |
| 342 | + txn.current_index = i |
| 343 | + txn.last_index = last_index |
327 | 344 |
|
328 | | - for (i, txn) in enumerate(self): # type: Tuple[int, ProposedTransaction] |
329 | | - txn.current_index = i |
330 | | - txn.last_index = last_index |
| 345 | + sponge.absorb(txn.get_signature_validation_trytes().as_trits()) |
331 | 346 |
|
332 | | - sponge.absorb(txn.get_signature_validation_trytes().as_trits()) |
| 347 | + bundle_hash_trits = [0] * HASH_LENGTH # type: MutableSequence[int] |
| 348 | + sponge.squeeze(bundle_hash_trits) |
333 | 349 |
|
334 | | - bundle_hash_trits = [0] * HASH_LENGTH # type: MutableSequence[int] |
335 | | - sponge.squeeze(bundle_hash_trits) |
| 350 | + bundle_hash = BundleHash.from_trits(bundle_hash_trits) |
| 351 | + |
| 352 | + # Check that we generated a secure bundle hash. |
| 353 | + # https://github.com/iotaledger/iota.lib.py/issues/84 |
| 354 | + if any(13 in fragment for fragment in normalize(bundle_hash)): |
| 355 | + # Increment the legacy tag and try again. |
| 356 | + tail_transaction = self.tail_transaction # type: ProposedTransaction |
| 357 | + tail_transaction.increment_legacy_tag() |
| 358 | + else: |
| 359 | + break |
336 | 360 |
|
337 | 361 | # Copy bundle hash to individual transactions. |
338 | | - bundle_hash = BundleHash.from_trits(bundle_hash_trits) |
339 | 362 | for txn in self: |
340 | 363 | txn.bundle_hash = bundle_hash |
341 | 364 |
|
|
0 commit comments