<commit_before># coding: utf-8
from __future__ import unicode_literals, division, absolute_import, print_function

import sys
import hashlib
from datetime import datetime

if sys.platform == 'darwin':
    from ._osx.util import pbkdf2, pkcs12_kdf, rand_bytes  #pylint: disable=W0611
elif sys.platform == 'win32':
    from ._win.util import pbkdf2, pkcs12_kdf, rand_bytes  #pylint: disable=W0611
else:
    from ._openssl.util import pbkdf2, pkcs12_kdf, rand_bytes  #pylint: disable=W0611


if sys.version_info < (3,):
    byte_cls = str
    int_types = (int, long)  #pylint: disable=E0602

else:
    byte_cls = bytes
    int_types = int


def determine_pbkdf2_iterations(hash_algorithm, key_length, target_ms=100, quiet=False):
    """
    Runs pbkdf2() until the derivation process takes a number of milliseconds.
    Use this on a production machine to dynamically adjust the number of
    iterations as high as you can.

    :param hash_algorithm:
        The string name of the hash algorithm to use: "md5", "sha1", "sha224", "sha256", "sha384", "sha512"

    :param key_length:
        The length of the desired key in bytes

    :param target_ms:
        The number of milliseconds the derivation should take

    :param quiet:
        If no output should be printed as attempts are made

    :return:
        An integer number of iterations of PBKDF2 using the specified hash
        that will take at least target_ms
    """

    if hash_algorithm not in {'sha1', 'sha224', 'sha256', 'sha384', 'sha512'}:
        raise ValueError('hash_algorithm must be one of "sha1", "sha224", "sha256", "sha384", "sha512", not %s' % repr(hash_algorithm))

    if not isinstance(key_length, int_types):
        raise ValueError('key_length must be an integer, not %s' % key_length.__class__.__name__)

    if key_length < 1:
        raise ValueError('key_length must be greater than 0 - is %s' % repr(key_length))

    if not isinstance(target_ms, int_types):
        raise ValueError('target_ms must be an integer, not %s' % target_ms.__class__.__name__)

    if target_ms < 1:
        raise ValueError('target_ms must be greater than 0 - is %s' % repr(target_ms))

    if pbkdf2.pure_python:
        raise OSError('Only a very slow, pure-python version of PBKDF2 is available, making this function useless')

    # This number is doubled even for the first attempt
    iterations = 5000
    password = '<PASSWORD>'.encode('utf-8')
    salt = rand_bytes(key_length)

    observed_ms = 0
    while observed_ms < target_ms:
        iterations *= 2
        start = datetime.now()
        pbkdf2(hash_algorithm, password, salt, iterations, key_length)
        length = datetime.now() - start
        observed_ms = int(length.total_seconds() * 1000)
        if not quiet:
            print('%s iterations in %sms' % (iterations, observed_ms))

    return iterations


def pbkdf1(hash_algorithm, password, salt, iterations, key_length):
    """
    An implementation of PBKDF1 - should only be used for interop with legacy
    systems, not new architectures

    :param hash_algorithm:
        The string name of the hash algorithm to use: "md2", "md5", "sha1"

    :param password:
        A byte string of the password to use an input to the KDF

    :param salt:
        A cryptographic random byte string<commit_msg>Revised the PBKDF2 timing algorithm to always use two measurements<commit_after># coding: utf-8
from __future__ import unicode_literals, division, absolute_import, print_function

import sys
import hashlib
from datetime import datetime

if sys.platform == 'darwin':
    from ._osx.util import pbkdf2, pkcs12_kdf, rand_bytes  #pylint: disable=W0611
elif sys.platform == 'win32':
    from ._win.util import pbkdf2, pkcs12_kdf, rand_bytes  #pylint: disable=W0611
else:
    from ._openssl.util import pbkdf2, pkcs12_kdf, rand_bytes  #pylint: disable=W0611


if sys.version_info < (3,):
    byte_cls = str
    int_types = (int, long)  #pylint: disable=E0602

else:
    byte_cls = bytes
    int_types = int


def determine_pbkdf2_iterations(hash_algorithm, key_length, target_ms=100, quiet=False):
    """
    Runs pbkdf2() until the derivation process takes a number of milliseconds.
    Use this on a production machine to dynamically adjust the number of
    iterations as high as you can.

    :param hash_algorithm:
        The string name of the hash algorithm to use: "md5", "sha1", "sha224", "sha256", "sha384", "sha512"

    :param key_length:
        The length of the desired key in bytes

    :param target_ms:
        The number of milliseconds the derivation should take

    :param quiet:
        If no output should be printed as attempts are made

    :return:
        An integer number of iterations of PBKDF2 using the specified hash
        that will take at least target_ms
    """

    if hash_algorithm not in {'sha1', 'sha224', 'sha256', 'sha384', 'sha512'}:
        raise ValueError('hash_algorithm must be one of "sha1", "sha224", "sha256", "sha384", "sha512", not %s' % repr(hash_algorithm))

    if not isinstance(key_length, int_types):
        raise ValueError('key_length must be an integer, not %s' % key_length.__class__.__name__)

    if key_length < 1:
        raise ValueError('key_length must be greater than 0 - is %s' % repr(key_length))

    if not isinstance(target_ms, int_types):
        raise ValueError('target_ms must be an integer, not %s' % target_ms.__class__.__name__)

    if target_ms < 1:
        raise ValueError('target_ms must be greater than 0 - is %s' % repr(target_ms))

    if pbkdf2.pure_python:
        raise OSError('Only a very slow, pure-python version of PBKDF2 is available, making this function useless')

    iterations = 10000
    password = '<PASSWORD>'.encode('utf-8')
    salt = rand_bytes(key_length)

    def _measure():
        start = datetime.now()
        pbkdf2(hash_algorithm, password, salt, iterations, key_length)
        length = datetime.now() - start
        observed_ms = int(length.total_seconds() * 1000)
        if not quiet:
            print('%s iterations in %sms' % (iterations, observed_ms))
        return 1.0 / target_ms * observed_ms

    # Measure the initial guess, then estimate how many iterations it would
    # take to reach 1/2 of the target ms and try it to get a good final number
    fraction = _measure()
    iterations = int(iterations / fraction / 2.0)

    fraction = _measure()
    return int(round(iterations / fraction, -3))


def pbkdf1(hash_algorithm, password, salt, iterations, key_length):
    """
    An implementation of PBKDF1 - should only be used for interop with legacy
    systems, not new architectures

    :param hash_algorithm:
        The string name of the hash algorithm to use: "md2", "md5", "sha1"

    :param password:
        A byte string of the password to use an input to the KDF

    :param salt:
        A cryptographic random byte string
{'fraction_non_alphanumeric': 0.08586372221415081, 'fraction_numerical': 0.02949295365392997, 'mean_word_length': 3.267823930564166, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '297681', 'n_tokens_mistral': 2234, 'n_tokens_neox': 2059, 'n_words': 758}