.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/wallets/stretching/plot_01_pbkdf2_key_stretching.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code or to run this example in your browser via JupyterLite. .. rst-class:: sphx-glr-example-title .. _sphx_glr_api_gallery_wallets_stretching_plot_01_pbkdf2_key_stretching.py: PBKDF2 key stretching (2000) ============================ A key derived from a password is only as hard to find as the password. Burt Kaliski's PBKDF2, in RFC 2898, cannot add entropy, but it makes every guess expensive: it iterates HMAC c times, and mixes in a salt so that one precomputed table cannot serve every user, .. math:: U_1 = \mathrm{HMAC}(P, S \,\|\, 1), \quad U_j = \mathrm{HMAC}(P, U_{j-1}), \quad T = U_1 \oplus \cdots \oplus U_c . The honest user pays c HMAC calls once; an attacker trying N passwords pays N times c. BIP39 stretches seed phrases this way with 2048 iterations. Here a three-digit PIN is cracked at increasing iteration counts. .. GENERATED FROM PYTHON SOURCE LINES 22-28 .. code-block:: Python import time import matplotlib.pyplot as plt import blockchainkit as bk .. GENERATED FROM PYTHON SOURCE LINES 29-31 The same password, different salts ---------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 31-37 .. code-block:: Python alice = bk.wallets.pbkdf2(b"042", b"alice's salt", 10, 32) bob = bk.wallets.pbkdf2(b"042", b"bob's salt", 10, 32) print("alice", alice.hex()[:16], "bob", bob.hex()[:16]) assert alice != bob .. rst-class:: sphx-glr-script-out .. code-block:: none alice bb8dcf6d9b44a816 bob b3912ad5ac011953 .. GENERATED FROM PYTHON SOURCE LINES 38-40 The cost of exhaustive search ----------------------------- .. GENERATED FROM PYTHON SOURCE LINES 40-66 .. code-block:: Python iterations = [1, 2, 4, 8, 16, 32] calls, seconds = [], [] for c in iterations: key = bk.wallets.pbkdf2(b"731", b"salt", c, 32) start = time.perf_counter() result = bk.wallets.crack_pin(key, b"salt", c, 3) seconds.append(time.perf_counter() - start) calls.append(result.hash_calls) print( f"c = {c:2}: found {result.secret} after {result.guesses} guesses," f" {result.hash_calls:,} HMAC calls" ) assert result.secret == "731" and result.hash_calls == 732 * c fig, ax = plt.subplots(figsize=(6, 4)) ax.loglog(iterations, calls, "o-", color="#2563eb", label="HMAC calls") ax.set(xlabel="iterations c", ylabel="attacker's HMAC calls") twin = ax.twinx() twin.loglog(iterations, seconds, "s--", color="#dc2626", label="seconds") twin.set_ylabel("seconds") ax.set_title("Each iteration multiplies every guess") fig.legend(loc="upper left", bbox_to_anchor=(0.15, 0.85)) fig.tight_layout() plt.show() .. image-sg:: /api/gallery/wallets/stretching/images/sphx_glr_plot_01_pbkdf2_key_stretching_001.png :alt: Each iteration multiplies every guess :srcset: /api/gallery/wallets/stretching/images/sphx_glr_plot_01_pbkdf2_key_stretching_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none c = 1: found 731 after 732 guesses, 732 HMAC calls c = 2: found 731 after 732 guesses, 1,464 HMAC calls c = 4: found 731 after 732 guesses, 2,928 HMAC calls c = 8: found 731 after 732 guesses, 5,856 HMAC calls c = 16: found 731 after 732 guesses, 11,712 HMAC calls c = 32: found 731 after 732 guesses, 23,424 HMAC calls .. GENERATED FROM PYTHON SOURCE LINES 67-73 Exercise -------- How many iterations make cracking a six-digit PIN cost as many HMAC calls as cracking an unstretched nine-digit one? What does that say about stretching against a long, random password? A worked solution is in :doc:`/exercises/wallets`. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.209 seconds) .. _sphx_glr_download_api_gallery_wallets_stretching_plot_01_pbkdf2_key_stretching.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: lite-badge .. image:: images/jupyterlite_badge_logo.svg :target: ../../../../lite/lab/index.html?path=api/gallery/wallets/stretching/plot_01_pbkdf2_key_stretching.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_01_pbkdf2_key_stretching.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_01_pbkdf2_key_stretching.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_01_pbkdf2_key_stretching.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_