Пример #1
0
def _measure_scaled_params(baseline: Measurement) -> typ.List[Measurement]:
    measurements = [baseline]
    while len(measurements) < 4:
        baseline = measurements[0]

        if len(measurements) == 1:
            m = baseline.m * PARAM_SCALING
            t = baseline.t
        elif len(measurements) == 2:
            m = baseline.m
            t = baseline.t * PARAM_SCALING
        elif len(measurements) == 3:
            m = baseline.m * PARAM_SCALING
            t = baseline.t * PARAM_SCALING
        else:
            # To increase accuracy, repeat measurement with previous
            # parameters and use the lower measurement.
            measurement = measurements[len(measurements) % 4]

            m = measurement.m
            t = measurement.t

        kdf_params = kdf.init_kdf_params(m, t)
        measurement = measure(kdf_params)
        measurements.append(measurement)

    return measurements
Пример #2
0
def test_digest_len():
    kdf_params = kdf.init_kdf_params(p=1, m=10, t=1)

    secret_data = b"\x01\x23\x45\x67\x89\xab\xcd\xef"
    for hash_len in range(4, 50):
        res = kdf.digest(secret_data, kdf_params, hash_len)
        assert len(res) == hash_len
Пример #3
0
def test_argon2_fuzz():
    # Compare two implementations. Ostensibly they both use
    # the same implementation underneath, so there should
    # be absolutely no difference
    try:
        importlib.import_module('pyargon2')
    except ImportError:
        return

    r = random.Random(0)

    for _ in range(10):
        p = r.randrange(1,   4)
        m = r.randrange(1, 100)
        t = r.randrange(1,   4)

        kdf_params = kdf.init_kdf_params(p=p, m=m, t=t)

        test_data = str(r.random()) * 2

        hash_data_1 = kdf._hash_pyargon2(
            test_data,
            t=kdf_params.t,
            p=kdf_params.p,
            m=kdf_params.m,
        )

        hash_data_2 = kdf._hash_argon2_cffi(
            test_data.encode("utf-8"),
            t=kdf_params.t,
            p=kdf_params.p,
            m=kdf_params.m,
        )

        assert hash_data_1 == hash_data_2, kdf_params
Пример #4
0
def estimate_param_cost(tgt_kdf_params: kdf.KDFParams,
                        sys_info: typ.Optional[SystemInfo] = None) -> Seconds:
    """Estimate the runtime for parameters in seconds.

    This extrapolates based on a few short measurements and
    is not very precise (but good enough for a progress bar).
    """
    tgt_p, tgt_m, tgt_t, _ = tgt_kdf_params

    if tgt_m < 10 and tgt_t < 10:
        return 1.0

    if sys_info is None:
        _sys_info = load_sys_info()
        if len(_sys_info.measurements) < 4:
            _sys_info = update_measurements(_sys_info)
    else:
        _sys_info = sys_info

    assert len(_sys_info.measurements) >= 4

    measurements = _sys_info.measurements

    min_measurements: typ.Dict[kdf.KDFParams, float] = {}
    for measurement in measurements:
        key = kdf.init_kdf_params(measurement.m, measurement.t)
        if key in min_measurements:
            val = min_measurements[key]
            min_measurements[key] = min(measurement.duration, val)
        else:
            min_measurements[key] = measurement.duration

    measurements = [
        Measurement(p, m, t, h, d)
        for (p, m, t, h), d in min_measurements.items()
    ]
    assert len(measurements) == 4

    # Bilinear Interpolation
    # https://stackoverflow.com/a/8662355/62997
    # https://en.wikipedia.org/wiki/Bilinear_interpolation#Algorithm

    m0, _, _, m1 = [m for p, m, t, h, d in measurements]
    t0, _, _, t1 = [t for p, m, t, h, d in measurements]
    d00, d01, d10, d11 = [d for p, m, t, h, d in measurements]

    s = [
        d00 * (m1 - tgt_m) * (t1 - tgt_t),
        d10 * (tgt_m - m0) * (t1 - tgt_t),
        d01 * (m1 - tgt_m) * (tgt_t - t0),
        d11 * (tgt_m - m0) * (tgt_t - t0),
    ]

    return max(0.0, sum(s) / ((m1 - m0) * (t1 - t0) + 0.0))
Пример #5
0
def test_digest_progress():
    increments = []

    def _progress_cb(incr) -> None:
        increments.append(incr)

    kdf_params  = kdf.init_kdf_params(p=1, m=10, t=100)
    secret_data = b"\x01\x23\x45\x67\x89\xab\xcd\xef"
    kdf.digest(secret_data, kdf_params, 8, _progress_cb)

    assert len(increments) > 0
    assert increments[-1] == 100
Пример #6
0
def get_default_params() -> kdf.KDFParams:
    sys_info = load_sys_info()
    m = sys_info.initial_m

    t = 1
    while True:
        test_kdf_params = kdf.init_kdf_params(m=m, t=t)

        est_cost = estimate_param_cost(test_kdf_params)
        if est_cost > DEFAULT_KDF_TIME_SEC:
            return test_kdf_params
        else:
            t = math.ceil(t * 1.5)
Пример #7
0
def test_digest_iters():
    all_kdf_params = set()
    for p in range(1, 4):
        for t in range(1, 8):
            kdf_params = kdf.init_kdf_params(p=p, m=10, t=t)
            all_kdf_params.add(kdf_params)

    kdf_input = b"\x01\x23\x45\x67" * 4
    digests   = set()
    for kdf_params in all_kdf_params:
        res = kdf.digest(kdf_input, kdf_params, hash_len=32)
        digests.add(res)

    # digests should be unique for unique kdf_params
    assert len(digests) == len(all_kdf_params)
Пример #8
0
def test_digest_inputs():
    kdf_params = kdf.init_kdf_params(p=1, m=random.randint(1, 4) * 8, t=random.randint(1, 20))

    kdf_inputs = [
        b"\x00\x00\x00\x00\x00\x00\x00\x00",
        b"\x11\x11\x11\x11\x11\x11\x11\x11",
        b"\x22\x22\x22\x22\x22\x22\x22\x22",
        b"\x33\x33\x33\x33\x33\x33\x33\x33",
    ]

    digests = set()
    for kdf_input in kdf_inputs:
        res = kdf.digest(kdf_input, kdf_params, hash_len=32)
        digests.add(res)

    # digests should be unique for unique inputs
    assert len(digests) == len(kdf_inputs)
Пример #9
0
def test_kdf_params_fuzz():
    r = random.Random(0)

    for _ in range(100):
        p = r.randrange(1, int(kdf.P_BASE ** (2 ** 4 - 1))) * kdf.MIN_P
        m = r.randrange(1, int(kdf.M_BASE ** (2 ** 6 - 1))) * kdf.MIN_M
        t = r.randrange(1, int(kdf.T_BASE ** (2 ** 6 - 1))) * kdf.MIN_T

        kdf_params = kdf.init_kdf_params(p=p, m=m, t=t)
        decoded    = kdf.KDFParams.decode(kdf_params.encode())
        assert decoded == kdf_params

        dp = abs(kdf_params.p - p) / kdf_params.p
        dm = abs(kdf_params.m - m) / kdf_params.m
        dt = abs(kdf_params.t - t) / kdf_params.t

        assert dp <= 0.5
        assert dm <= 0.5
        assert dt <= 0.5
Пример #10
0
def _update_measurements(sys_info: SystemInfo) -> SystemInfo:
    # NOTE: choice of the baseline memory probably has the
    #   largest influence on the accuracy of cost estimation
    #   for parameters. Presumably you'd want to do something
    #   more clever than a cutoff. We might for example look
    #   to see if curve of the durations is past some inflection
    #   point that is presumably related to a bottleneck.

    m = 1

    while True:
        kdf_params = kdf.init_kdf_params(m=m, t=2)
        p = kdf_params.p
        m = kdf_params.m
        sample = measure(kdf_params)
        if sample.duration > KDF_MEASUREMENT_SIGNIFIGANCE_THRESHOLD:
            break
        else:
            m = math.ceil(m * 1.5)

    _dump_sys_info(sys_info)
    return sys_info
Пример #11
0
def test_kdf_params(p, m, t):
    kdf_params = kdf.init_kdf_params(p=p, m=m, t=t)
    assert kdf_params.p == p
    assert kdf_params.m == m
    assert kdf_params.t == t
Пример #12
0
    while remaining_iters > 0:
        step_iters = max(1, round(remaining_iters / remaining_steps))
        print(f"remaining: {remaining_iters:>3} of {t}  -  next: {step_iters}")
        result = argon2.low_level.hash_secret_raw(
            secret=result, salt=result, time_cost=step_iters, **constant_kwargs
        )
        print("<<", len(result))
        remaining_steps -= 1
        remaining_iters -= step_iters

    assert remaining_steps == 0, remaining_steps
    assert remaining_iters == 0, remaining_iters
    return result[:digest_len]


kdf_params  = kdf.init_kdf_params(m=1, t=1)
digest_data = digest(b"test1234", p=kdf_params.p, m=kdf_params.m, t=kdf_params.t)
if VERIFY:
    assert digest_data == kdf.digest(b"test1234", kdf_params, hash_len=1024)
else:
    print(binascii.hexlify(digest_data))
    # remaining:   1 of 1  -  next: 1
    # b'f874b69ca85a76f373a203e7d55a2974c3dc50d94886383b8502aaeebaaf362d'


# This can be verified against https://antelle.net/argon2-browser/
#
# Params: pass=test1234, salt=test1234, time=1, mem=1024, hashLen=32, parallelism=1, type=0
# Encoded: $argon2d$v=19$m=1024,t=1,p=1$dGVzdDEyMzQ$O2GpxMquN/amTCVwe5GHPJr89BvBVnM0ylSHfzez4l8

kdf_params  = kdf.init_kdf_params(m=1, t=2)