Source code for pyaescbc.generate_pin_iterations

# Copyright 2025 Artezaru
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import hashlib
from typing import Optional

from .delete_bytearray import delete_bytearray

[docs] def generate_pin_iterations(pin: bytearray, Nmin: Optional[int] = None, Nmax: Optional[int] = None, delete_keys: bool = True) -> int: """ Generates a number of iterations for PBKDF2 based on the PIN. Use the following code to estimate the order of magnitude of the number of iterations. By default, the number of iterations is between 2,000,000 and 5,000,000 (valid for computers with 4GB of RAM in 2021). It is recommended to have a derived key generation time between 1 and 2 seconds to avoid brute force attacks withouth affecting the user experience. .. note:: The PIN is deleted from memory at the end of the function if delete_keys is True. Otherwise, it needs to be deleted after dealing with Exception. .. code-block:: python import pyaescbc import time import os password = pyaescbc.random_bytearray(32) salt = pyaescbc.random_salt() time_start = time.time() iteration = 2_000_000 # Change this value to the estimated number of iterations. pyaescbc.derive_key(password, salt, iteration) time_end = time.time() print(f'{iteration=}, {time_end-time_start=}') Parameters ---------- pin : bytearray The PIN to generate the number of iterations. Nmin : Optional[int], optional The minimum number of iterations. The default is None -> 2,000,000. Nmax : Optional[int] The maximum number of iterations. The default is None -> 5,000,000. delete_keys : bool Delete the PIN from memory at the end of the function. Default is True. If False, it needs to be deleted after dealing with Exception. Returns ------- iterations : int The number of iterations based on the PIN. Raises ------ TypeError If `Nmin` or `Nmax` are not int instances or if `pin` is not a bytearray instance. ValueError If `Nmin` or `Nmax` are not positive integers or if `Nmin` is greater than `Nmax`. """ # Check the types of the parameters if not isinstance(pin, bytearray): raise TypeError('Parameter pin is not bytearray instance.') if (Nmin is not None) and (not isinstance(Nmin, int)): raise TypeError('Parameter Nmin is not int instance.') if (Nmax is not None) and (not isinstance(Nmax, int)): raise TypeError('Parameter Nmax is not int instance.') if not isinstance(delete_keys, bool): raise TypeError('Parameter delete_keys is not a boolean.') if Nmin is None: Nmin = 2_000_000 if Nmax is None: Nmax = 5_000_000 # Check the values of the parameters if Nmin <= 0: raise ValueError('Parameter Nmin must be a positive integer.') if Nmax <= 0: raise ValueError('Parameter Nmax must be a positive integer.') if Nmin >= Nmax: raise ValueError('Parameter Nmin must be less than Nmax.') # Hash the PIN to generate a random number pin_hash = hashlib.sha256(pin).digest() hash_value = int.from_bytes(pin_hash, byteorder='big') # Generate the number of iterations iterations = hash_value % (Nmax - Nmin + 1) + Nmin # Delete the PIN from memory if required if delete_keys: delete_bytearray(pin) return iterations